I am trying to read a JSON file, for example:
{ "a": "abc", "data" : { "type" : 1, ... } }
where ... part changes depending on type type:
{ "a": "abc", "data" : { "type" : 1, "b" : "bcd" } }
or:
{ "a": "abc", "data" : { "type" : 2, "c" : "cde", "d" : "def", } }
In my life, I cannot find suitable JAXB annotations / classes to use to make this happen. I have no problem moving the type variable outside the data block, if necessary.
I am using Glassfish 3.1.2.2.
Edit:
Based on the code provided by Perception, I made a quick attempt ... does not work on a glass planet:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.PROPERTY, property = "type") @JsonSubTypes( { @JsonSubTypes.Type(value = DataSubA.class, name = "1"), @JsonSubTypes.Type(value = DataSubB.class, name = "2") }) @XmlRootElement public abstract class Data implements Serializable { private static final long serialVersionUID = 1L; public Data() { super(); } } @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) public class DataSubA extends Data { private static final long serialVersionUID = 1L; @XmlElement private BigDecimal expenditure; public DataSubA() { super(); } public DataSubA(final BigDecimal expenditure) { super(); this.expenditure = expenditure; } @Override public String toString() { return String.format("%s[expenditure = %s]\n", getClass().getSimpleName(), getExpenditure()); } public BigDecimal getExpenditure() { return expenditure; } public void setExpenditure(BigDecimal expenditure) { this.expenditure = expenditure; } } @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) public class DataSubB extends Data { private static final long serialVersionUID = 1L; @XmlElement private String name; @XmlElement private Integer age; public DataSubB() { super(); } public DataSubB(final String name, final Integer age) { super(); this.name = name; this.age = age; } @Override public String toString() { return String.format("%s[name = %s, age = %s]\n", getClass().getSimpleName(), getName(), getAge()); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } } @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) public class DataWrapper { @XmlElement private Data data; public Data getData() { return data; } public void setData(Data data) { this.data = data; } }
And a simple POST that takes it:
@Stateless @Path("x") public class Endpoint { @POST @Consumes( { MediaType.APPLICATION_JSON, }) @Produces( { MediaType.APPLICATION_JSON, }) public String foo(final DataWrapper wrapper) { return ("yay"); } }
When I go into JSON, for example:
{ "data" : { "type" : 1, "expenditure" : 1 } }
I get a message like:
Can not construct instance of Data, problem: abstract types can only be instantiated with additional type information at [Source: org.apache.catalina.connector.CoyoteInputStream@28b92ec1 ; line: 2, column: 5] (through reference chain: DataWrapper["data"])