REST Jersey Client - unable to parse JSON into POJO class - java

I am trying to build a rest client using jersey 2.13.
The rest endpoint is in : https://gist.githubusercontent.com/richersoon/ff4dd5c5abe414c5ec4c/raw/4ce49c32e57bf071d052f7efa76f332d60308035/user.json
But when I tried to run the application I got:
Exception in thread "main" org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=text/plain, type=class com.napier.entity.User, genericType=class com.napier.entity.User.
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:173)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:134)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:988)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:833)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:768)
at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:96)
at org.glassfish.jersey.client.ScopedJaxrsResponse.access$001(ScopedJaxrsResponse.java:56)
at org.glassfish.jersey.client.ScopedJaxrsResponse$1.call(ScopedJaxrsResponse.java:77)
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:397)
at org.glassfish.jersey.client.ScopedJaxrsResponse.readEntity(ScopedJaxrsResponse.java:74)
at com.napier.service.rest.UsersClient.main(UsersClient.java:20)
Here's the code:
public class UsersClient {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(
UriBuilder.fromUri(
"https://gist.githubusercontent.com/richersoon/ff4dd5c5abe414c5ec4c/raw/4ce49c32e57bf071d052f7efa76f332d60308035/user.json"));
Response response = target.request().accept(MediaType.APPLICATION_JSON).get(Response.class);
User user = response.readEntity(User.class);
System.out.println(user);
}
}
Here's the POJO:
#XmlRootElement
public class User {
private String firstname;
private String lastname;
private String photourl;
... setters and getters...
}
Here's the POM:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.13</version>
</dependency>
Please guide me because I am totally new to webservices.

Your client is accepting results of media type "application/json", but your REST webservice returns "text/plain". Check this post to see a possible solution: MessageBodyReader not found for media type=application/octet-stream

Seems you are trying to access the wring uri, which is plain text.
I was able to get it to work with this uri, which is the actual .json file
"https://gist.github.com/richersoon/ff4dd5c5abe414c5ec4c#file-user-json"

Related

Spring boot RestTemplate post giving 400 error

