Restful web service 415 - java

#RestController
#RequestMapping(value="/uri",produces = "application/json",
consumes="application/json")
public class VisitorService {
VisitorDAO vis=new VisitorDAO();
#RequestMapping(value = "/ex" ,method = RequestMethod.POST)
public String showDetails(#RequestBody VisitorDTO visitor){
vis.addVisitorEntry(visitor);
return "success"+visitor;
}}
Above is my rest service.
whenever I hit a post using the URL with the below JSON,
{
"phoneNumber" : 188892,
"name" : "kikiki" ,
"email" : "loa#gmail.com",
"purpose" : "Business",
"hostName" : "sjs S Murthy"
}
im getting HTTP Status 415 – Unsupported Media Type.
why would that be?

Check that you have set the #EnableWebMvc annotation in a #Configuration class.
Also, try adding the following dependencies to your pom.xml (if not using Maven, just add them to your classpath however you prefer).
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-version}</version> // 2.4.3
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-version}</version> // 2.4.3
</dependency>
Spring uses Jackson and Jackson-databind to parse the request's JSON body into a Java Object.

Related

How to decode JSon response with custom Feign client?

In my application, I have to know, from a list a server addresses, which are up. The solution I found is to call health endpoint from Spring-Boot Actuator, for each of them. The JSon reponse is:
{
"status": "UP"
}
In other parts of the application, I use Feign clients from Spring-Cloud defined with the #FeignClient annotation, which works perfectly:
#FeignClient(
name = "tokenProxy",
url = "${host}:${port}"
)
Unfortunately this kind of configuration doesn't allow to re-use the same client to call the same endpoint on different addresses. So I have to define my own custom client (If there is another solution, do not hesitate to tell me! ):
#GetMapping(
value = "/servers"
)
public Server discover() {
MyClient myClient = Feign.builder()
.target(
Target.EmptyTarget.create(
MyClient.class
)
);
return myClient.internalPing(URI.create("http://localhost:8090"));
}
interface MyClient {
#RequestLine("GET /actuator/health")
Server internalPing(URI baseUrl);
}
class Server {
private final String status;
#JsonCreator
public Server(#JsonProperty("status") String status) {
this.status = status;
}
public String getStatus() {
return status;
}
}
When I call the endpoint /servers, I get the following error, indicating that my custom Feign client isn't confgured with the appropriate decoder:
feign.codec.DecodeException: class com.xxx.web.Server is not a type supported by this decoder.
at feign.codec.StringDecoder.decode(StringDecoder.java:34) ~[feign-core-10.10.1.jar:na]
at feign.codec.Decoder$Default.decode(Decoder.java:92) ~[feign-core-10.10.1.jar:na]
at feign.AsyncResponseHandler.decode(AsyncResponseHandler.java:115) ~[feign-core-10.10.1.jar:na]
at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:87) ~[feign-core-10.10.1.jar:na]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138) ~[feign-core-10.10.1.jar:na]
I guess i should use JacksonDecoder, but I cannot find it in my dependencies from Spring-Cloud Hoxton.SR5:
<dependencies>
...
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
...
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
Could someone help me, either with a better solution for my need or a explanation on how to properly configure custom Feign clients?
Thanks in advance
In fact, the library which includes Jackson decoder and encoder was not loaded by default when using spring-cloud dependencies. To fix the issue I simply had to add the following to my pom.xml file:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
Another way could be annotating the class with #Import(FeignClientsConfiguration.class) which is the default configuration provided by Spring Cloud Netflix.
Then it becomes easy to inject both Encoder and Decoder when creating the Feign client:
#Import(FeignClientsConfiguration.class)
#Configuration
public class MyConfiguration {
(...)
Myclient myClient (Decoder feignDecoder, Encoder feignEncoder) {
return Feign.builder()
.decoder( feignDecoder )
.encoder( feignEncoder )
.target(
Target.EmptyTarget.create(
MyClient.class
)
);
}
There are two different defined encoders in the configuration class (pageable or not), so pay attention to clearly identify which you want, either by its name or a qualifier.

jackson-dataformat-xml breaks defualt config

I have a RestController which receives a XML POST Request.
#PostMapping(value = "/check", consumes = { MediaType.TEXT_XML_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE }, produces = MediaType.TEXT_XML_VALUE)
public ResponseEntity<CheckResponse> checkRequest(
#RequestBody(required = true) CheckRequest checkRequest) {
//Code...
}
The body looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<ns2:CheckRequest>
<UserIp>1.1.1.1</UserIp>
<AgencyManagement>
<Customer>123456</Customer>
<Office>abcde</Office>
</AgencyManagement>
</ns2:CheckRequest>
I'm using the default converter configuration and the CheckRequest Object is filled with data.
Now I like to save the request to the Database using the com.fasterxml.jackson.databind.ObjectMapper. Using the default config its writing JSON instead of XML. So I added the following dependency to get the XmlMapper.class :
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
So if I start my application again and send the same request all the properties are empty when it arrives to the Controller.
Why is this the case and how can I solve it?

Can't retrieve JSONObject from my rest api

So I recently moved from Jersey 1.x to 2.x and after a long list of problems finaly got it working. But whenever I try to reach a resource which returns a JSONObject I get problems. First of, here is my example method:
#GET
#Path("/foobar")
#Produces(MediaType.APPLICATION_JSON)
public JSONObject print2() throws JSONException {
JSONObject jsonObject = new JSONObject();
jsonObject.put("hi", 22);
return jsonObject;
}
Now if I use Jettison 1.3.8 for my JSONObject, I get the following if I try to reach this resource:
{"escapeForwardSlashAlways":true}
Not sure whats going on there. Then I tried some older versions of Jettison and also the org.json but these gives me this issue instead:
No serializer found for class org.json.JSONObject and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )
Not sure why I get these problems when this kind of method worked fine for me on Jersey 1.x.
Assuming you are using Servlet 3.0 and above, the following example might help you to setup your environment to work with JSON data:
Dependency: if you are using Maven you need the following dependencies:
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.23.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.23.2</version>
</dependency>
If you are not using Maven, you need to add the correponding jars into your classpath.
Define POJOs to contain the data you want to serialize to JSON, for example,
public class User {
private String username;
private String email;
// getters + setters
}
Modify your resource method accordingly:
#GET
#Path("/foobar")
#Produces(MediaType.APPLICATION_JSON)
public User print2() {
User jsonObject = new User();
jsonObject.setUsername("Me");
jsonObject.setEmail("my#email.com");
return jsonObject;
}
Package and deploy, and the output should be:
{
"username": "Me",
"email": "my#email.com"
}
Note: This example is deployed and works on Tomcat 8.5.5.
I was struggling with the same issue, and eventually Jersey's bookmark exmple helped.
The problem is that your Jersey has no serializer for JSONObject and it tries to use BeanSerializer instead. Jettison JSONObject has only one public getter (isEscapeForwardSlashAlways) and org.json.JSONObject has no getters at all so BeanSerializer cannot be applied.
The solution is for (jettison json object):
Add dependency jersey-media-json-jettison:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jettison</artifactId>
<version>2.26</version>
</dependency>
Register the jettison feature declaratively in your web.xml
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.jettison.JettisonFeature</param-value>
<init-param>
Or programmatically in your application:
#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
registerClasses(UsersResource.class);
register(new JettisonFeature());
}
}
web.xml:
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.glassfish.jersey.examples.bookmark.MyApplication</param-value>
</init-param>
Perhaps org.json.JSONObject has such serializer feature for Jersey too, I don't know...
Another option is to allow the Response to convert your object to JSON. This gives the added benefit of adding the HTTP code as well. So you can return a 400, 404, 500 etc. and still send back a JSON response that can be acted upon by your JS. You should be able to drop your JSONObject in there since it's basically just extended Map - or any object for that matter.
#GET
#Path("/foobar")
#Produces(MediaType.APPLICATION_JSON)
public Response print2() {
User jsonObject = new User();
jsonObject.setUsername("Me");
jsonObject.setEmail("my#email.com");
return Response.status(Response.Status.OK).entity(jsonObject).build());
}

