Can't Deserialize JSON in Java Servlet - java

My endpoint can't make sense of incoming JSON.
Here's the endpoint:
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.hibernate.Query;
import org.hibernate.Session;
import org.json.JSONObject;
...
#POST
#Path("/{department}/{team}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response handleJSON(JSONObject json , #PathParam("department") String department, #PathParam("team") String team){
MyObj myObj = new MyObj();
myObj.setDepartment(department);
myObj.setTeam(team);
myObj.setPlatform(json.optString("platform"));
saveObj(myObj);
return Response.ok(true).build();
}
I'm posting JSON containing the key/value for "platform" using Postman, with header: Content-Type as application/json
But I get this exception: com.owlike.genson.JsonBindingException: Could not deserialize to type class org.json.JSONObject
Looks like the problem has to do with: Illegal character at row 0 and column 1 expected { but read '-' !
But I'm pretty sure Postman should be sending valid JSON...
Here's more of the stacktrace:
09-Jul-2014 10:30:00.017 SEVERE [http-nio-8080-exec-4] com.sun.jersey.spi.container.ContainerResponse.logException Mapped exception to response: 500 (Internal Server Error)
javax.ws.rs.WebApplicationException: com.owlike.genson.JsonBindingException: Could not deserialize to type class org.json.JSONObject
at com.owlike.genson.ext.jaxrs.GensonJsonConverter.readFrom(GensonJsonConverter.java:127)
at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:474)
at com.sun.jersey.server.impl.model.method.dispatch.EntityParamDispatchProvider$EntityInjectable.getValue(EntityParamDispatchProvider.java:123)
at com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:46)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:203)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:526)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:655)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:744)
Caused by: com.owlike.genson.JsonBindingException: Could not deserialize to type class org.json.JSONObject
at com.owlike.genson.Genson.deserialize(Genson.java:391)
at com.owlike.genson.ext.jaxrs.GensonJsonConverter.readFrom(GensonJsonConverter.java:125)
... 41 more
Caused by: com.owlike.genson.stream.JsonStreamException: Illegal character at row 0 and column 1 expected { but read '-' !
at com.owlike.genson.stream.JsonReader.newWrongTokenException(JsonReader.java:949)
at com.owlike.genson.stream.JsonReader.begin(JsonReader.java:425)
at com.owlike.genson.stream.JsonReader.beginObject(JsonReader.java:157)
at com.owlike.genson.reflect.BeanDescriptor.deserialize(BeanDescriptor.java:101)
at com.owlike.genson.reflect.BeanDescriptor.deserialize(BeanDescriptor.java:90)
at com.owlike.genson.convert.BeanViewConverter.deserialize(BeanViewConverter.java:102)
at com.owlike.genson.convert.NullConverter$NullConverterWrapper.deserialize(NullConverter.java:56)
at com.owlike.genson.Genson.deserialize(Genson.java:389)
... 42 more

This might not be an ideal solution, but i do think it could work.
Hopefully you have the Jackson JSON dependency already...
you can find it here: http://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
I would try the following code:
#POST
#Path("/{department}/{team}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response handleJSON(String json, #PathParam("department") String department, #PathParam("team") String team){
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readValue(json, JsonNode.class);
MyObj myObj = new MyObj();
myObj.setDepartment(department);
myObj.setTeam(team);
if (node.get("platform") != null) {
myObj.setPlatform(node.get("platform").textValue());
}
saveObj(myObj);
return Response.ok(true).build();
}
Notice that I am asking your WS Framework to just pass me the JSON as a String and just handling it myself.
Maybe its not ideal, but should work.
Cheers!

