I have the below class structure.
#XmlSeeAlso({Phone.class, Address.class})
abstract class ContactInfo {
}
#XmlRootElement(name="address")
class Address extends ContactInfo {
private String street;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
#XmlRootElement(name="phone")
class Phone extends ContactInfo {
private String mobile;
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
class Contact {
private ContactInfo contact;
#XmlElementRef
public ContactInfo getContact() {
return contact;
}
public void setContact(ContactInfo contact) {
this.contact = contact;
}
}
#XmlRootElement(name="user")
class User {
private String name;
private Contact contact;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
}
When I convert this to XML using JAXB, I am getting the below structure.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
<contact>
<phone>
<mobile>8971829749</mobile>
</phone>
</contact>
<name>Halley</name>
</user>
Where as my JSON looks a bit different.
{
"User" : {
"name" : "Halley",
"contact" : {
"contact" : {
"mobile" : "8971829749"
}
}
}
}
The root element user, and phone is not at all present in my sub JSON structure.
While JAXB is honouring the XMLRootElement annotation, Jackson is not. Any idea why and how I can rectify this?
I need to generate JSON and XML from the same entity classes.
you can use
#JsonRootName as class level annotation
and ObjectMapper to configure serialization to use root element.
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
Using JsonRootName is optional unless you want to have different element name than XML.
As Jackson is ignoring the element name provided via #XmlRootElement, the Jackson annotations #JsonTypeInfo and #JsonSubTypes should be used to specify which ContactInfo type is Address or Phone. See https://stackoverflow.com/a/6543330/6911095 for an example.
Related
public class RequestXml // this pojo for RequestXML
{
private Contact[] Contact;
public Contact[] getContact ()
{
return Contact;
}
#XmlElement(name="Contact")
public void setContact (Contact[] Contact)
{
this.Contact = Contact;
}
}
another pojo
public class Contact // this class is for contact
{
private String content;
private String role;
public String getContent ()
{
return content;
}
#XmlElement(name="content")
public void setContent (String content)
{
this.content = content;
}
public String getRole ()
{
return role;
}
#XmlElement(name="role")
public void setRole (String role)
{
this.role = role;
}
}
As I am getting result like below while marshalling
<Contact role="firstUser"/>
<Contact role="secondUser"/>
<Contact role="LastUser"/>
As below is the expected output:
<Contact role="firstUser">aaaa</Contact>
<Contact role="secondUser">bbbb</Contact>
<Contact role="LastUser">cccc</Contact>
Please help me on this.
For marshalling the field as content, use the #XmlValue annotation. For marshalling it as attribute, use the #XmlAttribute. This is how the Contract POJO looks like, along with my test:
#XmlRootElement
public class RequestXml {
private Contact[] contact;
#XmlElement(name = "Contact")
public Contact[] getContact() {
return contact;
}
public void setContact(Contact[] Contact) {
this.contact = Contact;
}
}
public class Contact {
private String content;
private String role;
public Contact(String content, String role) {
this.content = content;
this.role = role;
}
#XmlValue
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
#XmlAttribute
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
The test:
public class JaxbTest {
#Test
public void testObjectToXml() throws JAXBException {
RequestXml requestXml = new RequestXml();
requestXml.setContact(new Contact[]{new Contact("aaa", "bbb")});
JAXBContext jaxbContext = JAXBContext.newInstance(RequestXml.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(requestXml, System.out);
}
}
This provides the following output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<requestXml>
<Contact role="bbb">aaa</Contact>
</requestXml>
EDIT: Also, see What is the difference between using #XmlElement before field and before getter declaration? for the difference of annotating getters/setters and fields.
I need to execute a selective marshalling object. For example:
There is a class Contact:
#XmlRootElement(name = "contact")
public class Contact {
private String name;
private String number;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Marshalling the object:
public static void main(String[] args) throws JAXBException {
Contact contact = new Contact();
contact.setAddress("5 Av.");
contact.setName("John");
contact.setNumber("5555555");
JAXBContext context = JAXBContext.newInstance(Contact.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(contact, System.out);
}
As a result we have:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contact>
<address>5 street</address>
<name>John</name>
<number>5555555</number>
</contact>
Is there any simple way to perform a selective marshalling? For example, only the address to get at the output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contact>
<address>5 street</address>
</contact>
Thanks!
When unspecified, the default is as-if the following annotation is on the class:
#XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
That means that all public member will be used by JAXB, i.e. all your getter methods.
You can either keep that default and suppress the getter methods you don't want, or you can change the default and explicitly mark the getter methods you do want processed.
To suppress a getter method, annotate with #XmlTransient:
Prevents the mapping of a JavaBean property/type to XML representation.
To change default, annotate with #XmlAccessorType(XmlAccessType.NONE):
None of the fields or properties is bound to XML unless they are specifically annotated with some of the JAXB annotations.
Then explicitly annotate desired getter methods with #XmlElement:
Maps a JavaBean property to a XML element derived from property name.
Using #XmlTransient
#XmlRootElement(name = "contact")
class Contact {
private String name;
private String number;
private String address;
#XmlTransient
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlTransient
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Using #XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "contact")
#XmlAccessorType(XmlAccessType.NONE)
class Contact {
private String name;
private String number;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
#XmlElement
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Output (from both)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contact>
<address>5 Av.</address>
</contact>
So I have code like this:
#XmlRootElement(name = "person")
#XmlType(propOrder = {"name", "secondName"})
public class Person {
private String name;
private String secondName;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setSecondName(String secondName) {
this.secondName = secondName;
}
public String getSecondName() {
return secondName;
}
}
And when I want to create XML file it makes me:
<person>
<name>John</name>
<secondName>Smith</secondName>
</person>
Is it any way to make in xml file <second-name> instead of <secondName> without changing in class on private String second-name?
Problem solved. I should just do this:
#XmlElement(name="second-name")
public String getSecondName() {
return secondName;
}
I am writing a Restful webservice which would receive data in the below format.
{
"myOrder": {
"submitDate": "2015-04-16T02:52:01.406-04:00",
"supplier": "Amazon",
"orderName": "Wifi Router",
"submittedBy": "Gaurav Varma",
"price": {
"value": "2000",
"currency": "USD"
},
"address": {
"name": "My home",
"address": "Unknow island",
"city": "Mainland China",
"state": "Xinjiang",
"contact": {
"firstName": "Gaurav",
"lastName": "Varma",
"phone": "000-000-0000",
"email": "test#gv.com"
}
}
}
}
To read that data I am considering Jackson or GSON frameworks. The easiest way would be to use a Java POJO which has exactly the same structure as the json request. But for me the structure of Java POJOs is different. I have four different pojo as mentioned below :
Submitter.java
- SubmittedBy
- SubmitDate
Order.java
- Supplier
- OrderName
Price.java
- Value
- Currency
Address.java
- Name
- Address
- City
- State
Contact.java
- FirstName
- LastName
- Phone
- Email
Question : Is it a way to parse the json once into five different POJOs. May be some annotation based approach where we can map json attribute to respective pojo attribute? Any framework available for it?
Thanks in advance !
I'm currently using Jackson on my project. You have the option of annotating your POJO fields with #JsonProperty or #JsonUnwrapped. You would use #JsonUnwrapped on Order, for example, and then Order would have two fields (supplier and orderName) that use #JsonProperty.
See here for more details.
You could use eclipse link moxy for this. It uses JAXB style annotations for field to JSON/XML mapping.
Moxy is part of eclipse link.
Wikipedia:
EclipseLink is the open source Eclipse Persistence Services Project
from the Eclipse Foundation. The software provides an extensible
framework that allows Java developers to interact with various data
services, including databases, web services, Object XML mapping (OXM),
and Enterprise Information Systems (EIS).
So in your code you would use it like;
Model A:
#XmlElement(name="completed_in")
public float getCompletedIn() {
return completedIn;
}
Model B:
#XmlElement(name="created_at")
#XmlJavaTypeAdapter(DateAdapter.class)
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
#XmlElement(name="from_user")
public String getFromUser() {
return fromUser;
}
Json:
{
"completed_in":0.153,
{
"created_at":"Fri, 12 Aug 2011 01:14:57 +0000",
"from_user":"stackfeed",
you can use the composition design pattern and have an instance of each object in a wrapper class. Or you can try to parse the json into a map and write code to instantiate and set the variables as needed.
You could use Jackson; I think you need a POJO to wrapp the Order and Address like
class FullOrder {
Order order;
Address address;
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
With this you can easily use Jackson
String json; // your json here
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.readValue(json, FullOrder.class);
And that will parse the json into your pojo. Hope it helps you
The full structure
class Submitter {
private Date submittedBy;
private Date submitDate;
public Date getSubmittedBy() {
return SubmittedBy;
}
public void setSubmittedBy(Date submittedBy) {
SubmittedBy = submittedBy;
}
public Date getSubmitDate() {
return SubmitDate;
}
public void setSubmitDate(Date submitDate) {
SubmitDate = submitDate;
}
}
class Order {
private String supplier;
private String orderName;
private Price price;
private Submitter submitter;
public Price getPrice() {
return price;
}
public void setPrice(Price price) {
this.price = price;
}
public Submitter getSubmitter() {
return submitter;
}
public void setSubmitter(Submitter submitter) {
this.submitter = submitter;
}
public String getSupplier() {
return Supplier;
}
public void setSupplier(String supplier) {
Supplier = supplier;
}
public String getOrderName() {
return OrderName;
}
public void setOrderName(String orderName) {
OrderName = orderName;
}
}
class Price {
private int value;
private int currency;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getCurrency() {
return currency;
}
public void setCurrency(int currency) {
this.currency = currency;
}
}
class Address {
private String name;
private String address;
private String city;
private String state;
private Contact contact;
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
class Contact {
String firstName;
String lastName;
long phone;
String email;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public long getPhone() {
return phone;
}
public void setPhone(long phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
class FullOrder {
Order myOrder;
Address address;
public Order getMyOrder() {
return order;
}
public void setMyOrder(Order order) {
this.order = order;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
This is structure of your json, you only need to copy it and use the Object mapper to parse the json to the pojo (FullOrder) that contains the other pojos and properties
String json; // your json here
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.readValue(json, FullOrder.class);
I figured out the solution approach. Posting for other users. The complete implementation is on my blog - http://javareferencegv.blogspot.com/2015/04/parse-json-into-multiple-java-pojos.html
So basically 3 points regarding solution approach:
We use Jackson annotation - #JsonIgnoreProperties. This would make
sure only those fields in Pojo are mapped to JSON attributes. So we
read the json twice, once mapping to Order.java and then to
Submitter.java. Both gets the correspondingly mapped fields.
We use Jackson annotation - #JsonProperty. This lets us map the exact JSON attribute to a field in POJO. The annotation makes sure different named attributes in JSON and POJO are mapped.
Jackson doesn't provide any annotation to perform #JsonWrapped (The vice-versa #JsonUnwrapped is available for serialization). Hence, we map Price as an attribute in Order.java.
The main class looks like this :
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonDeserializer {
public static void main(String[] args) {
try {
// ObjectMapper provides functionality for data binding between
ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"submitDate\":\"2015-04-16\",\"submittedBy\":\"Gaurav Varma\",\"supplier\":\"Amazon\",\"orderName\":\"This is my order\","
+ "\"price\": {\"value\": \"2000\",\"currency\": \"USD\"}"
+ "}";
System.out.println("JSON String: " + jsonString);
// Deserialize JSON to java format and write to specific POJOs
Submitter submitterObj = mapper.readValue(jsonString, Submitter.class);
Order orderObj = mapper.readValue(jsonString, Order.class);
Price priceObj = orderObj.getPrice();
System.out.println("submitterObj: " + submitterObj);
System.out.println("orderObj: " + orderObj);
System.out.println("priceObj: " + priceObj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
How can i create following type xml in java using jaxb
<myInfo>
<firstName>MyfirstName</firstName>
<lastName>MyLstNme</lastName>
<contactList>
<contact>
<id>001</id>
<name>name1</name>
<contact/>
<contact>
<id>002</id>
<name>name2</name>
<contact/>
<contact>
<id>003</id>
<name>name3</name>
<contact/>
</ContactList>
</myInfo>
Bean Classes are..
#XmlRootElement(name = "myInfo")
#XmlAccessorType(XmlAccessType.FIELD)
public class MyInfo {
#XmlElement(name = "firstName")
public String firstName;
#XmlElement(name = "lastName")
public String lastName;
#XmlElement(name = "contactList")
public ContactList contactList;
...getter setter
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "contactList")
public class ContactList {
#XmlElement(name = "contact", type = Contact.class)
public List<Contact> list = new ArrayList<Contact>();
public ContactList() {
}
public ContactList(List<Contact> list) {
this.list = list;
}
...getter setter
}
#XmlRootElement(name = "Contact")
public class Contact {
#XmlElement(name = "id")
public String id;
#XmlElement(name = "name")
public String name;
...getter setter
And Exception
objData ToXML 2 counts of IllegalAnnotationExceptions
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
==
Class has two properties of the same name "id"
this problem is related to the following location:
at public java.lang.String java8javafx8.Contact.getId()
at java8javafx8.Contact
at public java.util.List java8javafx8.ContactList.list
at java8javafx8.ContactList
at public java8javafx8.ContactList java8javafx8.MyInfo.contactList
at java8javafx8.MyInfo
this problem is related to the following location:
at public java.lang.String java8javafx8.Contact.id
at java8javafx8.Contact
at public java.util.List java8javafx8.ContactList.list
at java8javafx8.ContactList
at public java8javafx8.ContactList java8javafx8.MyInfo.contactList
at java8javafx8.MyInfo
Class has two properties of the same name "name"
this problem is related to the following location:
at public java.lang.String java8javafx8.Contact.getName()
at java8javafx8.Contact
at public java.util.List java8javafx8.ContactList.list
at java8javafx8.ContactList
at public java8javafx8.ContactList java8javafx8.MyInfo.contactList
at java8javafx8.MyInfo
this problem is related to the following location:
at public java.lang.String java8javafx8.Contact.name
at java8javafx8.Contact
at public java.util.List java8javafx8.ContactList.list
at java8javafx8.ContactList
at public java8javafx8.ContactList java8javafx8.MyInfo.contactList
at java8javafx8.MyInfo
How create Bean Class and Bean List Class??
Ok hear you go:
Make one class call MyInfo as:
#XmlRootElement(name="myInfo")
public class MyInfo {
private String firstName;
private String lastName;
private List<Contact> contactList = new ArrayList<Contact>(0);
public MyInfo(){}
public MyInfo(String fName, String lName){
this.firstName = fName;
this.lastName = lName;
}
#XmlElement(name = "firstName")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#XmlElement(name="lastName")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public List<Contact> getContactList() {
return contactList;
}
#XmlElement(name = "contactList")
public void setContactList(List<Contact> contactList) {
this.contactList = contactList;
}
}
write another class called Contact as:
public class Contact {
private int id;
private String name;
public Contact(){}
public Contact(int id, String name){
this.id = id;
this.name = name;
}
#XmlElement(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Marshell it with JAXB (create XML) as:
public class Test {
public static void main(String[] args){
Contact c1 = new Contact(1, "first");
Contact c2 = new Contact(2, "second");
MyInfo info = new MyInfo("Shekhar", "Khairnar");
info.getContactList().add(c1);
info.getContactList().add(c2);
try {
JAXBContext jaxbContext = JAXBContext.newInstance(MyInfo.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(info, System.out);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
In above eg. I just print the xml output on console you can write in a file also.
out put will be:
<myInfo>
<firstName>Shekhar</firstName>
<lastName>Khairnar</lastName>
<contactList>
<id>1</id>
<name>first</name>
</contactList>
<contactList>
<id>2</id>
<name>second</name>
</contactList>
You can do the following:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class MyInfo {
private String firstName;
private String lastName;
#XmlElementWrapper
#XmlElement(name="contact")
private List<Contact> contactList;
// getters & setters
}
Things to note:
JAXB is configuration by exception so you only need to annotate where you want the XML representation to differ from the default.
By default JAXB treats public fields and properties as mapped. If you want to treat only fields as mapped you should specify #XmlAccessorType(XmlAccessType.FIELD).
The mapped fields can be private.
#XmlElementWrapper is used to add a grouping element to a collection.
When #XmlElement is used on a collection it applies to each item in the collection.