JAXBException occurred : unexpected element while calling Rest Service from Postman client

I have a rest service written using Spring and CXF. The method is shown below.
#POST
#Path("/detail")
public StudentResponse getStudentDetails(Student student);
The Student Class.
#XmlRootElement(name="Student")
public class Student implements Serializable{
...
I am able to call the service using a cxf client
WebClient client = WebClient.create("http://localhost:8180/oauthserver/service/student/detail");
client.type("application/json").accept("application/json");
Response response =client.post(s);
StudentResponse sr = response.readEntity(StudentResponse.class);
The data i am posting(Used jackson to generate the json entry)
{
"name" : "input",
"id" : 1,
"marks" : 20.2
}
But while calling the service from PostMan for SoapUI i am getting the below error.
JAXBException occurred : unexpected element (uri:"", local:"name").
Expected elements are <{}Student>.
unexpected element (uri:"", local:"name"). Expected elements are <{}Student>.
I am calling as POST method and context type RAW.I have set the header values to this:
Content-Type : application/json
Accept : application/json
But still its not working. Any pointers?
Just posting this for any one facing the same issue.
I had to add the jackson provider to the service listing
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
then needed to add the maven dependency (The newer version will have a different package dependency)
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
This page had the solution...
http://cxf.apache.org/docs/jax-rs-data-bindings.html

Post data Spring web services Restful

I am trying to save data on my database with a web service POST wich serializes a HTML form to save a object. The rest client firefox says this:
"The server refused this request because the requested entity is in a format not supported by the requested resource for the requested method"
The eclipse console shows the message:
org.jasig.cas.client.util.CommonUtils - safeGetParameter called on a POST HttpServletRequest for LogoutRequest. Cannot complete check safely. Reverting to standard behavior for this Parameter
I understand that the object that i want to save is not valid, but I don't see what the problem is.
#RequestMapping(value="/solicitudCita", method = RequestMethod.POST)
public #ResponseBody String putSolicitud(#ModelAttribute("Solicitud") Solicitud solicitud) throws Exception{
System.out.println(solicitud.toString());
solicitudCitaAppMService.createOrUpdate(solicitud);
String solicitudAdded = "Solicitud de cita -> {" + solicitud.toString() + "} añadida";
System.out.println(solicitud);
return solicitudAdded;
}
Help me please
Thanks
If you want to call this controller in a RESTful manner, you have to annotate the solicitud parameter as #RequestBody. Second, you have to have the Jackson libraries in you classpath so Spring can pick them up and use them for unmarshalling the object.
If you use Maven, use these dependencies:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.12</version>
</dependency>
BTW, why do you have to serialize the HTML form and sent it across? I would suggest you use a REST client, for instance this one, that is available in the Chrome WebStore.

Categories