I don't know which JSON Serializer you are using but most probably this will be Jettison or Jackson. As far as I know they don't support converting an instance of org.json.JSONObject directly. The more common way is to simply use custom Java Beans:
public class Foo implements Serializable {
private String platform;
// getters + setters
}
#POST
#Path("/{department}/{team}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response handleJson(Foo foo, #PathParam("department") String department, #PathParam("team") String team) {
...
myObj.setPlatform(foo.getPlatform());
...
}
Foo should be annotated with #XmlRootElement if you are using Jettison.
If you don't want to create a custom Bean for every Entity you are expecting you can use Object, Map or String as parameter and serialize on your own:
#POST
#Path("/{department}/{team}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response handleJson(String json, #PathParam("department") String department, #PathParam("team") String team) {
...
JSONObject jsonObject = new JSONObject(json);
myObj.setPlatform(json.optString("platform"));
...
}
Last solution is implementing a MessageBodyReader which handles JSONObject. Simple example:
#Provider
public class JsonObjectReader implements MessageBodyReader<JSONObject> {
#Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return type == JSONObject.class && MediaType.APPLICATION_JSON_TYPE.equals(mediaType);
}
#Override
public JSONObject readFrom(Class<JSONObject> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
return new JSONObject(IOUtils.toString(entityStream));
}
}

You should first inspect how your request is being sent. It is probably being sent as an escaped String, instead of raw JSON.
In my case, that was what was happening when I was using a generic REST client to send requests as pure JSON Strings, as my client doesn't know the object definitions.
To prevent that, in your client, you could send a (org.codehaus.jettison.json) JSONObject instead of just a String (it has a constructor that accepts a JSON String), but that will depend on your dependencies. In my case I'm using Jersey 1.19.
Note that, depending on your classpath, (Jersey 1.19 with Genson in my case) you might also need to read the response input stream manually if you also want to read the response as a JSON String.

Related

How to resolve 'mediaType' must not be empty error in Spring 3.0 MVC?

