[英]Jackson Serialization: Setting field value as XML element name
我們使用Jackson jax-rs XML內容提供程序在我們基於jax-rs的REST API項目中處理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>
我們的要求,即將類型設置為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序列化ResponsePOJO時,我們得到以下異常......
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
你能幫我解決這個問題嗎?
編輯到以前的解決方案:你幾乎就在那里,只需要將@JsonIgnore
添加到private String type; // "Error" or "Warning"
private String type; // "Error" or "Warning"
<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>
我的觀點是你的方法過於復雜。 我會改為將你的消息類重組為:
public class Message { private String msg; // The actual message }
public class Message { private String msg; // The actual message }
,並根據類型對其進行子類化:
public class Error extends Message { }
public class Warning extends Message { }
。
此外,此方法允許您為每種類型添加更靈活的自定義字段。
“我不能發表評論,因為它太長了”以下是自定義類:
@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>
您需要調整元素名稱以獲得所需的結果。
我也有類似的問題。 我編寫了一個自定義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和構造函數):
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:我用傑克遜版本2.9.3測試我的代碼
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.