Spring REST jackson not marshalling on POST request - json

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

Related

SpringBoot Rest response not deserialiazed with jackson

I am a running a project with SpringBoot. In this project I am calling an external Rest Service. I have modeled the response items into bean.
But when I get the response back the data are not serialised into the beans.
I guess there must be some configuration missing but I cannot find what.
I have added onfiguration spring-boot-starter-test to the configuration of Maven:
The rest client:
#RunWith(SpringRunner.class)
#SpringBootTest
public class RestClientTest {
#Autowired
private RestTemplateBuilder restTemplate;
#Test
public void sayHello() {
System.out.println("Hello");
assert(true);
}
#Test
public void testGetEmployee() {
RestTemplate template = restTemplate.build();;
HttpHeaders headers = new HttpHeaders();
List<MediaType> types = new ArrayList<MediaType>();
types.add(MediaType.APPLICATION_JSON);
types.add(MediaType.APPLICATION_XML);
headers.setAccept(types);
headers.set("Authorization", "Bearer gWRdGO7sUhAXHXBnjlBCtTP");
HttpEntity<Items> entity = new HttpEntity<Items>(headers);
String uri = "https://mytest.com/employees";
//ResponseEntity<String> rec = template.exchange(uri, HttpMethod.GET, entity, String.class);
//System.out.println("Received: " + rec);
ResponseEntity<Items> rec = template.exchange(uri, HttpMethod.GET, entity, Items.class);
System.out.println("Received: " + rec);
}
}
When I inspect the elements of the response it, I get a list, all the items are with null values
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Item implements Serializable {
#JsonProperty
private String id;
#JsonProperty
private String name;
#JsonProperty
private String email;
#JsonProperty
private String phone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Items implements Serializable {
#JsonProperty
private List<Item> items = new ArrayList<Item>();
public List<Item> getItems() {
return items;
}
}
Do you see what I am missing here?
The response is like this:
{
"items": [
{
"item": {
"id": 0,
"name": "string",
"email": "string",
"phone": "string",
Do you see what I am missing here?
Thanks
Gilles
The way you have implemented will try to deserialize data into Items class. But it doesn't have the required properties to deserialize. When you need to get a list of data through rest template exchange, you can get them as follows.
Get data as an array and convert it into arrayList.
Item[] itemArray = template.exchange(uri, HttpMethod.GET, entity, Item[].class).getBody();
List<Item> itemList = Arrays,asList(itemArray);
or
Use ParameterizedTypeReference to get data as a list
ResponseEntity<List<Item>> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {});
List<Item> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {}).getBody(); // access list directly
You might need to add this to your ObjectMapper:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
And on your entity add #JsonRootName("item")

spring boot maps null properties to POJO from JSON post request from angular2

After doing a big deal of research on the topic I decided to ask in here. I am getting all null properties to the POJO/Model which is supposed to get values from the JSON I am posting from the Angular 2 Front end. Here is the rest controller method:
#RequestMapping(value = "/employees/update", method = RequestMethod.POST, consumes = "application/json")
public String allEmployees( #RequestBody Employee emp){
return "";
}
The following is the POJO/Model/Hibernate Entity:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false, updatable = false)
private Long id;
private String firstname;
private String lastname;
private String department;
public Employee(){}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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 getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
The following is the Angular 2 Service method:
updateEmployee(emp:Employee){
let url: string = "http://localhost:8080/api/employees/update";
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post(url, {emp}, {headers: headers, withCredentials: true }).map(res => res.json());
}
and the Employee interface of Angular 2:
export interface Employee{
id: number;
firstname: string;
lastname: string;
department: string;
}
What am I doing wrong? I have searched for similar issues but none I found applies to my case. Thank you!
You need to serialize the javascript object before sending it. Try:
this.http.post(url, JSON.stringify(emp), {headers: headers, withCredentials: true }).map(res => res.json());
Try annotating the method with #ResponseBody
Which would become:
#ResponseBody
#RequestMapping(value = "/employees/update", method = RequestMethod.POST, consumes = "application/json")
public String allEmployees( #RequestBody Employee emp){
return "";
}

Post JSON to Rest Spring 4 service

I am trying to post a complex/nested json to Rest Spring4 using PostMan rest client but objectMapper.readValue returns null.
#RequestMapping(value = "/loginuser", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
Status Login(#RequestBody String userdata) {
try {
ObjectMapper objectMapper = new ObjectMapper();
LoginData theUser = objectMapper.readValue(userdata, LoginData.class);
String userdata contains Json string but objectMapper.readValue returns null.
JSON {"LoginData":{"id":"1", "username":"kashmir1","password":"kashmir2"}}
POJO:
public class LoginData implements Serializable{
#Id
#GeneratedValue
#Column(name = "id")
#JsonProperty("id")
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
and soon for username and password
Please provide inputs
I got answer :
follow below lines instead of directly accessing required node
JsonNode rootNode = objectMapper.readValue(jsonString, JsonNode.class) ;
JsonNode userNode=rootNode.path("LoginData");
LoginData theUser = objectMapper.treeToValue(userNode, LoginData.class);
System.out.println("In Login"+theUser.getUsername());

JAXRS client - Deserialization Issue with Pojo

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.

Jersey application fails to return JSON representation for a simple POJO

I'm trying to use Jersey RS to return JSON for a POJO. This is not a servlet and there is no servlet container. The Jersey is being setup from within Netty (not Jetty). I can get Jersey to return APPLICATION_XML but APPLICATION_JSON on same resource throws an exception saying No Message Body writer for my domain class was found. I have included jersey-json and jackson-jaxrs modules in pom.xml.
Here's how the ResourceConfig is being setup :
Map<String, Object> props = new HashMap<String, Object>();
props.put(PackagesResourceConfig.PROPERTY_PACKAGES, RESOURCES_PACKAGE);
props.put(PROPERTY_BASE_URI, "http://localhost:9000/");
props.put(JSONConfiguration.FEATURE_POJO_MAPPING, true);
ContainerFactory.createContainer(JerseyHandler.class, new PackagesResourceConfig(props));
where JerseyHandler is my Netty Handler class.
The resource is very simple:
#Path("/test")
public class TestResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public TestData get() {
return new TestData();
}
TestData is the simplest model class:
#XmlRootElement
public class TestData {
private String firstName;
private String lastName;
public TestData() {}
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;
}
}
Here's the exception when trying to access "/test" :
SEVERE: A message body writer for Java class com.xyz.models.TestData, and Java type class com.xyz.models.TestData, and MIME media type application/json was not found
I have tried including Context classes from here but still no luck.
I can't imagine returning JSON from Jersey can be that hard. All examples on internet assume you're using Jersey from a servlet container but I am not! thanks for any inputs.
Do you have jackson-core and jackson-mapper librairies ? That is what we need to get JSON serialization working.