How to resolve mediaType must not be empty error in Spring 3.0 MVC? One of our requirement we want to implement the "Support Universal Links" for mobile app:
The file path should be: http://localhost:9080/.well-known/apple-app-site-association When I request the URL https://localhost:9080/.well-known/apple-app-site-association We are getting the below error:
Error:
[5/7/18 10:54:38:776 EDT] 00000125 SystemOut O 2018-05-07 10:54:38,757 ERROR PageController - Exception while processing request for: /.well-known/apple-app-site-association
java.lang.IllegalArgumentException: 'mediaType' must not be empty
at org.springframework.util.Assert.hasLength(Assert.java:136) ~[spring-core-3.1.4.RELEASE.jar:3.1.4.RELEASE]
at org.springframework.http.MediaType.parseMediaType(MediaType.java:687) ~[spring-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
at com.sdl.webapp.common.impl.interceptor.StaticContentInterceptor.fallbackForContentProvider(StaticContentInterceptor.java:79) ~[dxa-common-impl-1.5.0.jar:1.5.0]
at com.sdl.webapp.common.impl.interceptor.StaticContentInterceptor.preHandle(StaticContentInterceptor.java:111) ~[dxa-common-impl-1.5.0.jar:1.5.0]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:914) ~[spring-webmvc-3.1.4.RELEASE.jar:3.1.4.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852) ~[spring-webmvc-3.1.4.RELEASE.jar:3.1.4.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) ~[spring-webmvc-3.1.4.RELEASE.jar:3.1.4.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778) ~[spring-webmvc-3.1.4.RELEASE.jar:3.1.4.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:575) [javax.j2ee.servlet.jar:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668) [javax.j2ee.servlet.jar:na]
My Controller:
package com.sdl.webapp.main.controller;
import com.sdl.webapp.common.api.WebRequestContext;
import com.sdl.webapp.common.api.localization.Localization;
import com.sdl.webapp.common.api.localization.LocalizationResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.*;
#Controller
public class AdminController
{
private static final Logger LOG = LoggerFactory.getLogger(AdminController.class);
private String successView;
#Autowired
private WebRequestContext webRequestContext;
#Autowired
private LocalizationResolver localizationResolver;
public AdminController() {}
#RequestMapping(method=RequestMethod.GET, value="/.well-known/apple-app-site-association", headers="content-type=application/json", produces = "application/json", consumes = "application/json")
public String getHeaders(#RequestHeader(value="Content-Type", required=false, defaultValue="application/json") String ContentType, #RequestHeader(value="Accept", defaultValue="application/json") String accept)
{
Localization localization = webRequestContext.getLocalization();
LOG.trace("ContentType : " + ContentType);
return localization.getPath() + "/.well-known/apple-app-site-association";
}
}
In your request mapping for "/.well-known/apple-app-site-association" , you are specifying a request header parameter of "Content-Type", however you are not supplying one with your request.
try a method signature of:
public String getHeaders(#RequestHeader(value="Content-Type", required=false) String ContentType)
or
public String getHeaders(#RequestHeader(value="Content-Type", defaultValue="some value") String ContentType)
Possible elements for the RequestHeader annotation are defaultValue, name, required and value.
Add produce type to #RequestMapping()
example :
produces = MediaType.APPLICATION_JSON_VALUE
produces = MediaType.TEXT_PLAIN_VALUE
produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE}

How to return text_html type response in Jersey

I am developing a REST API using jersey jax-RS. This consumes data in JSON format and produces the output in html format.
When I set the MediaType for #Produces as TEXT_HTML and #Consumes as #APPLICATON_JSON and requested the 'GET' query on POSTMAN REST client, it gave me the following error:
org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [Jersey Web Application] in context with path [/try2] threw exception [org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=text/html, type=class java.util.ArrayList, genericType=java.util.List<org.sc.try2.model.Event>.] with root cause
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=text/html, type=class java.util.ArrayList, genericType=java.util.List<org.sc.try2.model.Event>.
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:247)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:103)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:88)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1154)
at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:613)
at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:375)
at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:365)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:272)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
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:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:297)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:252)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1025)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:372)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:345)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:220)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
My codes :
StudentResource.java
package org.sc.try2.resources;
//import java.awt.Event;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
//import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.sc.try2.model.Student;
import org.sc.try2.service.StudentService;
#Path("/students")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_HTML)
public class StudentResource {
StudentService studentService = new StudentService();
//EventService es = new EventService();
#GET
#Path("/{studentEmail}/viewAll")
public List<Student> getStudents(#PathParam("studentEmail") String emailID){
System.out.println("cmn in this method of StudentResource........ ");
return studentService.getAllStudents(emailID);
}
#GET
#Path("/{studentEmail}/viewMyProfile")
public Student getStudent(#PathParam("studentEmail") String emailID){
System.out.println("cmn in this method of StudentResource........ ");
return studentService.getStudent(emailID);
}
#Path("/{studentEmail}/events")
public AllEventsResource getEvents(){
System.out.println("cmn in this method of StudentResource ");
return new AllEventsResource();
}
#Path("/{studentEmail}/myevents")
public EventResource getStudentEvents(){
return new EventResource();
}
#PUT
#Path("/{studentEmail}/updateProfile")
public String updateStudent(#PathParam("studentEmail") String emailID,Student student){
//student.setEmailID(emailID);
return studentService.updateStudent(emailID,student);
}
#DELETE
#Path("/{studentEmail}/deleteStudent/{delEmail}")
public String deleteStudent(#PathParam("studentEmail") String emailID,#PathParam("delEmail") String delEmail){
return studentService.removeStudent(emailID,delEmail);
}
}
EventsResource.java
package org.sc.try2.resources;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.sc.try2.model.Event;
import org.sc.try2.service.EventService;
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_HTML)
public class EventResource {
EventService es = new EventService();
#GET
public List<Event> getMyEvents(#PathParam("studentEmail") String emailID){
System.out.println("cmn in this method of EventsResource ");
return es.getAllEventsForStudent(emailID);
}
#POST
public String addEvent(#PathParam("studentEmail") String email,Event event){
System.out.println("here in res add evnt..");
return es.addEvent(email,event);
}
#PUT
#Path("/{eventId}")
public String updateEvent(#PathParam("studentEmail") String email,#PathParam("eventId") long id,Event event){
event.seteID(id);
return es.updateEvent(email,id,event);
}
#DELETE
#Path("/{eventId}")
public String deleteEvent(#PathParam("studentEmail") String email,#PathParam("eventId") long id){
return es.removeEvent(email,id);
}
}
On searching about this on the internet, I did not come across any useful solution except it was mentioned to download the genson jar and add it. After adding it as external jar in Eclipse (Java EE) MAVEN Project, it still gave the same exception which I guess is due to the fact that this jar is for json MediaType and is not used in the context of html content type.
Basically, I want to produce the content as HTML. How can I do it? I am entirely new to Jersey and the concept of REST API.

