Jackson 多态序列化生成不正确的类名
Posted
技术标签:
【中文标题】Jackson 多态序列化生成不正确的类名【英文标题】:Jackson polymorphic serialization generates an incorrect class name 【发布时间】:2018-08-21 20:22:42 【问题描述】:当我使用 Jackson 多态序列化时,它会生成一个带有不正确的完全限定类名的 JSON 对象。
下面的代码序列化一个 XMLGregorianCalendar。输出是:
["java.util.GregorianCalendar",-3600000]
我预计会出现以下情况:
["javax.xml.datatype.XMLGregorianCalendar",-3600000]
为什么会输出 java.util.GregorianCalendar?
或者更重要的是:我该如何解决这个问题?
代码示例:
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.io.ByteArrayOutputStream;
public class JacksonGregorianProblem
public static void main(String[] args) throws java.io.IOException, DatatypeConfigurationException
XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar();
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
mapper.writeValue(byteArrayOutputStream, xmlGregorianCalendar);
System.out.println(byteArrayOutputStream);
【问题讨论】:
在检查了 Jackson 的源代码后,我明白为什么它会显示意外行为。在 com.fasterxml.jackson.databind.ext.XMLGregorianCalendarSerializer 类中,XMLGregorianCalendar 被强制转换为 GregorianCalendar。 github.com/FasterXML/jackson-databind/blob/… 所以这就解释了为什么会发生意外行为。 【参考方案1】:为了获得预期的行为,我实现了一个自定义 XMLGregorianCalendar 序列化程序。这个类负责 XLMGregorianCalendar 的序列化,现在输出正是我所期望的。 :-)
class XMLGregorianCalendarSerializer extends StdSerializer<XMLGregorianCalendar>
public XMLGregorianCalendarSerializer()
this(null);
public XMLGregorianCalendarSerializer(Class<XMLGregorianCalendar> t)
super(t);
@Override
public void serialize(XMLGregorianCalendar value, JsonGenerator gen, SerializerProvider provider)
throws IOException
gen.writeNumber(value.toGregorianCalendar().getTimeInMillis());
@Override
public void serializeWithType(XMLGregorianCalendar value, JsonGenerator gen, SerializerProvider provider,
TypeSerializer typeSerializer) throws IOException
gen.writeStartArray();
gen.writeString("javax.xml.datatype.XMLGregorianCalendar");
serialize(value, gen, provider); // call your customized serialize method
gen.writeEndArray();
您可以使用以下代码将此序列化程序添加到对象映射器。可以粘贴在问题中的代码示例中。
SimpleModule module = new SimpleModule();
module.addSerializer(XMLGregorianCalendar.class, new XMLGregorianCalendarSerializer());
mapper.registerModule(module);
【讨论】:
嗨!是的,这是可行的,但它是一个 hack 也许你知道更好的答案? 嗨aarexer,我不知道更好的解决方案。此外,我不认为这是一种黑客行为。在我看来,这是一个适当的解决方案。 ? 为什么我认为这是一个 hack - 因为在我想使用 XMLGregorianCalendar 的每个项目中,我都需要复制此代码并注册我自己的简单模块。而且对我来说不方便 这里讨论了一个相关的问题:github.com/FasterXML/jackson-databind/issues/1791 这个问题被标记为 2.11 版本。所以也许它会在 2.11 中修复。 似乎会在 2.11 中修复,是的,谢谢【参考方案2】:XMLGregorian calendar 假设单独处理序列化和反序列化。因此我更喜欢使用下面的序列化器和反序列化器:
private class XMLCalendarDeserializer extends StdDeserializer<XMLGregorianCalendar>
private DatatypeFactory factory = DatatypeFactory.newDefaultInstance();
public XMLCalendarDeserializer()
super(XMLGregorianCalendar.class);
@Override
public XMLGregorianCalendar deserialize(JsonParser parser, DeserializationContext ctx) throws IOException, JsonProcessingException
if (parser.hasToken(JsonToken.VALUE_STRING))
return factory.newXMLGregorianCalendar(parser.getText());
else
throw new JsonParseException(parser, "not string token");
private class XMLCalendarSerializer extends StdSerializer<XMLGregorianCalendar>
public XMLCalendarSerializer()
super(XMLGregorianCalendar.class);
@Override
public void serialize(XMLGregorianCalendar val, JsonGenerator gen, SerializerProvider ser) throws IOException
gen.writeString(val.toXMLFormat());
`
【讨论】:
以上是关于Jackson 多态序列化生成不正确的类名的主要内容,如果未能解决你的问题,请参考以下文章