I've written a simple webService in Java 8, on Eclipse Photon, using RestTemplate to post (using postForObject) an object (called patentListWrapper) that wraps a List of objects (called PatentDetails ). I post from a Java client (called MainWsClient ) , then set a value in patentDetails on the server side and read the patentListWrapper object back at the client. It works fine when the server side (program SpringWebServiceHello) uses old Spring MVC 4 technology with only 1 jar file (Spring-web.5.07.RELEASE.jar) following this - serverSideExample ie a web.xml and rest-servlet.xml files controlling the access point. I then wrote another server side program (PndGuidRequestWs) using SpringBoot 2.03 with Spring 5.07 jars, and Maven ,with an identicle #RequestMapping method but no web.xml file and the access point defined in the application.properties file:
server.port=8082
server.servlet.path=/
#spring.mvc.servlet.path=/
#server.servlet.contextPath=/
When I call this new server program using this client - ARC it also works fine
but when I call it using the same java client and exactly the same request (accept for a different url obviously). I get a 400 error:
2018-12-18 16:56:53,861 [main] INFO - Running MainWsClient with name = DS fileType = post3
2018-12-18 16:56:54,101 [main] DEBUG - Created POST request for "http://localhost:8082/guidRequest/xmlList"
2018-12-18 16:56:54,145 [main] DEBUG - Setting request Accept header to [application/xml, text/xml, application/json, application/*+xml, application/*+json]
2018-12-18 16:56:54,152 [main] DEBUG - Writing [com.springservice.client.PatentListWrapper#4ba2ca36] using [org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter#3444d69d]
2018-12-18 16:56:54,384 [main] DEBUG - POST request for "http://localhost:8082/guidRequest/xmlList" resulted in 400 (null); invoking error handler
2018-12-18 16:56:54,387 [main] ERROR - DS1B org.springframework.web.client.HttpClientErrorException: 400 null
The non working ,PndGuidRequestWs, server side has:
#RestController
public class PndController {
#RequestMapping(value = "/guidRequest/xmlList", method = RequestMethod.POST, produces = { "application/xml" } )
public PatentListWrapper guidSearchList(#RequestBody PatentListWrapper patentListWrapper) {
for (PatentDetails pd : patentListWrapper.getPatentList())
{
pd.setGuid("guidSetOnServer3");
}
return patentListWrapper;
}
}
The working (SpringWebServiceHello) server side is identicle except for :
value = "/service/greeting/xml/post2"
The Java client has:
public void runCode(String name , String fileType)
{
String url;
if (fileType.equalsIgnoreCase("post2")) {
url = "http://localhost:8080/SpringWebServiceHello/service/greeting/xml/post2";
// This method is identicle to postToPndGuidRequestWs() but this method works fine.
postToSpringWebServiceHello(url);
}else if (fileType.equalsIgnoreCase("post3")) {
url = "http://localhost:8082/guidRequest/xmlList";
// This method gives 404 error
postToPndGuidRequestWs(url);
}
}
private void postToPndGuidRequestWs(String url)
{
PatentListWrapper patentListWrapper = new PatentListWrapper();
PatentDetails pd = new PatentDetails("CN","108552082","A","00000000",12345,"guidIn");
List<PatentDetails> patentList = new ArrayList<PatentDetails>();
patentList.add(pd);
patentListWrapper.setPatentList(patentList);
RestTemplate restTemplate = new RestTemplate();
/* HttpHeaders headers = new HttpHeaders();
headers.add("header_name", "header_value");
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<PatentListWrapper> request = new HttpEntity<PatentListWrapper>(patentListWrapper, headers); */
/*List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
Jaxb2RootElementHttpMessageConverter jaxbMessageConverter = new Jaxb2RootElementHttpMessageConverter();
List<MediaType> mediaTypes = new ArrayList<MediaType>();
mediaTypes.add(MediaType.APPLICATION_XML);
jaxbMessageConverter.setSupportedMediaTypes(mediaTypes);
messageConverters.add(jaxbMessageConverter);
restTemplate.setMessageConverters(messageConverters);*/
/* headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_XML));
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);*/
try {
patentListWrapper = restTemplate.postForObject(
url,
patentListWrapper,
PatentListWrapper.class);
logger.debug("DS1A employee obj returned. guid = " + patentListWrapper.getPatentList().get(0).getGuid());
}catch(Exception e) {
logger.error("DS1B " + e);
}
}
}
ie fileType="post2" calls SpringWebServiceHello, fileType="post3" calls PndGuidRequestWs. As you can see i've tried several commented out solutions but nothing works. Since the only real difference between the 2 server side programs is that none working one uses Spring boot and the working one doesn't the problem must be in the SpringBoot setup ie directory structure, application.properties or pom.xml. My pom.xml has:
<?xml version="1.0" encoding="UTF-8"?>
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
<groupId>com.clarivate</groupId>
<artifactId>pndguidrequestws</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>pndGuidRequestWs</name>
<description>Guid request webService</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<start-class>com.clarivate.pndguidrequestws.PndGuidRequestWsApplication</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.1.0</version>
<!-- <scope>provided</scope> --> <!-- DS insert for unix -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Implementing XML Representation for Spring Boot Services -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<!-- httpcomponents jars are Required by PndGuidGenerator -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<build>
<finalName>PndGuidRequestWs</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
</project>
The PatentListWrapper class is:
package com.clarivate.pndguidrequestws.model;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class PatentListWrapper {
private List<PatentDetails> patentList;
public PatentListWrapper() {}
public List<PatentDetails> getPatentList() {
return patentList;
}
public void setPatentList(List<PatentDetails> patentList) {
this.patentList = patentList;
}
}
Any suggestions most welcome.
EDIT:
To simplify the object I created PatentListWrapper2 with just 1 string member:
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class PatentListWrapper2 {
private String name;
public PatentListWrapper2() {}
public PatentListWrapper2(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I can again successfully send this xml using the ARC client:
<patentListWrapper2>
<name>DSDS</name>
</patentListWrapper2>
with contentType="application/xml"
but when I try to send patentListWrapper2 from java I get an unmarshalling error:
2018-12-20 09:17:13,931 [main] INFO - Running MainWsClient with name = DS fileType = post4
2018-12-20 09:17:14,166 [main] DEBUG - Created POST request for "http://localhost:8082/guidRequest/xmlList2"
2018-12-20 09:17:14,200 [main] DEBUG - Setting request Accept header to [application/xml, text/xml, application/json, application/*+xml, application/*+json]
2018-12-20 09:17:14,206 [main] DEBUG - Writing [com.springservice.client.PatentListWrapper2#517cd4b] using [org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter#6cc7b4de]
2018-12-20 09:17:14,246 [main] DEBUG - POST request for "http://localhost:8082/guidRequest/xmlList2" resulted in 200 (null)
2018-12-20 09:17:14,248 [main] DEBUG - Reading [com.springservice.client.PatentListWrapper2] as "application/xml;charset=UTF-8" using [org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter#6cc7b4de]
2018-12-20 09:17:14,255 [main] ERROR - DS2B org.springframework.web.client.RestClientException: Error while extracting response for type [class com.springservice.client.PatentListWrapper2] and content type [application/xml;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: Could not unmarshal to [class com.springservice.client.PatentListWrapper2]: unexpected element (uri:"", local:"PatentListWrapper2"). Expected elements are <{}patentListWrapper2>; nested exception is javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"PatentListWrapper2"). Expected elements are <{}patentListWrapper2>
EDIT2 I ran pndGuidRequestWs on Eclipse Tomcat , instead of - Run As -> Spring Boot App. The server log is below:
2018-12-20 11:15:45.655 WARN 236 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.clarivate.pndguidrequestws.model.PatentDetails` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('CN'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.clarivate.pndguidrequestws.model.PatentDetails` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('CN') at [Source: (PushbackInputStream); line: 1, column: 98] (through reference chain: com.clarivate.pndguidrequestws.model.PatentListWrapper["patentList"]->java.util.ArrayList[0])
Can you test with :
try {
HttpHeaders headers = new HttpHeaders();
//headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
//headers.setContentType((MediaType.APPLICATION_JSON));
// I comment the code abouve because you did not specify a consumes whitch defines the media types that the methods of
//a resource class or MessageBodyReader can accept. If not specified, a container will assume that any media type is acceptable.
HttpEntity<PatentListWrapper> request = new HttpEntity<>(patentListWrapper, headers);
PatentListWrapper patentListWrapperResult = = restTemplate.exchange(url, HttpMethod.POST, request,PatentListWrapper.class);
logger.debug("DS1A employee obj returned. guid = " + patentListWrapper.getPatentList().get(0).getGuid());
}catch(Exception e) {
logger.error("DS1B " + e);
}
PatentListWrapper is a complex object, not a piece of xml , so the answer is to remove all references to xml ie
Remove #XmlRootElement(name="PatentListWrapper") from PatentListWrapper.
Add jackson-*.jar(s) into the classpath to do the message converting
Change the server side #RequestMapping from :
#RequestMapping(value = "/xmlList", method = RequestMethod.POST , consumes = { "application/xml" }, produces = { "application/xml" })
to
#RequestMapping(value = "/xmlList", method = RequestMethod.POST )
This means that the ARC client now returns JSON (as it's the default return type), even when I send xml, but that's not important as it's just a test tool.
So, when posting objects with RestTemplate in Spring 2, no contentType settings or additional messageConverters are required on the client side , just:
RestTemplate restTemplate = new RestTemplate();
MyObject myObjectReturn = restTemplate.postForObject(url,myObject,MyObject.class);
and on the server side:
#RestController
#RequestMapping(value = "/endPoint", method = RequestMethod.POST)
public MyObject anyMethodName(#RequestBody MyObject myObject) {
//Do stuff to myObject
return myObject;
}

Jersey Client Fails To Deserialize to Object

So I am trying to implement a simple Jersey Client that hits a public API to get movie times etc..
https://api.eventcinemas.co.nz/Api/Movies/GetMovies
I have gone through tutorials on how to do this and have implemented two methods that deserialzse the JSON response into:
A String
An Object (POJOs)
The issue is this: the JSON to String method is working correctly, printing the String to console gives me the expected result. However when trying to deserialize to my Java Objects I am always getting null.
I have tried a few simple things such as different dependency versions, different API calls etc but no luck. To save time I have used an online converter to take the JSON response and populate the necessary POJOs for deserialization, I have taken this to be correct.
Would someone be kind enough to point me in the right direction on why I am always getting null, I feel like its something small or silly that I have missed. Thanks in advance!
So starting with my pom.xml dependencies...
pom.xml
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
My Client is as follows:
MoviesClient:
package nz.co.brownbridge.application;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
public class MoviesClient {
protected MoviesResponse getMovieDetails() {
/*JSON to POJO*/
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("https://api.eventcinemas.co.nz/Api/Movies/GetMovies");
MoviesResponse response = webTarget.request().accept(MediaType.APPLICATION_JSON_TYPE).get(MoviesResponse.class);
return response;
}
protected String getMovieDetailsString() {
/*JSON to String*/
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("https://api.eventcinemas.co.nz/Api/Movies/GetMovies");
String response = webTarget.request().accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
return response;
}
}
and finally the main() class:
Application Class:
package nz.co.brownbridge.application;
public class Application {
public static void main(String[] args) throws InterruptedException {
MoviesClient moviesClient = new MoviesClient();
String stringResponse = moviesClient.getMovieDetailsString();
MoviesResponse pojoResponse = moviesClient.getMovieDetails();
System.out.println("Printing String Response...");
System.out.println();
System.out.println(stringResponse);
System.out.println();
System.out.println();
System.out.println("Printing POJO Response...");
System.out.println();
System.out.println(pojoResponse);
}
}
Would output the following:
Printing String Response...
//super long but correct string response goes here
Printing POJO Response...
ClassPojo [Data = null, Success = null]

Jersey test set max http header size

Does any body know how to set the max header size while using Grizzly2 and Jersey Test .
I'm currently using the following dependencies :
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.23.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.23.2</version>
</dependency>
and i have a simple Test class extending Jersey test like this :
public class JerseyTestInitializer extends JerseyTest {
#Override
public Application configure() {
// Configuration stuff
}
#Test
public void test() {
WebTarget webTarget = target(URL);
Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON)
.header("test",SOME VALUE THAT IS MORE THAN 8K Characters);
SomeEntity someEntity = new SomeEntity();
Response response = invocationBuilder.post(Entity.entity(someEntity, MediaType.APPLICATION_JSON));
}
}
While performing the post i'm currently getting a HTTP status 400 with no other information about the bad request. If I use a header value with less than 8K characters , than it's working for me.
Please advice.
Thanks
Mohit
Please check on this question about URI size (this is also a header).
Jersey/Grizzly POST fails for large URI