Issue while accessing post method in CXF rest service

i am trying to create a simple Restful web service and client using CXF 3.1.2 as below,
Service:
package com.rs.sample;
import javax.jws.WebService;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
public class GenServiceImpl {
#GET
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/login/{ext}")
public String login(#PathParam("ext") Integer ext) {
return "LoggedIn";
}
#POST
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/logout/{ext}")
public String logout(#PathParam("ext") Integer ext) {
return "LoggedOut";
}
}
Client:
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.cxf.jaxrs.client.WebClient;
public class TestClient {
static final String REST_URI = "http://localhost:8080/RestfulSample/Restful";
public static void main(String[] args) {
WebClient client = WebClient.create(REST_URI);
/*
//Get
client.path("login").path(new Integer(1234)).accept(MediaType.TEXT_PLAIN);
String loginResponse = client.get(String.class);
System.out.println(loginResponse); */
//Post
client.path("logout").accept(MediaType.TEXT_PLAIN);
String logoutResponse = client.post("1024").toString();
System.out.println(logoutResponse);
}
Here i have no problem in accesing login(Get) method and it is working as expected.
But when i tried to access logout(Post) method i am getting the below error,
WARNING: No operation matching request path "/RestfulSample/Restful/agentLogout" is found, Relative Path: /agentLogout, HTTP Method: POST, ContentType: application/xml, Accept: text/plain,. Please enable FINE/TRACE log level for more details.
Nov 04, 2015 3:49:32 PM org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper toResponse
WARNING: javax.ws.rs.ClientErrorException: HTTP 404 Not Found
at org.apache.cxf.jaxrs.utils.SpecExceptions.toHttpException(SpecExceptions.java:117)
at org.apache.cxf.jaxrs.utils.ExceptionUtils.toHttpException(ExceptionUtils.java:162)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.findTargetMethod(JAXRSUtils.java:528)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:177)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:77)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:251)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:171)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:293)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:212)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:268)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Could you please correct my mistake
Thanks,
#Path("/logout/{ext}"). You need another path segment after /logout. Whatever the value of {ext} should be
client.post("1024") is the body of the request. #PathParam is for the URI, so you need to add 1024 to the URI path, i.e. path("logout").path("1024"). Right now without the 1024 in the path, the endpoint doesn't exist (hence 404).
If you want to put the data in the POST body, then change it to #Path("/logout"), take out the #PathParam, and make the method param type String. You will need to parse it yourself

How to pass #RequestBody value to forwarded controller Spring MVC

