Struts Version: 2.5.2
Struts Dependencies in POM
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>${org.strutsframework-version}</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-convention-plugin</artifactId>
<version>${org.strutsframework-version}</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-rest-plugin</artifactId>
<version>${org.strutsframework-version}</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>${org.strutsframework-version}</version>
</dependency>
Struts xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- Tell jinjava where the templates are -->
<constant name="struts.jinjava.basepath" value="WEB-INF/jinjava" />
<!-- custom jinjava tags specific to iws -->
<constant name="struts.jinjava.scan.tagPackage" value="com.hs.iws.jinjava.tag" />
<constant name="struts.jinjava.scan.functionPackage" value="com.hs.iws.jinjava.function" />
<!--Tell struts to use the REST action Mapper-->
<!--<constant name="struts.mapper.class" value="rest"/>-->
<!-- allow rest and non rest actions to live together -->
<constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.PrefixBasedActionMapper" />
<constant name="struts.mapper.prefixMapping" value=":rest,/grid:struts"/>
<constant name="struts.rest.namespace" value="/" />
<constant name="struts.convention.action.suffix" value="Action"/>
<constant name="struts.convention.action.mapAllMatches" value="true"/>
<constant name="struts.convention.package.locators.basePackage" value="com.hs.iws.actions" />
<!--re-assert the extensions for struts that have been over written by the rest plugin-->
<constant name="struts.action.extension" value="xhtml,,json,action"/>
<constant name="struts.rest.content.restrictToGET" value="false" />
<!--configure Convention Plugin to find our controllers-->
<constant name="struts.convention.default.parent.package" value="iws-default"/>
<!-- Spring Configuration -->
<!-- <constant name="struts.objectFactory" value="spring" /> -->
<constant name="struts.objectFactory.spring.autoWire" value="type" />
<!-- all grid actions should fall under this package -->
<package name="iws-grid" namespace="/grid" extends="struts-default,jweb-struts-gson-json,jinjava,datatables">
<interceptors>
<interceptor-stack name="iws-datatable-stack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="gson-json" />
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="debugging"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="iws-datatable-stack" />
</package>
<package name="iws-default" extends="rest-default, struts-default, jinjava, jweb-struts-gson-json" namespace="/">
</package>
</struts>
Action Class
package com.hs.iws.actions;
import com.hs.datatables.DataTable10CriteriaQuery;
import com.hs.datatables.DataTable10Helper;
import com.hs.iws.model.Users;
import org.apache.struts2.convention.annotation.*;
/**
* Created by Paul on 9/14/2016.
*/
@InterceptorRef(value = "iws-datatable-stack")
@ParentPackage(value = "iws-grid")
public class TestGridAction extends DataTable10CriteriaQuery{
@Action(value="/test-grid-json",
results={
@Result(name = "success", type = "datatable")
}
)
public String execute() {
return super.execute();
}
@Override
protected Class<?> getHibernateClass() {
return Users.class;
}
}
I am working with the DataTables JS library and am trying to write actions for the grid. I have a api in place that creates the json for me already and I just need to stream it back. I created a custom result to handle this, but the result mapped in the action never runs. No matter what the result type, the REST mapper tries to handle it as soon as it sees that application/json has been requested from the client. I have used the prefix mapping in the configuration to have all url's using /grid to bypass the rest mapper. It seems to be working in some capacity because it runs the correct interceptor stack and is using the @Action annotation information to map the url. However, the result specified is NOT running and is instead being provided by the rest mapper based on the stack trace I am receiving. I would like to completely bypass the rest mapper for any actions in the /grid namespace. Have I done something wrong in the configuration that is still causing rest to be involved in the request to those actions?
Stack Trace
ERROR RestActionInvocation Exception processing the result.
net.sf.json.JSONException: java.lang.reflect.InvocationTargetException
at net.sf.json.JSONObject._fromBean(JSONObject.java:987)
at net.sf.json.JSONObject.fromObject(JSONObject.java:168)
at net.sf.json.AbstractJSON._processValue(AbstractJSON.java:265)
at net.sf.json.JSONArray._processValue(JSONArray.java:2514)
at net.sf.json.JSONArray.processValue(JSONArray.java:2539)
at net.sf.json.JSONArray.addValue(JSONArray.java:2526)
at net.sf.json.JSONArray._fromCollection(JSONArray.java:1057)
at net.sf.json.JSONArray.fromObject(JSONArray.java:123)
at net.sf.json.AbstractJSON._processValue(AbstractJSON.java:237)
at net.sf.json.JSONObject._processValue(JSONObject.java:2808)
at net.sf.json.JSONObject.processValue(JSONObject.java:2874)
at net.sf.json.JSONObject.setInternal(JSONObject.java:2889)
at net.sf.json.JSONObject.setValue(JSONObject.java:1577)
at net.sf.json.JSONObject._fromBean(JSONObject.java:934)
at net.sf.json.JSONObject.fromObject(JSONObject.java:168)
at net.sf.json.AbstractJSON._processValue(AbstractJSON.java:265)
at net.sf.json.JSONObject._processValue(JSONObject.java:2808)
at net.sf.json.JSONObject.processValue(JSONObject.java:2874)
at net.sf.json.JSONObject.setInternal(JSONObject.java:2889)
at net.sf.json.JSONObject.setValue(JSONObject.java:1577)
at net.sf.json.JSONObject._fromBean(JSONObject.java:934)
at net.sf.json.JSONObject.fromObject(JSONObject.java:168)
at net.sf.json.JSONObject.fromObject(JSONObject.java:130)
at org.apache.struts2.rest.handler.JsonLibHandler.fromObject(JsonLibHandler.java:72)
at org.apache.struts2.rest.DefaultContentTypeHandlerManager.handleResult(DefaultContentTypeHandlerManager.java:181)
at org.apache.struts2.rest.RestActionInvocation.executeResult(RestActionInvocation.java:227)
at org.apache.struts2.rest.RestActionInvocation.processResult(RestActionInvocation.java:194)
at org.apache.struts2.rest.RestActionInvocation.invoke(RestActionInvocation.java:142)
at com.opensymphony.xwork2.DefaultActionProxy.execute(DefaultActionProxy.java:154)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:556)
at org.apache.struts2.dispatcher.ExecuteOperations.executeAction(ExecuteOperations.java:81)
at org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:113)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at com.hs.security.SecurityScanner.doFilter(SecurityScanner.java:95)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:105)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1078)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:760)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1524)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2116)
at org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(PropertyUtilsBean.java:1267)
at org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(PropertyUtilsBean.java:808)
at org.apache.commons.beanutils.PropertyUtilsBean.getProperty(PropertyUtilsBean.java:884)
at org.apache.commons.beanutils.PropertyUtils.getProperty(PropertyUtils.java:464)
at net.sf.json.JSONObject._fromBean(JSONObject.java:918)
... 52 more
Caused by: java.lang.UnsupportedOperationException: JsonObject
at com.google.gson.JsonElement.getAsByte(JsonElement.java:257)
... 62 more