EclipseLink MOXy JSON Serialization

☆樱花仙子☆ 提交于 2019-12-18 05:51:36

问题


I have got a sample class:

class Zoo {
    public Collection<? extends Animal> animals;
}

When serialized with MOXy, I am getting:

{
    "bird": [
        {
            "name": "bird-1",
            "wingSpan": "6 feets",
            "preferredFood": "food-1"
        }
    ],
    "cat": [
        {
            "name": "cat-1",
            "favoriteToy": "toy-1"
        }
    ],
    "dog": [
        {
            "name": "dog-1",
            "breed": "bread-1",
            "leashColor": "black"
        }
    ]
}

Why is it using array indicators "[]", while bird, cat, and dog are not arrays? Second, is there a way to get rid of "bird", "cat", and "dog"?

In other words, I am trying to get to:

{
        {
            "name": "bird-1",
            "wingSpan": "6 feets",
            "preferredFood": "food-1"
        }
    ,
        {
            "name": "cat-1",
            "favoriteToy": "toy-1"
        }
    ,
        {
            "name": "dog-1",
            "breed": "bread-1",
            "leashColor": "black"
        }
}

Thanks, Behzad


回答1:


QUESTION #1

Why is it using array indicators "[]", while bird, cat, and dog are not arrays?

To get this JSON representation you have mapped your model with the @XmlElementRef annotation which tells JAXB to use the value of the @XmlRootElement annotation as the inheritance indicator. With MOXy's JSON binding these become keys. We make the value of these keys JSON arrays since keys are not allowed to repeat.

Zoo

In your model you have the @XmlElementRef annotation on your animals field/property.

import java.util.Collection;
import javax.xml.bind.annotation.XmlElementRef;

class Zoo {
    @XmlElementRef
    public Collection<? extends Animal> animals;
}

Animal

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({Bird.class, Cat.class, Dog.class})
public abstract class Animal {

    private String name;

}

Bird

On each of your subclasses you have an @XmlRootElement annotation.

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Bird extends Animal {

    private String wingSpan;
    private String preferredFood;

}

input.json/Output

{
   "bird" : [ {
      "name" : "bird-1",
      "wingSpan" : "6 feets",
      "preferredFood" : "food-1"
   } ],
   "cat" : [ {
      "name" : "cat-1",
      "favoriteToy" : "toy-1"
   } ],
   "dog" : [ {
      "name" : "dog-1",
      "breed" : "bread-1",
      "leashColor" : "black"
   } ]
}

For More Information

  • http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html

QUESTION #2

Second, is there a way to get rid of "bird", "cat", and "dog"?

You are going to need some sort of inheritance indicator to represent the various subclasses.

OPTION #1 - @XmlDescriminatorNode/@XmlDescriminatorValue

Here I do this using MOXy's @XmlDescriminatorNode/@XmlDescriminatorValue annotations.

Zoo

import java.util.Collection;

class Zoo {
    public Collection<? extends Animal> animals;
}

Animal

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({Bird.class, Cat.class, Dog.class})
@XmlDiscriminatorNode("@type")
public abstract class Animal {

    private String name;

}

Bird

import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorValue;

@XmlDiscriminatorValue("bird")
public class Bird extends Animal {

    private String wingSpan;
    private String preferredFood;

}

input.json/Output

{
   "animals" : [ {
      "type" : "bird",
      "name" : "bird-1",
      "wingSpan" : "6 feets",
      "preferredFood" : "food-1"
   }, {
      "type" : "cat",
      "name" : "cat-1",
      "favoriteToy" : "toy-1"
   }, {
      "type" : "dog",
      "name" : "dog-1",
      "breed" : "bread-1",
      "leashColor" : "black"
   } ]
}

For More Information

  • http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-moxy-extension.html

OPTION #2 - @XmlClassExtractor

ClassExtractor (AnimalExtractor)

You can write some code that will determine the appropriate subclass based on the JSON content.

import org.eclipse.persistence.descriptors.ClassExtractor;
import org.eclipse.persistence.sessions.*;

public class AnimalExtractor extends ClassExtractor {

    @Override
    public Class extractClassFromRow(Record record, Session session) {
        if(null != record.get("@wingSpan") || null != record.get("@preferredFood")) {
            return Bird.class;
        } else if(null != record.get("@favoriteToy")) {
            return Cat.class;
        } else {
            return Dog.class;
        }
    }

}

Animal

The @XmlClassExtractor annotation is used to specify the ClassExtractor.

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlClassExtractor;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({Bird.class, Cat.class, Dog.class})
@XmlClassExtractor(AnimalExtractor.class)
public abstract class Animal {

    private String name;

}

Bird

Due to how MOXy processes the @XmlElement and @XmlAttribute annotations, any of the data you want to be made available to the ClassExtractor will need to be annotated with @XmlAttribute.

import javax.xml.bind.annotation.XmlAttribute;

public class Bird extends Animal {

    @XmlAttribute
    private String wingSpan;

    @XmlAttribute
    private String preferredFood;

}

input.json/Output

{
   "animals" : [ {
      "wingSpan" : "6 feets",
      "preferredFood" : "food-1",
      "name" : "bird-1"
   }, {
      "favoriteToy" : "toy-1",
      "name" : "cat-1"
   }, {
      "breed" : "bread-1",
      "leashColor" : "black",
      "name" : "dog-1"
   } ]
}

For More Information

  • http://blog.bdoughan.com/2012/02/jaxb-and-inheritance-eclipselink-moxy.html

DEMO CODE

The following demo code can be used with both of the mappings described above.

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[] {Zoo.class}, properties);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StreamSource json = new StreamSource("src/forum14210676/input.json");
        Zoo zoo = unmarshaller.unmarshal(json, Zoo.class).getValue();

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(zoo, System.out);
    }

}


来源:https://stackoverflow.com/questions/14210676/eclipselink-moxy-json-serialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!