3

I'm referencing a web service that returns an array in the format:

{
    "ZooAnimals": {
        "@size": "2",
        "Animal": {
            "0": {
                "@name": "elephant",
                "@size": "huge"
            },
            "1": {
                "@name": "termite",
                "@size": "verysmall"
            }
        }
    }
}

If requested in XML format it returns:

<ZooAnimals size="2">
    <Animal name="elephant" size="huge"></Animal>
    <Animal name="termite" size="very small"></Animal>
</ZooAnimals>

I am writing a test to verify that it gets deserialized properly into a Java class. The XML works properly, but the JSON (using jackson) gives an error: Unrecognized field "0" not marked as ignorable.

I do not control the JSON response and would prefer to use a single class to receive the deserialized contents. The class I inherited was annotated like this:

@XmlAccessorType(XmlAccessType.FIELD)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@JsonTypeName("ZooAnimals")
public class ZooAnimals {

    @XmlAttribute
    @JsonProperty("@size")
    private String size;

    @XmlElement(name = "Animal", required = false)
    @JsonProperty("Animal")
    private List<Animal> animalList;
...
}

@XmlAccessorType(XmlAccessType.FIELD)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@JsonTypeName("Animal")
public class Animal {

    @XmlAttribute
    @JsonProperty("@name")
    private String name;

    @XmlAttribute
    @JsonProperty("@size")
    private String size;
...
}

Is there a way to annotate this class so that jackson can deserialize the text above without my having to write custom code? As an aside, maintaining ordering is not a requirement.

Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
John Dilley
  • 123
  • 8
  • 1
    I doubt it. the web service is not returning a json array (see for e.g. http://www.w3schools.com/json/json_syntax.asp ) so you'd probably have to write some custom serialization to get that into a list. – Taylor Sep 06 '14 at 01:49

1 Answers1

3

You have to use JsonAnySetter annotation and your ZooAnimals class should look like this:

@XmlAccessorType(XmlAccessType.FIELD)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@JsonTypeName("ZooAnimals")
class ZooAnimals {

    @XmlAttribute
    @JsonProperty("@size")
    private String size;

    @XmlElement(name = "Animal", required = false)
    private List<Animal> animalList;

    @JsonAnySetter
    public void setAny(String propertyName, Map<String, Animal> map) {
        animalList = new ArrayList<Animal>(map.values());
    }

    // getters, setters, toString
}

You do not have to change Animal class at all. Below program:

ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
ZooAnimals zooAnimals = mapper.readValue(XML, ZooAnimals.class);
System.out.println(zooAnimals);

prints:

ZooAnimals{size='2', animalList=[Animal{name='elephant', size='huge'}, Animal{name='termite', size='verysmall'}]}
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146