JAXRS client - Deserialization Issue with Pojo - json

Helo Everyone. I am new to jersey and Jackson and finding it really difficult to deserialize a JSOn response from my REST service on client side. I am pretty sure that I am still not grasping the Object mapper and JSON provider APIs that well. Any help or guidance is appreciated in advance. Here is my source code.
Source Code
POJO Class
#XmlRootElement(name = "user")
public class User implements Serializable{
private String firstName;
private String lastName;
private String email;
private String userID;
public User() {
}
public User(String firstName, String lastName, String email, String userID) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.userID = userID;
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
}
Client Code
package com.example.service.client;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.jackson.JacksonFeature;
import com.example.service.bean.User;
import com.example.service.client.mapper.MyMessageBodyReader;
import com.example.service.client.mapper.MyObjectMapperProvider;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
public class GetJSONResponse {
public static void main(String[] args) {
// TODO Auto-generated method stub
JacksonJaxbJsonProvider provider1 = new JacksonJaxbJsonProvider();
Client c = ClientBuilder.newClient()register(provider1);//.register(mapper);
WebTarget target = c.target("http://localhost:8080/RestfulWebserviceExample").path("/jaxrs/user/Nishit");
Response resp = target.request(MediaType.APPLICATION_JSON).get();
System.out.println(resp.getStatus());
String user1 = resp.readEntity(String.class);
System.out.println(user1);
User user = target.request(MediaType.APPLICATION_JSON).get(User.class);
System.out.println("User : " + user.getUserID());
}
}
`
The first 2 sysout generates an output as
200
{"user":{"firstName":"Nishit","lastName":"Ladha","email":"ladha#us.ibm.com","userID":"nishiz"}}
But when i tries to directly get the User object from response, I get an error as
Exception in thread "main" javax.ws.rs.client.ResponseProcessingException: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "user" (class com.example.service.bean.User), not marked as ignorable (4 known properties: "lastName", "firstName", "email", "userID"])
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream#10163d6; line: 1, column: 10] (through reference chain: com.example.service.bean.User["user"])
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:806)
at org.glassfish.jersey.client.JerseyInvocation.access$700(JerseyInvocation.java:92)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:700)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:696)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:420)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:316)
at com.example.service.client.GetJSONResponse.main(GetJSONResponse.java:40)
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "user" (class com.example.service.bean.User), not marked as ignorable (4 known properties: "lastName", "firstName", "email", "userID"])
It will be really kind if anyone of you can guide me how to resolve this.
I am not using Maven as I first wanted to try without Maven
I am not sure why my rest service is wrapping the response. Here is the code :
Service Method
#GET
#Path("/{username}")
#Produces(MediaType.APPLICATION_JSON)
public User helloWorld(#PathParam("username") String name){
User user = new User();
user.setFirstName("Nishit");
user.setLastName("Ladha");
user.setUserID("nishiz");
user.setEmail("ladha#us.ibm.com");
return user;
}
Web.xml##
<servlet>
<description>JAX-RS Tools Generated - Do not modify</description>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
com.example.service,
com.fasterxml.jackson.jaxrs.json
</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>

Man, look, you are trying to bind unexistent field User.
If you want to properly parse this json
{"user":{"firstName":"Nishit","lastName":"Ladha","email":"ladha#us.ibm.com","userID":"nishiz"}}
You need to have similar to this class
public class UserWrapper implements Serializable{
private User user;
// Constructors
// Getters, and setters
// HashCode and equals
}
Then this client code will work:
public class GetJSONResponse {
public static void main(String[] args) {
// TODO Auto-generated method stub
JacksonJaxbJsonProvider provider1 = new JacksonJaxbJsonProvider();
Client c = ClientBuilder.newClient()register(provider1);//.register(mapper);
WebTarget target = c.target("http://localhost:8080/RestfulWebserviceExample").path("/jaxrs/user/Nishit");
Response resp = target.request(MediaType.APPLICATION_JSON).get();
System.out.println(resp.getStatus());
String user1 = resp.readEntity(String.class);
System.out.println(user1);
UserWrapper userWrapper = target.request(MediaType.APPLICATION_JSON).get(UserWrapper.class);
}
}
If you have any questions - just ask.Hope your code will work.

Related

What are the steps required to create spring boot project using database first approach? Database used here is MySQL

I am learning spring boot (for REST API). I have read spring boot documentation and other tutorials but all are based on creating database tables using entities (code first approach). One of the tutorials talked about JBoss(installed in from Eclipse marketplace). So I followed the tutorial and I was able to create entities, dao, pojo classes from database tables. But the tutorial doesn't talk about how to perform crud operations now. So I tried to perform some crud operation and I am getting errors.
UserController
package com.example.dbfirst.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.dbfirst.entities.User;
import com.example.dbfirst.service.UserService;
#RestController
public class UserController {
#Autowired
private UserService userService;
#RequestMapping("users/{id}")
public User getUser(#PathVariable("id") int id) {
return this.userService.getUser(id);
}
}
UserService
package com.example.dbfirst.service;
import javax.ejb.EJB;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.dbfirst.dao.UserHome;
import com.example.dbfirst.entities.User;
#Service
public class UserService {
//#Autowired
private UserHome userHome;
public User getUser(int id) {
userHome=new UserHome();
return this.userHome.findById(id);
}
}
User DAO class using JBoss and hibernate.cfg.xml
UserHome
package com.example.dbfirst.dao;
// Generated 25-Mar-2021, 4:50:30 pm by Hibernate Tools 5.2.12.Final
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Repository;
import com.example.dbfirst.entities.User;
#Stateless
public class UserHome {
private static final Log log = LogFactory.getLog(UserHome.class);
#PersistenceContext
private EntityManager entityManager;
public void persist(User transientInstance) {
log.debug("persisting User instance");
try {
entityManager.persist(transientInstance);
log.debug("persist successful");
} catch (RuntimeException re) {
log.error("persist failed", re);
throw re;
}
}
public void remove(User persistentInstance) {
log.debug("removing User instance");
try {
entityManager.remove(persistentInstance);
log.debug("remove successful");
} catch (RuntimeException re) {
log.error("remove failed", re);
throw re;
}
}
public User merge(User detachedInstance) {
log.debug("merging User instance");
try {
User result = entityManager.merge(detachedInstance);
log.debug("merge successful");
return result;
} catch (RuntimeException re) {
log.error("merge failed", re);
throw re;
}
}
public User findById(Integer id) {
log.debug("getting User instance with id: " + id);
try {
User instance = entityManager.find(User.class, id);
log.debug("get successful");
return instance;
} catch (RuntimeException re) {
log.error("get failed", re);
throw re;
}
}
}
UserEntities
package com.example.dbfirst.entities;
// Generated 25-Mar-2021, 4:12:53 pm by Hibernate Tools 5.2.12.Final
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* User generated by hbm2java
*/
#Entity
#Table(name = "user", catalog = "mydb")
public class User implements java.io.Serializable {
private Integer id;
private String email;
private String password;
public User() {
}
public User(String email, String password) {
this.email = email;
this.password = password;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "email", length = 45)
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name = "password", length = 45)
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
}
User Pojo class
package com.example.dbfirst.pojo;
// Generated 25-Mar-2021, 4:09:56 pm by Hibernate Tools 5.2.12.Final
/**
* User generated by hbm2java
*/
public class User implements java.io.Serializable {
private Integer id;
private String email;
private String password;
public User() {
}
public User(String email, String password) {
this.email = email;
this.password = password;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
}
Now When I call "users/id" from POSTMAN, I am getting this error:
"status": 500,
"error": "Internal Server Error",
"message": "Cannot invoke \"javax.persistence.EntityManager.find(java.lang.Class, Object)\" because \"this.entityManager\" is null",
"path": "/users/2"
I might be missing some steps or I might have made some mistake somewhere.
It would be helpful if you can tell me the steps required to create spring boot project using database first approach (upto crud operation). You can also share some articles/link.
I have already looked at many articles to solve this issue. The reason I want database first approach are following:
I want to keep database part separate from spring project coding part (Don't want to mix them at such level)
I want to design database separately , completely independent of project type.
Thank you for your help.
In your case follow these steps:
Create your database table first.
Turn off auto-create and auto-update.
There is lot of unnecessary lines in your code.
Create only Entity class(add dto later)
Directly access repository from controller(remove service layer for now add later )
If have map columns to entity field properly other-wise it will cause errors(Use #Cloumn(name ="name")) for avoiding error and Use #Id for primary key.
You can refer:
Disable auto update in spring data jpa
https://spring.io/guides/gs/accessing-data-jpa/

Spring REST jackson not marshalling on POST request

Im using spring 4 and have added jackson-databind so I can get the request/reponse object marshalled.. It works when I return the object from a GET request, but the POST request object is not being populated.. It is NOT null so it is being instantiated
I have tried it using an HttpEntity for the method param to see if I was getting the JSON object and it was in the body of the entity. I could then manually marshal it..
I'm trying to figure out what is missing or mis-configured to have jackson
This is the method where the object is instantiated but not populated. Im using Spring 4 and the controller is annotated with #RestController which combines #Controller and #ResponseBody
#RequestMapping(value="/create", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> getUser(User user) {
log.debug("got user: " + user.getId());
return new ResponseEntity<>(HttpStatus.OK);
}
Here is the JSON:
{
"id": 12,
"lastName": "Test",
"firstName": "Me"
}
This is the user object:
public class User {
private int id;
private String lastName;
private String firstName;
public User(){}
public User(int id, String lname, String fname) {
this.id = id;
this.lastName = lname;
this.firstName = fname;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
I also have the jackson mapper defined in my context file. Although the docs stated this didn't have to be done. It did work without it
<beans:bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonMessageConverter"/>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</beans:bean>
Try to use #RequestBody annotation in your method call
#RequestMapping(value="/create", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ResponseEntity <?> getUser(#RequestBody final User user){
You are missing an annotation call #RequestBody in your method and if I'm not wrong you'll need to add #ResponseBody too.
#RequestMapping(value="/create", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ResponseEntity<?> getUser(#RequestBody User user) {
log.debug("got user: " + user.getId());
return new ResponseEntity<>(HttpStatus.OK);
}
The responsed provided were correct. I did need to add the #RequestBody to the method..I mis-read the docs.. it is only the #ResponseBody and #Controller that are added using #RestController. With that I do not need to add the #ResponseBody to the return object

Jaxb annotations to deserialize json data using Jackons

I do have a simple json data and my pojo is annotated with jaxb annotations. I wanted to deserialize it WITHOUT using json annotations.
(It's must, please do NOT suggest to use both annotations on pojo).
Jackson confirms (that's what I understood) that it's possible through
http://wiki.fasterxml.com/JacksonJAXBAnnotations
https://github.com/FasterXML/jackson-module-jaxb-annotations
But when I ran the code, it does NOT provide the desired result.
Here is the pojo.
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Simple_root")
#XmlAccessorType(XmlAccessType.FIELD)
public class Simple {
#XmlElement(name = "x")
private String firstName;
#XmlElement(name = "y")
private String lastName;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Below is the test class with two test methods using jackson ObjectMapper.
import org.junit.Assert;
import org.junit.Test;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
public class XmlMapperTest {
#Test
public void jsonDeserialize_using_JaxbAnnotationIntrospector() throws Exception {
ObjectMapper jsonMapper = new ObjectMapper();
jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
jsonMapper.getDeserializationConfig().with(introspector);
jsonMapper.getSerializationConfig().with(introspector);
Simple simple = jsonMapper.readValue("{\"Simple_root\": {\"x\": \"2\", \"y\": \"4\"}}", Simple.class);
Assert.assertNotNull(simple.getFirstName());
Assert.assertNotNull(simple.getLastName());
}
#Test
public void jsonDeserialize_using_JaxbAnnotationModule() throws Exception {
ObjectMapper jsonMapper = new ObjectMapper();
jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JaxbAnnotationModule jaxbModule = new JaxbAnnotationModule();
jsonMapper.registerModule(jaxbModule);
Simple simple = jsonMapper.readValue("{\"Simple_root\": {\"x\": \"2\", \"y\": \"4\"}}", Simple.class);
Assert.assertNotNull(simple.getFirstName());
Assert.assertNotNull(simple.getLastName());
}
}
Any help would be appreciated, as I know I am definitely missing something which I couldn't find out in a day and 2 hours before bedtime.

Consume Json in REST post jersy

I am trying to consume json object in rest service,and convert it to local bean pojo jaxb class and use it for further processing.
Here is my webservice code:
#POST
#Path("login1")
#Consumes(MediaType.APPLICATION_JSON)
public String login1(LoginJSON data)
{
try
{
System.out.println("request received for user"+data.username);
System.out.println("pass: "+data.password);
} catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return "success";
}
Here is pojo class:
#XmlRootElement
public class LoginJSON
{
#XmlElement(required=true)
public String username;
#XmlElement(required=true)
public String password;
public LoginJSON()
{
super();
// TODO Auto-generated constructor stub
}
public LoginJSON(String username, String password)
{
super();
this.username = username;
this.password = password;
}
public String getUsername()
{
return username;
}
#XmlElement
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
#XmlElement
public void setPassword(String password)
{
this.password = password;
}
}
web.xml is :
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.myapp.webservices</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Webservice client is sending a json object with both user and password attribute.Error I am getting is :
INFO: No default constructor found on class
com.myapp.webservices.LoginJSON
java.lang.NoSuchMethodException: com.myapp.webservices.LoginJSON.<init>()
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.getDeclaredConstructor(Unknown Source)
at com.sun.xml.internal.bind.v2.ClassFactory.create0(Unknown Source)
....
How do I resolve this any suggestions?
Remove the constructors used in the class LoginJSON
public LoginJSON()
{
super();
// TODO Auto-generated constructor stub
}
public LoginJSON(String username, String password)
{
super();
this.username = username;
this.password = password;
}
Let the class to use the default constructor, otherwise the json won't be parsed to LoginJSON.
The most simple library for processing JSON in java is org.json,
you don't need a POJO class:
#POST
#Path("login1")
#Consumes(MediaType.APPLICATION_JSON)
public String login1(LoginJSON data) {
JSONObject dataJSON = new JSONObject(data);
String username = dataJSON.get("username").toString();
String password = dataJSON.get("password").toString();
//...
return "success";
}

how to handle Json body in post request in jax-rs

I have a project (homework) about JAX-RS. I'm working with NetBeans, Jersey and Tomcat.
This is my "User" class for main object in the system.
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="user")
public class User {
//#XmlElement
//public int id ;
#XmlElement
public String username;
#XmlElement
public String fullname;
#XmlElement
public String gender;
#XmlElement
public String birthDate;
public User(){
}
public User(String username,String fullname, String gender,String birthDate){
//this.id = id;
this.username = username;
this.fullname = fullname;
this.gender = gender;
this.birthDate = birthDate;
}
}
This is my "JAXBContextResolver" Class
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.api.json.JSONJAXBContext;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
#Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext>{
private JAXBContext context;
private Class[] types = {User.class};
public JAXBContextResolver() throws Exception {
this.context =
new JSONJAXBContext( JSONConfiguration.mapped().build(), types);
}
#Override
public JAXBContext getContext(Class<?> objectType) {
for (Class type : types) {
if (type == objectType) {
return context;
}
}
return null;
}
}
And this is my post method in the "UserService" class
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public List<User> createNewUser(User tUser) {
List<User> list = new ArrayList<User>();
list.add(tUser);
return list;
}
When I am trying a post new user in the localhost with RESTClient (Firefox add-ons) my request body is a json input like that:
{"user":{"username":"blabla","fullname":"blabla","gender":"M","birthDate":"05.01.1978"}}
In the post method (in the UserService class) must the variable "tUser" automatically filled with the coming input ? "tUser" variable shows null elements in it in the debugging mode like that:
If I know wrong could somebody correct me please? Why this values shows null? Must not them shows "blabla" - "blabla" - "M" - "05.01.1878" ? Could you help me please?
I solved this problem; In the JAXBContextResolver class I change the method like that :
public JAXBContextResolver() throws Exception {
this.context =
new JSONJAXBContext( JSONConfiguration.mapped().rootUnwrapping(false).build(), types);
}
The difference with the first one is adding "rootUnwrapping(false)" expression.
#XmlRootElement is not working in your example. Send
{"username":"blabla","fullname":"blabla","gender":"M","birthDate":"05.01.1978"}
instead
EDIT
1)
public List<User> createNewUser(Request tUser)
and class
class Request
{
public User user;
}
2)
public List<User> createNewUser(String tUser)
and convert String to object using google-gson or jackson json processor