Jackson xml模块:使用@JacksonXmlText属性反序列化不可变类型

时间:2017-08-15 09:36:09

标签: java xml jackson

我想将一个不可变类型序列化为json和xml:

序列化的JSON就像:

{
    "text" : "... the text..."
}

,序列化的xml就像:

 <asText>_text_</asText>

(请注意,文本是xml的元素文本)

java对象如下:

@JsonRootName("asText")
@Accessors(prefix="_")
public static class AsText {

    @JsonProperty("text") @JacksonXmlText
    @Getter private final String _text;

    public AsText(@JsonProperty("text") final String text) {
        _text = text;
    }
}

请注意_text属性是 final (因此对象是不可变的)并且使用@JacksonXmlText进行注释,以便序列化为xml元素&#39; s文本

作为对象不可变,需要文本中的构造函数,构造函数的参数必须用@JsonProperty注释

    public AsText(@JsonProperty("text") final String text) {
        _text = text;
    }

对JSON进行序列化/反序列化时,一切正常 ...在向/从XML序列化/反序列化时出现问题:

 // create the object
 AsText obj = new AsText("_text_");

 // init the mapper
 XmlMapper mapper = new XmlMapper();

 // write as xml
 String xml = mapper.writeValueAsString(obj);
 log.warn("Serialized Xml\n{}",xml);

 // Read from xml
 log.warn("Read from Xml:");
 AsText objReadedFromXml = mapper.readValue(xml,
                                              AsText.class);
 log.warn("Obj readed from serialized xml: {}",
          objReadedFromXml.getClass().getName());

例外是:

    com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "" (class r01f.types.url.UrlQueryStringParam), not marked as ignorable (2 known properties: "value", "name"])

似乎xml模块需要对对象的构造函数进行注释,如:

    public AsText(@JsonProperty("") final String text) {
        _text = text;
    }

但这甚至不起作用:

    com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `test.types.SerializeAsXmlElementTextTest$AsText` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

需要在构造函数的参数中使用注释@JsonProperty("text")来从JSON反序列化

......我怎样才能让它发挥作用

3 个答案:

答案 0 :(得分:5)

尝试为该属性添加公共getter。我认为应该解决反序列化问题。

@JsonRootName("asText")
@Accessors(prefix = "_")
public static class AsText {

    @JsonProperty("text")
    @JacksonXmlText
    @Getter
    private final String _text;

    public AsText(@JsonProperty("text") final String text) {
        _text = text;
    }

    public String getText() {
        return _text;
    }
}

实际上,它的工作原理也没有添加吸气剂,这些版本的Lombak&amp;杰克逊。

<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
        <version>2.9.0</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.18</version>
    </dependency>
</dependencies>

答案 1 :(得分:3)

我遇到了与错误相同的问题&#34;没有基于委托或属性的Creator&#34;。就我而言,它是Immutables版本2.5.6的问题。我通过降级到版本2.5.5修复了它。版本2.5.6在mvnrepository.com中可用,但在官方页面上是标记为2.5.5的稳定版本。

答案 2 :(得分:3)

更新2018年

这个hack在2.9.0中工作但似乎在commit之后停止工作。目前尚不清楚是否有一种简单的方法可以让它再次发挥作用。

看起来您的问题的主要原因是您尝试同时使用JSON和XML序列化但具有不同的配置。不幸的是,XmlMapper继承自ObjectMapper并继承了所有特定于JSON的配置(您可以覆盖它但不能使用特定于XML的注释清除它),这是您发生冲突的原因。似乎最简单的解决方法是在构造函数中使用@JsonAlias注释。它有点hacky但它​​的工作原理。这是一个适合我的最小例子(没有Lombok):

@JsonRootName("asText")
public static class AsText {

    @JsonProperty("text")
    @JacksonXmlText
    private final String _text;

    public AsText(@JsonAlias("") @JsonProperty("text") final String text) {
        _text = text;
    }

    @JsonIgnore
    public String getText() {
        return _text;
    }

    @Override
    public String toString() {
        return "AsText{" +
                "_text='" + _text + '\'' +
                '}';
    }
}

请注意,我还在getter中添加了@JsonIgnore,因为我没有获得您请求的XML格式(并且您可以使用onX中描述的Lombok的onMethod执行相同操作

进行简单的测试:

public static void main(String[] args) throws IOException {
    // create the object
    AsText obj = new AsText("123_text_");

    // init the mapper
    //ObjectMapper mapper = new ObjectMapper();
    XmlMapper mapper = new XmlMapper();

    // write as xml
    String xml = mapper.writeValueAsString(obj);
    System.out.println("Serialized Xml\n" + xml);

    // Read from xml
    AsText objReadedFromXml = mapper.readValue(xml, AsText.class);
    System.out.println("Read from Xml: " + objReadedFromXml);
}

我得到以下输出:

  

序列化Xml   
&lt; asText&gt; 123_text_&lt; / asText&gt;   
从Xml读取:AsText {_text ='123_text _'}