How to enable multiple Content-Types for a response in spring-mvc?

I have a simple #RestController and would like to response with both JSON or XML depending on the http header content-type.
Problem: I'm always only getting XML response, never JSON. Of course I'm using Content-Type: application/json as http header.
What might be missing in the following configuration?
#RestController
public void MyServlet {
#RequestMapping(value = "test", method = RequestMethod.GET,
produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public MyResponse test() {
return new MyResponse();
}
}
#XmlRootElement
public class MyResponse {
private String test = "somevalue";
//getter, setter
}
pom.xml:
<!-- as advised in: https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
</dependency>
Interestingly: if I switch the produces statement:
produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}),
then I'm always getting JSON out and never XML!
So the question is: why does the first MediaType always have precedence, and the http header is never taken into account?
In your case, you should use Accept header not Content-Type.
On a request, the Accept header is used to request the Content-Type of the response from the server.
On a request the Content-Type is used to define the structure of the request body.

Jersy 2 Client + JAXB (MessageBodyWriter not found)

I'm trying to use Jersy 2 in client mode to post XML to a server but i always get an exception.
I have got only one dependency in my pom file:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.18</version>
</dependency>
My Java code:
public static void main(String... args) {
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080");
Entity<SimpleClass> entity = Entity.entity(new SimpleClass(), MediaType.APPLICATION_XML_TYPE);
target.request(MediaType.TEXT_XML_TYPE).post(entity);
}
#XmlRootElement(name = "test")
#XmlAccessorType(XmlAccessType.NONE)
public class SimpleClass {
#XmlElement(name = "hello")
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
Exception:
Exception in thread "main" org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/xml, type=class jersey.SimpleClass, genericType=class jersey.SimpleClass.
What I'm doing wrong?
Thank's to peeskillet!
Since Jersey 2.16 you have to add JAX-B support:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-jaxb</artifactId>
<version>2.18</version>
</dependency>
See:
Jersey version issue: MessageBodyReader not found for media type=application/xml

Categories

Resources