I'm using JAX RS to create a REST webservice using the usual @Path, @GET, @Produces({"application/json, "application/xml"})
.
I'm returning a POJO as response which is sent as JSON or XML depending upon the type of request. It was working fine untill I added a Many-To-Many relationship with another entity. The relationship is bidirectional.
I'm using JBoss AS 7. I added Jackson's @JsonManagedReference
and @JsonBackReference
but to no avail.
How to get over this?
I deployed my JAX RS like this:-
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd" version="3.0">
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
I didn't extend any Application class or used any JAXRS activator class.
This JBoss's RESTEasy is using Jackson as their JSON provider, even then why it is not recognising @JsonManagedReference
annotations?
Do I have to update the dependencies, if yes then how? And how to fix if the request is of XML, there too it fails in circular reference in JAXB.
Thanks in advance!
To send a request in JSON format, we will send “Content-Type: application/json” key-value in the header of the request. To send a request in XML format, we will send “Content-Type: application/xml” key-value in the header of the request. That’s all for JAX RS @Consumes with both XML and JSON Example.
See also the DataContractsSerializer class. Here is an example custom Jackson JSONSerializer that deals with circular references by serializing the first occurrence and storing a * reference to the first occurrence on all subsequent occurrences.
When returning a "parent" object via a JsonResult a circular reference error is thrown because "child" has a property of class parent. I have tried the ScriptIgnore attribute but I lose the ability to look at the child objects. I will need to display information in a parent child view at some point.
Create the Java classes Produces_XML_JSON_Example.java and Student.java under com.javainterviewpoint folder. The getBothResponse () method is capable of producing both xml and json response, if the client is requesting for an xml response it will produce xml response, if json then it will produce json response.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
MOXy offers the @XmlInverseReference
extension that can be used to support bidirectional relationships in both XML and JSON binding.
JAVA MODEL
Customer
Customer
has a collection of PhoneNumber
objects.
package forum12312395;
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement
public class Customer {
private List<PhoneNumber> phoneNumbers;
@XmlElement(name="phone-number")
public List<PhoneNumber> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
}
PhoneNumber
Each PhoneNumber
object maintains a back pointer to the Customer
object. This property is annotated with @XmlInverseReference
.
package forum12312395;
import javax.xml.bind.annotation.XmlValue;
import org.eclipse.persistence.oxm.annotations.XmlInverseReference;
public class PhoneNumber {
private String value;
private Customer customer;
@XmlValue
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@XmlInverseReference(mappedBy="phoneNumbers")
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
jaxb.properties
To use 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
INPUT
Below are the documents that we will unmarshal in this example
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<phone-number>555-WORK</phone-number>
<phone-number>555-HOME</phone-number>
</customer>
input.json
{
"customer" : {
"phone-number" : ["555-HOME", "555-WORK"]
}
}
DEMO
package forum12312395;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;
import org.eclipse.persistence.oxm.MediaType;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
// JSON
Unmarshaller jsonUnmarshaller = jc.createUnmarshaller();
jsonUnmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
StreamSource json = new StreamSource("src/forum12312395/input.json");
Customer customerFromJSON = (Customer) jsonUnmarshaller.unmarshal(json);
for(PhoneNumber phoneNumber : customerFromJSON.getPhoneNumbers()) {
System.out.println(phoneNumber.getCustomer());
}
// XML
Unmarshaller xmlUnmarshaller = jc.createUnmarshaller();
StreamSource xml = new StreamSource("src/forum12312395/input.xml");
Customer customerFromXML = (Customer) xmlUnmarshaller.unmarshal(xml);
for(PhoneNumber phoneNumber : customerFromXML.getPhoneNumbers()) {
System.out.println(phoneNumber.getCustomer());
}
}
}
OUTPUT
Below is the output from running the demo code. As you can see the customer
property is populated on all of the PhoneNumber
objects.
forum12312395.Customer@3ef38fd1
forum12312395.Customer@3ef38fd1
forum12312395.Customer@320eef20
forum12312395.Customer@320eef20
FOR MORE INFORMATION
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With