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.
Related
I have some code for download file from web server.
Everything works alright, but in console I have this exception:
июн 26, 2015 2:08:42 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [default] in context with path [/TestTask] threw exception
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:462)
at org.apache.struts2.dispatcher.DefaultDispatcherErrorHandler.handleErrorInDevMode(DefaultDispatcherErrorHandler.java:109)
at org.apache.struts2.dispatcher.DefaultDispatcherErrorHandler.handleError(DefaultDispatcherErrorHandler.java:57)
at org.apache.struts2.dispatcher.Dispatcher.sendError(Dispatcher.java:909)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:576)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
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(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)
Why and what it can be? And how i can fix this problem? I try find answer in the google, but I failed.
The code:
package actions;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.Action;
import org.apache.log4j.Logger;
import org.apache.struts.chain.contexts.ServletActionContext;
import service.CsvCreator;
import com.opensymphony.xwork2.ActionSupport;
public class DownloadCsvAction extends ActionSupport {
private static final long serialVersionUID = -4714537109287679996L;
private CsvCreator CSVcreator;
private static final Logger logger = Logger.getLogger(DownloadCsvAction.class);
public CsvCreator getCSVcreator() {
return CSVcreator;
}
public void setCSVcreator(CsvCreator cSVcreator) {
CSVcreator = cSVcreator;
}
#Override
public String execute() {
HttpServletResponse response = org.apache.struts2.ServletActionContext.getResponse();
response.setHeader("Content-Disposition", "attachment; filename=\"phone_records.csv\"");
response.setContentType("text/csv");
ServletOutputStream out;
try {
out = response.getOutputStream();
String tableHeader = "Caller, Event, Reciever, Timestamp\n";
out.write(tableHeader.getBytes("UTF-8"));
out.write(CSVcreator.getAllRecordsInString().getBytes("UTF-8"));
out.flush();
out.close();
} catch (IOException e) {
logger.error(e.getMessage());
}
return SUCCESS;
}
}
And my struts.xml:
<action name="DownloadCsvAction" class="DownloadCsvAction">
<result name="success" type="dispatcher"/>
</action>
Why and what it can be?
Because response is already committed. You have closed response before it's used by the Struts2.
And how I can fix this problem?
When your action execution ends, return Action.NONE result code. This code tells the invoker to not execute any result because response might be already committed.
You can also rewrite the action implementation to use stream result type. In this way you have not to do with the response and let Struts2 do the rest. Example of using stream result is here.
I have created a rest service in Jersey which is internally using Jackson for mapping JSON to Java Object. The whole Service works on Apache tomcat but however when i deploy it on weblogic 10.2.3 it is giving the below error
java.lang.NoSuchMethodError: org.domain.pojo.CreateOutput.pcsetErrorText(Ljava/lang/String;)V
at org.domain.pojo.CreateOutput.setErrorText(CreateEVCOutput.java)
at org.domain.serviceinterface.ExceptionMapper.toResponse(ExceptionMapper.java:14)
at com.sun.jersey.spi.container.ContainerResponse.mapException(ContainerResponse.java:480)
at com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException(ContainerResponse.java:417)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1477)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:558)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:733)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:301)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:184)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3732)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3696)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2273)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1490)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
I am using Jersey 1.19 and weblogic 10.2.3 version.
Below is my service class POST method
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public CreateOutput RequestCall(Wrapper createServiceInput) {
/*
* handling all the business logic
*/
CreateOutput serviceOutput = new CreateOutput();
serviceOutput.setErrorCode("200");
logger.info("Messafe Successfully Consumed without any exception");
serviceOutput.setErrorText("Xml passed successfully");
serviceOutput.setStatus("SUCCESS");
// return HTTP response 200 in case of success
return serviceOutput;
}
and below is my exception mapper custom class to handle exception
#Provider
public class MapperException implements ExceptionMapper<Throwable> {
CreateOutput createOutput = new CreateOutput();
public Response toResponse(Throwable e) {
createOutput.setErrorText(e.getMessage());
createOutput.setErrorCode(Status.PRECONDITION_FAILED.toString());
createOutput.setStatus("failure");
return Response.status(Status.PRECONDITION_FAILED).entity(createOutput).type("application/json").build();
}
}
Thanks in advance for your help !
The page should be rendered only if user has permissions to see it. I try to achieve that by performing a check in PreRenderView event listener method:
<f:event type="preRenderView" listener="#{theBean.init}" />
And the method itself:
public void init() {
if (user.havePermission()) {
// backing bean init
} else {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.getRequestMap().put("message", no_permissions_message);
try {
ec.dispatch(ec.getRequestContextPath()
+ path_to_no_perm_page);
fc.responseComlete();
} catch (IOException e) {
e.printStackTrace();
}
}
}
When I try to look at denied page I see it, but get an exception in server log:
at org.omnifaces.util.FacesLocal.getRequestMap(FacesLocal.java:945) [omnifaces-1.7.jar:1.7]
at org.omnifaces.util.FacesLocal.getRequestAttribute(FacesLocal.java:953) [omnifaces-1.7.jar:1.7]
at org.omnifaces.util.Faces.getRequestAttribute(Faces.java:1416) [omnifaces-1.7.jar:1.7]
at org.omnifaces.eventlistener.CallbackPhaseListener.getCallbackPhaseListeners(CallbackPhaseListener.java:110) [omnifaces-1.7.jar:1.7]
at org.omnifaces.eventlistener.CallbackPhaseListener.afterPhase(CallbackPhaseListener.java:77) [omnifaces-1.7.jar:1.7]
at com.sun.faces.lifecycle.Phase.handleAfterPhase(Phase.java:189) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:107) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:98) [primefaces-4.0.7.jar:4.0.7]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
...
The cause: immediately after dispatch call, FacesContext.getCurrentInstance() returns null. But this don't interrupt current phase. So on the phase end PhaseListener is executed. It tries to get FacesContext instance, but gets null.
Can I avoid PhaseListener execution here?
Or may be check for FacesContext current instance is not null should be added to omnifaces?
Thanks.
Do not use ExternalContext#dispatch(), ever. This method has no single sensible use case in a decent JSF web application. It only corrupts the JSF life cycle because it creates another FacesContext within the current request. You should use JSF's own NavigationHandler or use ExternalContext#redirect().
When you're already on JSF 2.2, use <f:viewAction action="#{bean.init}"> which supports a navigation case outcome (like <h:commandButton action>):
public String init() {
// ...
return "someViewId";
}
Or when you're still on JSF 2.0/2.1, and can thus only use <f:event type="preRenderView">, and given that you're using OmniFaces use its Faces#navigate() or Faces#redirect():
public void init() {
// ...
Faces.navigate("someViewId");
}
In case you aren't using OmniFaces, here's how it's implemented:
public void init() {
// ...
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().getNavigationHandler().handleNavigation(context, null, "someViewId");
}
Note that this all may still fail when using #PostConstruct instead of f:viewAction or preRenderView. See also a.o. Redirect in #PostConstruct causes IllegalStateException.
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.
I am implementing a JAX-RS filter with CXF and I am trying to edit the Entity of the response. My filter's code is shown below
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) throws IOException {
String s = (String) responseContext.getEntity();
responseContext.setEntity(s + "an additional message");
}
The problem is that I am getting an NoSuchMethodError when I am running it.
Here is my Exception stack
javax.ws.rs.InternalServerErrorException: java.lang.NoSuchMethodError: javax.ws.rs.container.ContainerResponseContext.setEntity(Ljava/lang/Object;)V
at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.handleWriteException(JAXRSOutInterceptor.java:385)
at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.serializeMessage(JAXRSOutInterceptor.java:224)
at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.processResponse(JAXRSOutInterceptor.java:154)
at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.handleMessage(JAXRSOutInterceptor.java:85)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
at org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:77)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:239)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:223)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:203)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:137)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:158)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:243)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPut(AbstractHTTPServlet.java:180)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:640)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:219)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
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:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.NoSuchMethodError: javax.ws.rs.container.ContainerResponseContext.setEntity(Ljava/lang/Object;)V
at com.my.oasis.filters.TestResponseFilter.filter(TestResponseFilter.java:20)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.runContainerResponseFilters(JAXRSUtils.java:1675)
at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.serializeMessage(JAXRSOutInterceptor.java:219)
... 27 more
What am I doing wrong? Is that meaning that the setEntity() method is defined in the API but is not implemented by the CXF Framework?
Thanks
Try implementing a CXF filter instead of direct JAX-RS filter. For that you will have to implement ResponseHandler interface.
Following is dummy code :
package com.question;
import org.apache.cxf.jaxrs.ext.ResponseHandler;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.message.Message;
/*
* Filter for Responses
*/
public class CustomOutfilter implements ResponseHandler
{
/*
* #param : arg0
*
* #param : arg1
*
* #param : arg2
*
* #return : Response
*/
#Override
public Response handleResponse(Message arg0, OperationResourceInfo arg1,
Response arg2)
{
//play with arg2 here and return it
return arg2;
}
}