在基于jax-rs的REST API项目中,我们使用Jackson jax-rs XML内容提供者来处理XML内容类型。在序列化POJO列表时,我们需要从POJO中的字段动态设置xml元素名称。
public class ResponsePOJO {
@JacksonXmlProperty
@JacksonXmlElementWrapper(useWrapping = false)
private List<Message> message = new ArrayList<Message>();
}
public class Message {
private String type; // "Error" or "Warning"
private String msg; // The actual message
}
默认Jackson序列化XML:
<ResponsePOJO>
<message>
<type>Error</type>
<msg>Some random error message</msg>
</message>
<message>
<type>Warning</type>
<msg>Some random warning message</msg>
</message>
</ResponsePOJO>
我们的需求是,将type设置为XML元素名。
<ResponsePOJO>
<Error>
<msg>Some random error message</msg>
</Error>
<Warning>
<msg>Some random warning message</msg>
</Warning>
</ResponsePOJO>
为了实现这一点,我们以以下方式编写了一个自定义XML序列化程序:
public class MessageListSerializer extends
JsonSerializer<List<Message>> {
@Override
public void serialize(List<Message> value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
for(Message me : value){
jgen.writeObjectField(me.getType(), me);
}
}
}
并使用注释添加了序列化程序:
@JacksonXmlProperty
@JacksonXmlElementWrapper(useWrapping = false)
@JsonSerialize(using=MessageListSerializer.class)
private List<Message> message = new ArrayList<Message>();
但是,在使用Jackson XMLMapper序列化ResponseJo时,我们得到了以下异常。。。
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Array index out of range: -2
at com.fasterxml.jackson.dataformat.xml.ser.XmlSerializerProvider.serializeValue(XmlSerializerProvider.java:100)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:2866)
at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2289)
Caused by: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: -2
at com.ctc.wstx.sw.BufferingXmlWriter.writeRaw(BufferingXmlWriter.java:241)
at com.ctc.wstx.sw.BaseStreamWriter.writeRaw(BaseStreamWriter.java:1113)
at com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator.writeRaw(ToXmlGenerator.java:592)
at com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter$Lf2SpacesIndenter.writeIndentation(DefaultXmlPrettyPrinter.java:517)
at com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter.writeEndObject(DefaultXmlPrettyPrinter.java:223)
at com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator.writeEndObject(ToXmlGenerator.java:422)
at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer.serialize(XmlBeanSerializer.java:119)
at com.fasterxml.jackson.dataformat.xml.ser.XmlSerializerProvider.serializeValue(XmlSerializerProvider.java:92)
... 3 more
你能帮我解决这个问题吗。。。
我也有类似的问题。我编写了一个自定义JsonSerializer,为集合中的每个项生成不同的xml元素名(从@JsonTypeName读取)。
这是我的JsonSerializer:
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
public class NamedCollectionXmlSerializer extends JsonSerializer<Collection<Object>> {
@Override
public void serialize(Collection<Object> list, JsonGenerator gen, SerializerProvider provider) throws IOException {
boolean toXml = gen instanceof ToXmlGenerator;
if (!toXml) {
// fallback to the default behavior for non-xml serialization
gen.writeObject(list);
return;
}
gen.writeStartArray();
if (list != null) {
for (Object item : list) {
if (item == null) {
continue;
}
JsonTypeName jsonTypeName;
if ((jsonTypeName = item.getClass().getAnnotation(JsonTypeName.class)) != null) {
// read JsonTypeName as the xml element name
// if JsonTypeName not present, use the default name
((ToXmlGenerator) gen).setNextName(new QName("", jsonTypeName.value()));
}
gen.writeObject(item);
}
}
gen.writeEndArray();
}
}
对于以下POJO(由lombok生成的getter和constructor):
interface Message {
}
@Getter
@RequiredArgsConstructor
class ResponsePOJO {
@JacksonXmlElementWrapper(useWrapping = false)
@JsonSerialize(using = NamedCollectionXmlSerializer.class)
private final List<Message> messages;
}
@Getter
@RequiredArgsConstructor
@JsonTypeName("Error")
class Error implements Message {
private final String msg;
}
@Getter
@RequiredArgsConstructor
@JsonTypeName("Warning")
class Warning implements Message {
private final String msg;
}
和测试代码:
ResponsePOJO response = new ResponsePOJO(
Arrays.asList(new Error("error1"), new Warning("warn1"), new Error("error2"))
);
new XmlMapper().writerWithDefaultPrettyPrinter().writeValue(System.out, response);
这是输出:
<ResponsePOJO>
<Error>
<msg>error1</msg>
</Error>
<Warning>
<msg>warn1</msg>
</Warning>
<Error>
<msg>error2</msg>
</Error>
</ResponsePOJO>
PS:我用jackson 2.9.3版测试我的代码
“我不能发表评论,因为它太长了。”以下是定制类:
java prettyprint-override"> @XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class MyResponse {
@XmlElements({ @XmlElement(name = "error", type = MyError.class),
@XmlElement(name = "warning", type = MyWarning.class) })
@XmlElementWrapper
private List<MyMessage> messages = Lists.newArrayList();
public List<MyMessage> getMessages() {
return messages;
}
public void setMessages(List<MyMessage> messages) {
this.messages = messages;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
public class MyMessage {
protected String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
public class MyError extends MyMessage {
}
@XmlAccessorType(XmlAccessType.FIELD)
public class MyWarning extends MyMessage {
}
我用我的演示代码进行了测试:
MyResponse myResponse = new MyResponse();
MyMessage error = new MyError();
error.setText("error");
MyMessage warning = new MyWarning();
warning.setText("warning");
myResponse.setMessages(Lists.newArrayList(error, warning));
然后它返回:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myResponse>
<messages>
<error>
<text>error</text>
</error>
<warning>
<text>warning</text>
</warning>
</messages>
</myResponse>
不过,您需要调整元素名称以获得所需的结果。
编辑到以前的解决方案:你就快到了,只需要添加@JsonIgnore
到私有字符串类型;//"错误"或"警告"
<ResponsePOJO>
<Error>
<msg>error message</msg>
</Error>
<Warning>
<msg>warning message</msg>
</Warning>
</ResponsePOJO>
以下内容将输出上述xml:
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Main demo = new Main();
demo.run();
}
public void run(){
ObjectMapper xmlMapper = new XmlMapper();
ResponsePOJO responsePOJO = new ResponsePOJO();
Message message = new Message();
message.setType("Error");
message.setMsg("error message");
Message message2 = new Message();
message2.setType("Warning");
message2.setMsg("warning message");
responsePOJO.getMessage().add(message);
responsePOJO.getMessage().add(message2);
try {
String xml = xmlMapper.writeValueAsString(responsePOJO);
System.out.println(xml);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
public class ResponsePOJO {
@JacksonXmlProperty
@JacksonXmlElementWrapper(useWrapping = false)
@JsonSerialize(using=MessageListSerializer.class)
private List<Message> message = new ArrayList<Message>();
public List<Message> getMessage() {
return message;
}
}
public class Message {
@JsonIgnore
private String type; // "Error" or "Warning"
private String msg; // The actual message
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
}
和全班同学一起
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.List;
/**
* Created by Pand on 08/04/2015.
*/
public class MessageListSerializer extends
JsonSerializer<List<Main.Message>> {
@Override
public void serialize(List<Main.Message> value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
for(Main.Message me : value){
jgen.writeObjectField(me.getType(), me);
}
}
}
有依赖关系
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<version>4.1.4</version>
</dependency>
</dependencies>
有没有一个Jackson注释允许将数组反序列化到我的POJO的特定字段中?我可以用自定义的反序列化器很容易地做到这一点,但我希望用类内联的方式来完成。 例如,我从Elasticsearch返回了以下JSON。 我的POJO如下: 我希望“排序”数组(在数组[0]中总是有一个long,在数组[1]中总是有一个String)被反序列化如下: 我发现了另一个问题,唯一的答案是自定义的反序列化器,如果可以
我有以下xml 我需要将其反序列化为以下POJO: 这里的问题是被包装在元素中
有没有办法用Jackson来配置这个?如果没有,是否有一种有效的方法来编写(假设中的值可以是更复杂但众所周知的一致类型)?
问题内容: 使用Jackson 2,我正在寻找一种 通用的 方式将对象序列化为单个值(然后序列化它们,然后再填充该单个字段),而不必重复创建JsonSerializer / JsonDeserializer来处理每种情况。@JsonIdentityInfo批注非常接近,但由于我知道,它将始终对完整的子对象进行序列化,因此略微遗漏了该标记。 这是我想做的一个例子。给定的类: 我希望Order可以序列
但它抛出了一个异常: JSONMappingException:意外标记(VALUE_NUMBER_INT),预期的value_string:预期的数组或字符串。 如何将epoch反序列化为?我想补充一点,如果将datatype从更改为,它可以非常好地工作。因此,最好反序列化到并创建getter和setter,它们将执行到的转换。
有人能帮我把它弄好吗。谢谢你。