MOXy deserialization exception: A descriptor with default root element was not found in the project

前端 未结 1 739
Happy的楠姐
Happy的楠姐 2020-12-18 01:30

Here are my classes:

@XmlRootElement(name=\"Zoo\")
class Zoo {
    //@XmlElementRef
    public Collection animals;
}

@XmlAccessorTyp         


        
1条回答
  •  死守一世寂寞
    2020-12-18 01:31

    Below are my answers to your two questions:

    Question #1 - Exception

    When you use the MarshallerProperties.JSON_INCLUDE_ROOT property to turn off root elements then you need to use one of the unmarshal methods that takes a Class parameter to tell MOXy the type of object you wish to unmarshal.

    StreamSource json = new StreamSource("src/forum14246033/input.json");
    Zoo zoo = unmarshaller.unmarshal(json, Zoo.class).getValue();
    

    Question #2

    Also a question on the serialized JSON: Is there a way to get the JSON serializer to publish "@type" instead of "type". Currently, it looks like the objects having the property "type". If we could decorate it with "@", it will be more obvious that this is more of a type info than a property.

    The @ prefix indicates that a field/property maps to an XML attribute. You can use the JAXBContextProperties.JSON_ATTRIBUTE_PREFIX property to specify a prefix to qualify data that was mapped to an XML attribute.

    properties.put(JAXBContextProperties.JSON_ATTRIBUTE_PREFIX, "@");
    

    FULL EXAMPLE

    Demo

    package forum14246033;
    
    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 properties = new HashMap(2);
            properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
            properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
            properties.put(JAXBContextProperties.JSON_ATTRIBUTE_PREFIX, "@");
            JAXBContext jc = JAXBContext.newInstance(new Class[] {Zoo.class}, properties);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            StreamSource json = new StreamSource("src/forum14246033/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);
        }
    
    }
    

    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"
       } ]
    }
    

    DOMAIN MODEL

    I don't recommend using public fields in your domain model, but if you go that way you can reduce your metadata down to the following:

    Zoo

    import java.util.Collection;
    
    class Zoo {
        public Collection animals;
    }
    

    Animal

    import javax.xml.bind.annotation.XmlSeeAlso;
    import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode;
    
    @XmlSeeAlso({Bird.class, Cat.class, Dog.class})
    @XmlDiscriminatorNode("@type")
    abstract class Animal {
    
        public String name; 
    
    }
    

    Bird

    import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorValue;
    
    @XmlDiscriminatorValue("Bird")
    class Bird extends Animal {
        public String wingSpan;
        public String preferredFood;
    }
    

    jaxb.properties

    To specify MOXy as your JAXB (JSR-222) provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry:

    javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
    

    0 讨论(0)
提交回复
热议问题