在我的基于Restlet的API中,使用Restlet Jackson扩展,我试图将Java对象序列化为XML和JSON,并且无法获得我期望的格式(现有API已经发布)与嵌套列表或多维数组。
这是我的POJO生成正确的JSON:
@JacksonXmlRootElement( localName = "table")
@JsonInclude( JsonInclude.Include.NON_NULL)
public class TableResponse {
protected List data;
protected String[] columns;
public TableResponse( String[] columns, List<List<String>> data ) {
this.columns = columns;
this.data = data;
}
@JacksonXmlElementWrapper(localName = "data")
@JacksonXmlProperty(localName = "row")
//@CanIAddSomeAnnotationHereForNestedListElements?
public List<List<String>> getData() {
return data;
}
@JacksonXmlElementWrapper(localName = "columns")
@JacksonXmlProperty(localName = "column")
public String[] getColumns() {
return columns;
}
}
TableResponse的JSON,我想看到这样的JSON:
{
"data": [
[
"Row 1 Cell A",
"Row 1 Cell B"
],
[
"Row 2 Cell A",
"Row 2 Cell B"
],
[
"Row 3 Cell A",
"Row 3 Cell B"
]
],
"columns": [
"Column 1",
"Column 2"
]
}
我希望能够像这样制作XML:
<table>
<data>
<row>
<value>Row 1 Cell A</value>
<value>Row 1 Cell B</value>
</row>
<row>
<value>Row 2 Cell A</value>
<value>Row 2 Cell B</value>
</row>
<row>
<value>Row 3 Cell A</value>
<value>Row 3 Cell B</value>
</row>
</data>
<columns>
<column>Column 1</column>
<column>Column 2</column>
</columns>
</table>
但我获得了这个XML(TableResponse的XML),它失去了一个维度:
<table>
<data>
<row>Row 1 Cell A</row>
<row>Row 1 Cell B</row>
<row>Row 2 Cell A</row>
<row>Row 2 Cell B</row>
<row>Row 3 Cell A</row>
<row>Row 3 Cell B</row>
</data>
<columns>
<column>Column 1</column>
<column>Column 2</column>
</columns>
</table>
使用备用POJO结构,我可以实现我对嵌套列表所期望的XML(初始化数据并实例化此结构的类很痛苦)但是JSON不是我想要的:
@JacksonXmlRootElement( localName = "table")
@JsonInclude( JsonInclude.Include.NON_NULL)
public class TableResponseForXML {
protected List data;
protected String[] columns;
public TableResponseForXML( String[] columns, List<Row> data ) {
this.columns = columns;
this.data = data;
}
@JacksonXmlElementWrapper(localName = "data")
@JacksonXmlProperty(localName = "row")
public List<Row> getData() {
return data;
}
@JacksonXmlElementWrapper(localName = "columns")
@JacksonXmlProperty(localName = "column")
public String[] getColumns() {
return columns;
}
public static class Row {
private List<Value> values;
public Row( List<Value> values ) {
this.values = values;
}
@JacksonXmlElementWrapper(localName = "row", useWrapping = false)
@JacksonXmlProperty(localName = "value")
public List<Value> getValues() {
return values;
}
}
public static class Value {
private String value;
public Value( String value ) {
this.value = value;
}
@JsonValue
public String getValue() {
return value;
}
}
}
TableResponseForXML的JSON(对象正在包装内部列表):
{
"data": [
{
"values": [
"Row 1 Cell A",
"Row 1 Cell B"
]
},
{
"values": [
"Row 2 Cell A",
"Row 2 Cell B"
]
},
{
"values": [
"Row 3 Cell A",
"Row 3 Cell B"
]
}
],
"columns": [
"Column 1",
"Column 2"
]
}
我项目中的一些依赖项是:
有没有办法让嵌套列表按照我在JSON和XML之间的预期方式使用第一个POJO结构?与包装每个列表的对象相比,多维JSON数组更易于使用,并且是此API的现有已发布规范。
附注,我也尝试了Jackson: different XML and JSON format中的建议,但未能将我的XmlAdapter / @ XmlJavaTypeAdapter与reslet一起使用。
答案 0 :(得分:2)
使用Jackson注释似乎很难处理这两种格式。对于您的用例,我认为您需要实现一个单独处理JSON和XML的自定义序列化程序。
此序列化程序如下所示:
public class TableResponseSerializer extends StdSerializer<TableResponse> {
private MediaType mediaType;
public TableResponseSerializer(MediaType mediaType) {
super(TableResponse.class);
this.mediaType = mediaType;
}
private void serializeJson(TableResponse swe,
JsonGenerator jgen,
SerializerProvider sp) throws IOException, JsonGenerationException {
(...)
}
private void serializeXml(TableResponse swe,
JsonGenerator jgen,
SerializerProvider sp) throws IOException, JsonGenerationException {
(...)
}
@Override
public void serialize(TableResponse swe,
JsonGenerator jgen,
SerializerProvider sp) throws IOException, JsonGenerationException {
if (mediaType.equals(MediaType.APPLICATION_JSON)) {
serializeJson(swe, jgen, sp);
} else if (mediaType.equals(MediaType.TEXT_XML)) {
serializeXml(swe, jgen, sp);
}
}
}
serializeJson方法将构建JSON内容:
private void serializeJson(TableResponse swe,
JsonGenerator jgen,
SerializerProvider sp) throws IOException, JsonGenerationException {
jgen.writeStartObject();
// Data
jgen.writeArrayFieldStart("data");
for (List<String> row : swe.getData()) {
jgen.writeStartArray();
for (String rowElt : row) {
jgen.writeString(rowElt);
}
jgen.writeEndArray();
}
jgen.writeEndArray();
// Columns
jgen.writeArrayFieldStart("columns");
for (String column : swe.getColumns()) {
jgen.writeString(column);
}
jgen.writeEndArray();
jgen.writeEndObject();
}
和serializeXml one,XML one:
private void serializeXml(TableResponse swe,
JsonGenerator jgen,
SerializerProvider sp) throws IOException, JsonGenerationException {
jgen.writeStartObject();
// Data
jgen.writeObjectFieldStart("data");
jgen.writeArrayFieldStart("row");
for (List<String> row : swe.getData()) {
jgen.writeStartObject();
jgen.writeArrayFieldStart("value");
for (String rowElt : row) {
jgen.writeString(rowElt);
}
jgen.writeEndArray();
jgen.writeEndObject();
}
jgen.writeEndArray();
jgen.writeEndObject();
// Columns
jgen.writeObjectFieldStart("columns");
jgen.writeArrayFieldStart("column");
for (String column : swe.getColumns()) {
jgen.writeString(column);
}
jgen.writeEndArray();
jgen.writeEndObject();
jgen.writeEndObject();
}
最后一步是在Restlet Jackson转换器使用的ObjectMapper
实例上配置序列化器。为此,您需要扩展JacksonConverter
和JacksonRepresentation
类。
首先覆盖JacksonRepresentation
方法的getObjectMapper
类,为TableResponse
类注册序列化器:
public class CustomJacksonRepresentation<T> extends JacksonRepresentation<T> {
public CustomJacksonRepresentation(MediaType mediaType, T object) {
super(mediaType, object);
}
public CustomJacksonRepresentation(Representation representation,
Class<T> objectClass) {
super(representation, objectClass);
}
public CustomJacksonRepresentation(T object) {
super(object);
}
@Override
protected ObjectMapper createObjectMapper() {
ObjectMapper objectMapper = super.createObjectMapper();
if (getObjectClass().equals(TableResponse.class)) {
SimpleModule mod = new SimpleModule("");
mod.addSerializer(new TableResponseSerializer(getMediaType()));
objectMapper.registerModule(mod);
}
return objectMapper;
}
}
然后在必要时使用这种表示的CustomJacksonConverter
类:
public class CustomJacksonConverter extends JacksonConverter {
protected <T> JacksonRepresentation<T> create(MediaType mediaType, T source) {
return new CustomJacksonRepresentation<T>(mediaType, source);
}
protected <T> JacksonRepresentation<T> create(Representation source,
Class<T> objectClass) {
return new CustomJacksonRepresentation<T>(source, objectClass);
}
}
要注册CustomJacksonConverter
课程,您可以在启动组件之前依赖getRegisteredConverters
Engine
。不要忘记删除默认的JacksonConverter
。
List<ConverterHelper> converters = Engine.getInstance().getRegisteredConverters();
JacksonConverter jacksonConverter = new JacksonConverter();
for (ConverterHelper converter : converters) {
if (converter instanceof JacksonConverter) {
jacksonConverter = (JacksonConverter) converter;
break;
}
}
if (jacksonConverter!=null) {
converters.remove(jacksonConverter);
converters.add(new CustomJacksonConverter());
}
这样,您将根据内容协商(Accept
标题)获得XML和JSON所需的输出内容。