简体   繁体   中英

Java JAXB Marshalling the elements to the objects in inner class

I trying to use the JAXB annotation to convert the JSON data to XML. I have the JSON somewhat like this:

{
   "Employee": {
      "name": "Tanmay",
      "Email": "tanmaypatil@xyz.com",
      "Address": {
         "City": "Florida",
         "State": "Miami"
      }
   }
}

I would like to use marshalling to create the XML which would look something like this: (Please note the extension tag which is not present in JSON but I need to add in XML )

<Company>
    <Employee>
        <FirstName>Tanmay</FirstName>
        <extension>
            <Address>
                <City>Florida</City>
                <State>Miami</State>
            </Address>
        </extension>
    </Employee>
</Company>

I have the following classes:

My main class would actually read the JSON data and marshal it to XML. I have used Jackson to read the JSON data for simplicity purpose I have removed that code:

public class Main
{
    public static void main(String[] args) {
        JsonFactory jsonFactory = new JsonFactory();
        JsonParser jsonParser = jsonFactory.createParser(new File(Main.class.getClassLoader().getResource("InputEPCISEvents.json").toURI()));
        //I am using the JAKSON jsonParser to read the JSON file and automatically map it to the child classes 
        //Ommiting the JACKSON JsonParser code for simplicity purpose
        JAXBContext context = JAXBContext.newInstance(Employee.class);
        Marshaller mar = context.createMarshaller();
        mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        mar.marshal(eventInfo, System.out);
        System.out.println("-----------------");
    }
}

Following is my Parent class which would be mapped to Incoming JSON:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlTransient
public class Employee{
    
    private String name;
    private String email;
    private Address address;
    
    //getters and setters are ommited
    //Noargs and allargs constuctor ommited
    
}

Following is my Address class:

@XmlRootElement(name = "Employee")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Extension", propOrder = { "name","email","city","state"})
private class Address extends Employee{
    
    @XmlElement(name = "extension")
    private Extension extension;
    
    public Extension getExtension() {
        extension.setCity(getCity());
        extension.setState(getState());
        return extension;
    }
    
    public Extension setExtension(Extension extension) {
        this.setCity(extension.getCity());
        this.setState(extension.getState());
        this.extension = extension;
    }
}

Following is the Extension class that I have created as Extension tag will not be present within the incoming JSON but I need to add it to the XML during the marshaling:

@XmlAccessorType(XmlAccessType.FIELD)
public class Extension{
    private String city;
    private String state;
    
    //getters and setters are ommited
    //Noargs and allargs constuctor ommited
}

I would like to know how to do the following things using the JAXB . I am fine with creating some additional classes or modifying the existing class but I cannot change the incoming JSON or XML that I am creating as they are standard format.

  1. How can I map the address , city , state from JSON to Class object. If the elements are present within the Address.class then it can be mapped automatically but since I want the extension tag in XML I have moved them to my Extension.class hence the JAXB cannot recognize it and its not mapping to objects.

  2. How to add the additional extension tag to the XML that will be created during the marshalling. As we can see the JSON does not contain the extension tag but I need it in the XML . If its collection then I can use the @XmlElementWrapper but in my case it's not Collection.

I tried searching a lot but could not find anything that helps me. So based on my understanding I have done above mentioned things. Any help or suggestions would be really appreciated.

I think you have to register all used classes in your JAXBContext

JAXBContext context = JAXBContext.newInstance(Employee.class, Extension.class, ...)

Alternatively, you can also pass the "root" package of all your classes:

JAXBContext context = JAXBContext.newInstance("com.demo.beans")

Finally, I was able to do this using the Moxy @XmlPath . If you are using the Moxy then you can use the @XmlPath and add the additional tags and do not have to create any additional classes.

For example here in this case I do not have to create Extension.class but stil I can add the extension tag to my XML. Moxy is and implementation based on JAXB.

I spent a lot of time trying to figure out a lot of things. Hence, posting the same as it can be helpful to someone in the future.

  1. You can find how to configure Moxy from here . Do not worry its very simple.

  2. You can find how to use @XmlPath from here.

There you go with few very simple steps you can get the wrapper tags in your XML for even non-collection items. Also, no need to create multiple additional classes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM