406 error while retrieving the details in REST and hibernate - java

I am trying to fetch the details of countries in XML using REST and hibernate. But when hitting the URL below is the error I get. I have set the header accepts in the request correctly to xml.
The resource identified by this request is only capable of generating
responses with characteristics not acceptable according to the request
"accept" headers.
CONTROLLER
#RequestMapping(value = "/getAllCountries", method =
RequestMethod.GET,produces="application/xml",
headers = "Accept=application/xml")
public List<Country> getCountries() throws CustomerNotFoundException{
List<Country> listOfCountries = countryService.getAllCountries();
return listOfCountries;
}
MODEL
#XmlRootElement (name = "COUNTRY")
#XmlAccessorType(XmlAccessType.FIELD)
#Entity
#Table(name="COUNTRY")
public class Country{
#XmlAttribute
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
int id;
#XmlElement
#Column(name="countryName")
String countryName;
#XmlElement
#Column(name="population")
long population;
public Country() {
super();
}
SERVICE
#Transactional
public List<Country> getAllCountries() {
return countryDao.getAllCountries();
}
DAO
public List<Country> getAllCountries() {
Session session = this.sessionFactory.getCurrentSession();
List<Country> countryList = session.createQuery("from Country").list();
return countryList;
}
Can someone please help..

Use spring recommended jackson-dataformat-xml library in pom.xml. It will do automatic XML transformation for you as soon as JAXB library (which is inbuilt in JDK >= 1.6) is present, even without XML annotations. However, you can use #JacksonXml.. annotations to given desired structure to your xml.
To achieve the desired result here, I will create a wrapper class and update my controller as below:
//pom.xml
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
//wrapper class
#JacksonXmlRootElement(localName = "countries")
#Data //lombok
#AllArgsConstructor //lombok
public class Countries {
#JacksonXmlElementWrapper(useWrapping = false)
#JacksonXmlProperty(localName = "country")
private List<Country> countries;
}
//controller
#RequestMapping(value = "/getAllCountries", method = RequestMethod.GET)
public Object getCountries() throws CustomerNotFoundException{
return new Countries(countryService.getAllCountries());
}
NOTE: XML Wrapper class is not required here. Spring will just do fine with the default array transformation using <List><Items>, but its recommended to shape your XML as per desired structure.

Related

Stakover flow error with Jackson applied on JPA Entities to generate JSON

I have a JPA code with OneToMany relationship. A Customer has a list of Item to check out. However, the code continue to generate StackOverflowError.
Once, I had resolved this one by applying #JsonIgnore while fetching the List<Item> from Customer entity. But even that does not seem to work anymore.
In Customer class:
#OneToMany(mappedBy = "customer", orphanRemoval = true)
#JsonIgnore
private List<Item> items;
In Item class:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CUSTOMER_ID", nullable = false)
private Customer customer;
And CustomerRest class:
#Path("customers")
public class CustomerRest {
#Inject
NewSessionBean newSessionBean;
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Customer> getAllCustomers() {
return newSessionBean.getCustomers();
}
}
Method newSessionBean.getCustomers():
public List<Customer> getCustomers(){
TypedQuery<Customer> q= em.createQuery("select c from Customer c", Customer.class);
return q.getResultList();
}
I expect a nicely formatted JSON message but there is no sign of this. All I get is the java.lang.StackOverflowError on the browser and the Server log generates the following:
Generating incomplete JSON|#]
java.lang.StackOverflowError
java.lang.StackOverflowError at org.eclipse.yasson.internal.serializer.DefaultSerializers.findByCondition(DefaultSerializers.java:130)
It looks like you use Yasson project not Jackson. In that case you should use #JsonbTransient annotation. See documentation:
By default, JSONB ignores properties with a non public access. All
public properties - either public fields or non public fields with
public getters are serialized into JSON text.
Excluding properties can be done with a #JsonbTransient annotation.
Class properties annotated with #JsonbTransient annotation are ignored
by JSON Binding engine. The behavior is different depending on where
#JsonbTransient annotation is placed.
See also:
Circular reference issue with JSON-B

Deserialize JSON to polymorphic types Spring boot

I am working on an e-policy project where i need to save different types of policies. For simplicity i am considering only two types "LifeInsurance" and "AutoInsurance". What i want to achieve is if the JSON request to create policy contains "type":"AUTO_INSURANCE" then the request should be mapped to AutoInsurance.class likewise for LifeInsurance but currently in spring boot app the request is getting mapped to parent class Policy eliminating the specific request fields for auto/Life insurance. The domain model i have created is as below.
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#NoArgsConstructor
#Getter
#Setter
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include =
JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({ #Type(value = AutoInsurance.class, name = "AUTO_INSURANCE"),
#Type(value = LifeInsurance.class) })
public class Policy {
#Id
#GeneratedValue
private Long id;
private String policyNumber;
#Enumerated(EnumType.STRING)
private PolicyType policyType;
private String name;
}
My AutoInsurance class is below.
#Entity
#NoArgsConstructor
#Getter
#Setter
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonTypeName(value = "AUTO_INSURANCE")
public class AutoInsurance extends Policy {
#Id
#GeneratedValue
private Long id;
private String vehicleNumber;
private String model;
private String vehicleType;
private String vehicleName;
}
Below is LifeInsurance type child class
#Entity
#NoArgsConstructor
#Getter
#Setter
#JsonTypeName(value = "LIFE_INSURANCE")
public class LifeInsurance extends Policy {
#OneToMany(mappedBy = "policy")
private List<Dependents> dependents;
private String medicalIssues;
private String medication;
private String treatments;
}
To save the policy details, I am sending JSON request from UI with a "type" property indicating the type of insurance in the request.
When i run the below test method, JSON request gets mapped to the correct child class as required.
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
ObjectMapper map = new ObjectMapper();
String s = "{\"id\": 1,\"policyNumber\": \"Aut-123\",\"type\": \"AUTO_INSURANCE\",\"policyType\": \"AUTO_INSURANCE\",\"name\": null,\"address\": null,\"contact\": null,\"agentNumber\": null,\"agentName\": null,\"issuedOn\": null,\"startDate\": null,\"endDate\": null,\"vehicleNumber\": \"HR\",\"model\": null,\"vehicleType\": \"SUV\",\"vehicleName\": null}";
Policy p = map.readValue(s, Policy.class);
System.out.println(p.getClass());
//SpringApplication.run(EPolicyApplication.class, args);
}
But when i run the same in Spring boot in a RESTController postmapping, I am getting a PArent class object instead of the child class object.
#RestController
#RequestMapping("/policy")
public class PolicyController {
#PostMapping
public void savePolicy(Policy policy) {
System.out.println(policy.getClass());
}
}
I can get the JSON as string, autowire objectmapper and parse manually but i want to understand if its a known issue and if anyone else has faced the same with Spring boot. I have searched for solutions on this but i got was solution to deserializing to polymorphic classes but nothing related to issue with Spring boot.
In your method you haven't annotated the Policy method argument with #RequestBody. Which leads to Spring creating just an instance of Policy instead of using Jackson to convert the request body.
#PostMapping
public void savePolicy(#RequestBody Policy policy) {
System.out.println(policy.getClass());
}
Adding the #RequestBody will make that Spring uses Jackson to deserialize the request body and with that your annotations/configuration will be effective.

How to get json data only from parent class in hibernate one to many relationship in spring framework

I am using spring framework and hibernate as an ORM tool.
My parent class is like:
#Entity
public class Category {
#Id
#GeneratedValue
#NotNull
private int cid;
private String cname;
#OneToMany(cascade = CascadeType.ALL)
#LazyCollection(LazyCollectionOption.FALSE)
#JoinColumn(name = "cid")
List<Ad> ads;
//getter and setter, constructor
}
And my child class is like:
#Entity
public class Ad {
private int adid;
private String adName;
//getter and setter, constructor
}
My category controller is :
#Controller
public class CategoryController {
#Autowired
SessionFactory sessionFactory;
Session session;
#Transactional
#RequestMapping(value = "categories",method = RequestMethod.GET)
#ResponseBody
public List<Category> getAllCategory()throws SQLException{
session=sessionFactory.getCurrentSession();
return session.createCriteria(Category.class).list();
}
}
When i hit url localhost:8080/categories .I get json data like:
{"cid":"1",cname":"category","ads":[{"adid":"1","adName":"ad"}]}
Here I am getting datas of both parent and the related child table.But how can I get only datas of parent table.Here in this
example, I need data like:
{"cid":"1",cname":"category"}
How can I do this
I saw a nice article which describes exactly your problem.
Json Exclude Property
By configuring Entity using #JsonIgnore and #JsonProperty annotations you can achieve this.
You can try as below
Infinite Recursion with Jackson JSON and Hibernate JPA issue
Basically have to apply exclusion where you need to break the link

Resolve JPA association while deserializing JAX-RS JSON Object

I have some problems combining JAX-RS (in JBoss Wildfly container) with JSON payload and with JPA assiciations. Follwoing scenario:
There are two JPA entities
#Entity
class Organization {
#Id
private long id;
private String name;
}
#Entity
class Empolyee {
#Id
private long id;
#Id
private String name;
#ManyToOne(fetch = FetchType.EAGER)
#JsonProperty("organization_id")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
#JsonIdentityReference(alwaysAsId = true)
private Organization organization;
}
Next I have a JAX-RS service to create a new Employee with the following signature:
#POST
#Consumes({ "application/json" })
public Response create(final Employee employee) {
}
The JSON for a new Employee sent by the client looks like:
{
"name" : "Sam Sample",
"organization_id" : 2
}
My problem is that this JSON (obviously) cannot be deserialized into an instance of "Employee" since the mapping of the "organization_id" to the corresponding JPA Entity fails.
How can I configure JAX-RS (or the Jackson JSON mapper) to interpret the "orgainization_id" as the id of a JPA entity?
With Jackson you could define a custom deserializer (see this and this) that fetches the Organization entity based on the value of organization_id.
Edit:
Check this example for how to configure JAX-RS using Jackson with a custom deserializer programmatically (as opposed to via annotations):
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
private ObjectMapper objectMapper;
public JacksonContextResolver() throws Exception {
this.objectMapper = new ObjectMapper().configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
SimpleModule myModule = new SimpleModule("MyModule", new Version(1, 0, 0, null));
myModule.addDeserializer(MyType.class, new MyTypeDeserializer());
objectMapper.registerModule(myModule);
}
public ObjectMapper getContext(Class<?> objectType) {
return objectMapper;
}
}

Jersey ClientResponse Get List of Composite Entities

I am trying to get a Result of a List, basically a list of entities using Jersey RESTful API (Server and Client)
UserRESTClient client = new UserRESTClient();
ClientResponse response = client.getUsersByType(ClientResponse.class, String.valueOf(userType));
List<User> participants = response.getEntity(new GenericType<List<User>>() {
});
However, the above code does not work if Entity User has a Composite Object, if for instance,
public class User {
private UserId userId;
}
public class UserId {
private int id;
private int categoryId;
}
In this case, the JSON is deserialized by Jersey and returned null for the field type UserId inside Class User. I inspected the JSON returned and everything seems good at the RESTful Server end, but the nested JSON response is not clearly processed at the Client.
Any help would be greatly appreciated. I am not sure if it because of the Jackson preprocessor.
Following is the actual Code Snippet. It involves two classes Participant and ParticipantPK (primary for each Participant).
#Entity
#Table(name = "conference_participant")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Participant.findAll", query = "SELECT p FROM Participant p"),
public class Participant implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected ParticipantPK participantPK;
}
#Embeddable
public class ParticipantPK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "conference_id")
private int conferenceId;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 150)
#Column(name = "participant_sip_uri")
private String participantSipUri;
public ParticipantPK() {
}
public ParticipantPK(int conferenceId, String participantSipUri) {
this.conferenceId = conferenceId;
this.participantSipUri = participantSipUri;
}
And the Code for retrieving ClientResponse,
List<Participant> participants = response.getEntity(new GenericType<List<Participant>>() {
});
However, the ParticipantPK (Composite PK) is null.
You only pasted a code snippet so I don't know if this part is excluded, but in my code I didn't have setters for the fields. I had getters, but no setters.
Without the setters, my composite objects themselves were non-null, but the members of those objects were themselves null.
I tried to reproduce it, but using the same data structures worked for me. What version of Jersey are you using? Is User class annotated with #XmlRootElement or are you using the POJO mapping feature?

Categories