I am trying to read a JSON file like:
{
  "a": "abc",
  "data" : {
      "type" : 1,
      ...
  }
}
where the ... part is replaceable based on the type like:
{
  "a": "abc",
  "data" : {
      "type" : 1,
      "b" : "bcd"
  }
}
or:
{
  "a": "abc",
  "data" : {
      "type" : 2,
      "c" : "cde",
      "d" : "def",
  }
}
For the life of me I cannot figure out the proper JAXB annotations/classes to use to make this happen. I don't have an issue moving the type variable outside of the data block if needed.
I'm using Glassfish 3.1.2.2.
Edit:
Based on the code provided by Perception I did a quick attempt... doesn't work in glassfish though:
@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 in:
@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 pass in JSON like:
{
    "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"])
On the DataClass add an @XmlSeeAlso annotation that specifies all of the subclasses:
@XmlRootElement
@XmlSeeAlso({DataSubA.class, DataSubB.class})
public abstract class Data implements Serializable {
Then on each of the subclasses use the @XmlType annotation to specify the type name.
@XmlType(name="1")
public class DataSubA extends Data {
UPDATE
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
The JAXB (JSR-222) specification doesn't cover JSON-binding. There are different ways JAX-RS allows you to specify JSON mapping via JAXB annotations:
Since your model doesn't seem to be reacting as expected to the annotations I'm guessing you are using scenario 3. Below I will demonstrate the solution as if you were using scenario 2.
DataWrapper
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class DataWrapper { 
    private String a;
    private Data data;
}
Data
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({DataSubA.class, DataSubB.class})
public class Data {
}
DataSubA
import javax.xml.bind.annotation.XmlType;
@XmlType(name="1")
public class DataSubA extends Data {
    private String b;
}
DataSubB
import javax.xml.bind.annotation.XmlType;
@XmlType(name="2")
public class DataSubB extends Data {
    private String c;
    private String d;
}
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see:  http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
        properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
        JAXBContext jc = JAXBContext.newInstance(new Class[] {DataWrapper.class}, properties);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StreamSource json = new StreamSource("src/forum16429717/input.json");
        DataWrapper dataWrapper = unmarshaller.unmarshal(json, DataWrapper.class).getValue();
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(dataWrapper, System.out);
    }
}
input.json/Output
MOXy can read in the numeric value 2 as the inheritance indicator, but currently it will always write it out as "2".  I have opened the following enhancement request to address this issue:  http://bugs.eclipse.org/407528.
{
   "a" : "abc",
   "data" : {
      "type" : "2",
      "c" : "cde",
      "d" : "def"
   }
}
For More Information
The following link will help you use MOXy in a JAX-RS implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With