JAXB and inheritance

前端 未结 1 1210
时光取名叫无心
时光取名叫无心 2020-12-17 01:53

I am trying to read a JSON file like:

{
  \"a\": \"abc\",
  \"data\" : {
      \"type\" : 1,
      ...
  }
}

where the ... part is replacea

相关标签:
1条回答
  • 2020-12-17 02:44

    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:

    1. A JAXB implementation plus a library like Jettison that converts StAX events to JSON (see: http://blog.bdoughan.com/2011/04/jaxb-and-json-via-jettison.html)
    2. By leveraging a JAXB impl that offers a JSON-binding (see: http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html)
    3. Leveraging a JSON-binding tool that offers support for some JAXB metadata (i.e Jackson).

    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.

    • http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html
    0 讨论(0)
提交回复
热议问题