I have to consume value of #RequestBody to forwarded controller. As I passed JSON as a request body and from one controller it will forward to another controller. But it second controller it gives java.io.IOException
MyController.java
#Controller
public class MyController {
/*
Request JSON like
{"personeId":"123789","personName":"Fitz"}
*/
#RequestMapping(value = "/myapp/first/", method = RequestMethod.POST,
consumes = { "application/json" })
public String authorize(#RequestBody Person person) {
//Looking good
if(Validator.validatePerson(perosn)) {
return "forward:/myapp/second/";
} else {
return "forward:/myapp/secondError/";
}
}
#RequestMapping(value = "/myapp/second/", method = RequestMethod.POST,
consumes = { "application/json" })
public #ResponseBody String login(#RequestBody Person person) {
// Not able to get Person object here.
// Getting java.io.IOException: Stream closed :(
System.out.println("---> "+person.getPersonName());
return "success";
}
#RequestMapping(value = "/myapp/secondError/", method = RequestMethod.POST,
consumes = { "application/json" })
public #ResponseBody String loginError() {
return "error";
}
}
StackTrace
org.apache.catalina.core.ApplicationDispatcher invoke
SEVERE: Servlet.service() for servlet dispatcher threw exception
java.io.IOException: Stream closed
at org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:339)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:94)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at java.io.PushbackInputStream.read(PushbackInputStream.java:139)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:168)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:105)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:301)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:721)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:466)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:391)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:168)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1228)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1011)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:955)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:301)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1015)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
So there is any way to achieve this scenario with Spring MVC.
you are getting the exception because #RequestBody annotation reads the underlying servlet input streams and consumes it, so you cannot read it twice.
If you look closer at the stack trace you can note the origin
org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:339)
You are trying to (re)read the data from a stream that is closed.
If you want to keep the first controller as it now you must change the second, you can choose for example to redirect to the second controller and put the object in session or to extract a method from the second controller that does the business logic and call it from the first controller.
If you can put the json in a parameter of the http call (authorize) you can avoid this problem, but (authorize) it's not a REST ednpoint anymore, but something like a "simple" http integration.
You should not forward in that case, but simply call the other methods :
#RequestMapping(value = "/myapp/first/", method = RequestMethod.POST,
consumes = { "application/json" })
public String authorize(#RequestBody Person person) {
//Looking good
if(Validator.validatePerson(perosn)) {
return login(person);
} else {
return loginError();
}
}
And this would only have sense if /myapp/second/ and /myapp/secondError/ are real URLs, if not, and if methods login and loginError should only be called from authorize method, they should simply be private methods in the controller.
Of course, if it involved business rules, it should go in service layer.
I don't think your approach is ideal. I would have only one call to the controller, and then start delegating the different tasks to different services.
if(Validator.validatePerson(perosn)) {
return loginService.login(person);
} else {
return "error";
}
The accepted answer is correct, there is no proper solution.
However here's a workaround that worked for me. I wanted to build a dispatcher that takes in json and forwards the request internally based on a command field:
#Controller
public class StackoverflowExampleController {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
#PostMapping("/post")
public ModelAndView post(#RequestBody String body) {
JsonNode tree = OBJECT_MAPPER.readTree(body);
String command = tree.get("command").asText();
return new ModelAndView("forward:/" + command + "?json=" + URLEncoder.encode(body));
}
#PostMapping("/test")
#ResponseBody
public String test(#RequestParam String json) {
return json;
}
}

Parsing String[] Request Parameter through REST with Apache CXF

