Frank
Frank

Reputation: 671

Parse XML string to class object

I have an XML String like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes">
<Result xmlns="http://example.com/entities">
  <published>2022-02-17T14:26:54.000+01:00</published>
  <Id>10</Id>
  <QueryResults>
    <Id>11</Id>
    <created>2022-02-17T12:15:54.000+01:00</created>
  </QueryResults>
  <QueryResults>
    <Id>12</Id>
    <created>2022-02-17T12:16:54.000+01:00</created>
  </QueryResults>
</Result>
public class ResultModel {
  @JsonProperty("Id")
  private int id;
  @JsonProperty("published")
  private Date published;
  @JsonProperty("QueryResults")
  private List<QueryResult>

  // GETTERS and SETTERS
}

public class QueryResult {
  @JsonProperty("Id")
  private int id;
  @JsonProperty("created")
  private Date created;
}

When I try to read the string into an object like this

try {
  com.fasterxml.jackson.dataformat.xml.XmlMapper mapper = new XmlMapper();
  ResultModel obj = mapper.readValue(xmlString, ResultModel.class)
} catch (JsonProcessingException e) {
  e.printStackTrace();
}

I get the following error:

com.fasterxml.jackson.databind.exc.MisMatchedInputException: Cannot construct instance of `a.b.c.d.ResultModel` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ("11")
  at [Source: (StringReader); line 1, column 15] (through reference chain: a.b.c.d.ResultModel["QueryResults"]->java.util.ArrayList[0]

I am using @JsonProperty in the class because with @XmlElement I had other issues. If I exclude the field QueryResults in my ResultModel class, then the parsing of the string works and looks correct. What am I doing wrong here? I am very new to parsing of XML strings in Java so I hope there is something easy to fix this...

Upvotes: 0

Views: 702

Answers (1)

jcompetence
jcompetence

Reputation: 8413

You need to use the following 2 annotations:

    @JacksonXmlElementWrapper(useWrapping=false)
    @JacksonXmlProperty(localName = "QueryResults")

@Data
static class ResultModel {
    @JsonProperty("Id")
    private int id;
    @JsonProperty("published")
    private Date published;

    @JacksonXmlElementWrapper(useWrapping=false)
    @JacksonXmlProperty(localName = "QueryResults")
    private List<QueryResult> queryResult;

}

@Data
static class QueryResult {
    @JsonProperty("Id")
    private int id;
    @JsonProperty("created")
    private Date created;
}

public static void main(String[] argz) throws JsonProcessingException {

    String xml = "<Result>\n"
            + "  <published>2022-02-17T14:26:54.000+01:00</published>\n"
            + "  <Id>10</Id>\n"
            + "  <QueryResults>\n"
            + "    <Id>11</Id>\n"
            + "    <created>2022-02-17T12:15:54.000+01:00</created>\n"
            + "  </QueryResults>\n"
            + "  <QueryResults>\n"
            + "    <Id>12</Id>\n"
            + "    <created>2022-02-17T12:16:54.000+01:00</created>\n"
            + "  </QueryResults>\n"
            + "</Result>";

    XmlMapper mapper = new XmlMapper();
    ResultModel obj = mapper.readValue(xml, ResultModel.class);
    System.out.println(obj);

}

Console:

ResultModel(id=10, published=Thu Feb 17 14:26:54 CET 2022, queryResult=[QueryResult(id=11, created=Thu Feb 17 12:15:54 CET 2022), QueryResult(id=12, created=Thu Feb 17 12:16:54 CET 2022)])

Updated:

Lists and arrays are "wrapped" by default, when using Jackson annotations, but unwrapped when using JAXB annotations (if supported, see below) @JacksonXmlElementWrapper.useWrapping can be set to 'false' to disable wrapping JacksonXmlModule.setDefaultUseWrapper() can be used to specify whether "wrapped" or "unwrapped" setting is the default

https://github.com/FasterXML/jackson-dataformat-xml#known-limitations

Upvotes: 1

Related Questions