I'm currently trying to develop a simple proof of concept for a REST application using CXF 2.6.4. I'm taking the non-spring approach. I'm using JBoss AS 7.1.1 Final as my web server.
The following is my web service class:
package restful.webservice;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import restful.entity.ControllerVersion;
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class WebServiceRest implements WebServiceInterface
{
#Override
#POST
#GET
#Path("/getVersion")
public ControllerVersion getVersion(String deviceID, String[] macAddresses)
{
return new ControllerVersion();
}
}
ControllerVersion class:
package restful.entity;
#XmlRootElement(name = "ControllerVersion")
public class ControllerVersion {
private String version="R1.1.0.0";
public String getVersion() {
return version;
}
}
Now, when I try to make a REST call to my web service, I get the following exception on the server side:
18:51:52,913 WARNING [org.apache.cxf.jaxrs.utils.JAXRSUtils] (http--0.0.0.0-8080-1) No message body reader has been found for request class String[], ContentType : application/json.
18:51:52,927 WARNING [org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper] (http--0.0.0.0-8080-1) javax.ws.rs.WebApplicationException
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1054)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:614)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:578)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:238)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:89)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:236)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:209)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:154)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:130)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:225)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:145)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:201)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
at java.lang.Thread.run(Thread.java:662)
The libraries that I have under WEB-INF/lib are:
cxf-api-2.6.4.jar
cxf-bundle-2.6.4.jar
cxf-rt-frontend-jaxrs-2.6.4.jar
cxf-rt-frontend-jaxrs.jar
cxf-rt-transports-http-2.6.4.jar
geronimo-servlet.jar
jaxb-api-2.2.5.jar
jaxb-impl-2.2.5.1.jar
jaxb-xjc-2.2.5.1.jar
jettison-1.3.4.jar
log4j-1.2.16.jar
neethi-3.0.2.jar
xmlschema-core-2.0.3.jar
The interesting thing is that I tried to do another project, but this time in the signature of my web service method, I included a custom class. I had no problem reading the contents of the custom class' instance, nor a problem while returning it to my client.
Am I missing something?
UPDATE:
I tried to add the following to my web.xml:
<init-param>
<param-name>jaxrs.providers</param-name>
<param-value>
org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider
(writeXsiType=false)
</param-value>
</init-param>
And added the following dependencies as well:
jackson-jaxrs-1.9.2.jar
jackson-mapper-asl-1.9.2.jar
jackson-xc-1.9.2.jar
Now I'm getting the following exception:
19:22:29,762 WARNING [org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper] (http--0.0.0.0-8080-1) javax.ws.rs.WebApplicationException: java.io.IOException: Stream closed
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:243)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:89)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:236)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:209)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:154)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:130)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:225)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:145)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:201)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.io.IOException: Stream closed
at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:377)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:193)
at java.io.FilterInputStream.read(FilterInputStream.java:116)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.ensureLoaded(ByteSourceBootstrapper.java:507)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.detectEncoding(ByteSourceBootstrapper.java:129)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.constructParser(ByteSourceBootstrapper.java:224)
at org.codehaus.jackson.JsonFactory._createJsonParser(JsonFactory.java:785)
at org.codehaus.jackson.JsonFactory.createJsonParser(JsonFactory.java:561)
at org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:414)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1038)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:614)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:578)
Update 2:
I tried to implement a method with a different signature, and this time, I have omitted the String array from the method:
public ControllerVersion getVersion(String deviceID)
Everything is working perfectly without the String array. What do you think I should do?
I apparently misunderstood how REST works. What I did to finally solve the problem was the following:
1- Changed my web service signature:
#POST
#Path("/getVersion")
#Produces(MediaType.APPLICATION_JSON)
#Consumes({"application/xml", "application/json", "application/x-www-form-urlencoded"})
public ControllerVersion getVersion(#FormParam("deviceID") String deviceID,#FormParam("macAddresses") String macAddresses)
2- Now, make sure that the client is sending a request with content-type (application/x-www-form-urlencoded) and that the client correctly adds form parameters same as those you defined in the #FormParam annotations.
3- Now, you can use a library such as FlexJson, to deserialize your parameters from a JSon String. For instance, I'm now sending the macAddresses as a JSon String: ["mac1","mac2"] from the client. On the server side, I convert this JSon string to a String[] using the following method:
public static String[] parseStringArrayFromJSONArray(String jsonArray)
{
String[] stringArray = null;
try
{
JSONArray array = new JSONArray(jsonArray);
if (array != null)
{
stringArray = new String[array.length()];
for (int i = 0; i < array.length(); i++)
{
stringArray[i] = array.getString(i);
}
}
} catch (Exception e)
{
stringArray = null;
}
return stringArray;
}
I hope this will help someone out there.
You're using #Consumes(MediaType.APPLICATION_JSON). You need to add jackson-core (and maybe some more jackson dependencies) for the conversion to work.
cxf uses jettison by default. Why do you have #GET and #POST annotations?
But it say's
java.io.IOException: Stream closed
So there is most likely an inputstream that isn't being shut down.

Categories

Resources