From 6e07a63797422994a96059188b1753597a22ffd1 Mon Sep 17 00:00:00 2001 From: victorsosa Date: Fri, 24 Jun 2016 09:06:52 -0400 Subject: [PATCH] WW-4650 Json deserialization does not work in 2.5.1 logic need to be changed as accept can be a list; the check need to be done in the list itself. Accept:application/json, text/plain, */* --- .gitignore | 3 + .../apache/struts2/json/JSONInterceptor.java | 144 +++++++++--------- .../struts2/json/JSONInterceptorTest.java | 28 ++-- 3 files changed, 91 insertions(+), 84 deletions(-) diff --git a/.gitignore b/.gitignore index 0285aab243..65b5ac5d3e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ .metadata/ Servers/ +#VSCode +.vscode + # OSX .DS_Store diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java index ba775d32cc..b4ad4b7f51 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java @@ -82,6 +82,8 @@ public String intercept(ActionInvocation invocation) throws Exception { accept = request.getHeader("accept"); } + String[] accepts = accept.split(","); + Object rootObject = null; final ValueStack stack = invocation.getStack(); if (this.root != null) { @@ -92,96 +94,98 @@ public String intercept(ActionInvocation invocation) throws Exception { } } - if ((accept != null) && accept.equalsIgnoreCase("application/json")) { - // load JSON object - Object obj = JSONUtil.deserialize(request.getReader()); + for (String accept : accepts) { + if ((accept != null) && accept.equalsIgnoreCase("application/json")) { + // load JSON object + Object obj = JSONUtil.deserialize(request.getReader()); - // JSON array (this.root cannot be null in this case) - if(obj instanceof List && this.root != null) { - String mapKey = this.root; - rootObject = null; + // JSON array (this.root cannot be null in this case) + if(obj instanceof List && this.root != null) { + String mapKey = this.root; + rootObject = null; - if(this.root.indexOf('.') != -1) { - mapKey = this.root.substring(this.root.lastIndexOf('.') + 1); + if(this.root.indexOf('.') != -1) { + mapKey = this.root.substring(this.root.lastIndexOf('.') + 1); - rootObject = stack.findValue(this.root.substring(0, this.root.lastIndexOf('.'))); - if (rootObject == null) { - throw new RuntimeException("JSON array: Invalid root expression: '" + this.root + "'."); + rootObject = stack.findValue(this.root.substring(0, this.root.lastIndexOf('.'))); + if (rootObject == null) { + throw new RuntimeException("JSON array: Invalid root expression: '" + this.root + "'."); + } } - } - // create a map with a list inside - Map m = new HashMap(); - m.put(mapKey, new ArrayList((List) obj)); - obj = m; - } + // create a map with a list inside + Map m = new HashMap(); + m.put(mapKey, new ArrayList((List) obj)); + obj = m; + } - if (obj instanceof Map) { - Map json = (Map) obj; + if (obj instanceof Map) { + Map json = (Map) obj; - // clean up the values - if (dataCleaner != null) - dataCleaner.clean("", json); + // clean up the values + if (dataCleaner != null) + dataCleaner.clean("", json); - if (rootObject == null) // model overrides action - rootObject = invocation.getStack().peek(); + if (rootObject == null) // model overrides action + rootObject = invocation.getStack().peek(); - // populate fields - populator.populateObject(rootObject, json); - } else { - LOG.error("Unable to deserialize JSON object from request"); - throw new JSONException("Unable to deserialize JSON object from request"); - } - } else if ((accept != null) && accept.equalsIgnoreCase("application/json-rpc")) { - Object result; - if (this.enableSMD) { - // load JSON object - Object obj = JSONUtil.deserialize(request.getReader()); - - if (obj instanceof Map) { - Map smd = (Map) obj; - - if (rootObject == null) { // model makes no sense when using RPC - rootObject = invocation.getAction(); - } + // populate fields + populator.populateObject(rootObject, json); + } else { + LOG.error("Unable to deserialize JSON object from request"); + throw new JSONException("Unable to deserialize JSON object from request"); + } + } else if ((accept != null) && accept.equalsIgnoreCase("application/json-rpc")) { + Object result; + if (this.enableSMD) { + // load JSON object + Object obj = JSONUtil.deserialize(request.getReader()); + + if (obj instanceof Map) { + Map smd = (Map) obj; + + if (rootObject == null) { // model makes no sense when using RPC + rootObject = invocation.getAction(); + } + + // invoke method + try { + result = this.invoke(rootObject, smd); + } catch (Exception e) { + RPCResponse rpcResponse = new RPCResponse(); + rpcResponse.setId(smd.get("id").toString()); + rpcResponse.setError(new RPCError(e, RPCErrorCode.EXCEPTION, getDebug())); + + result = rpcResponse; + } + } else { + String message = "SMD request was not in the right format. See http://json-rpc.org"; - // invoke method - try { - result = this.invoke(rootObject, smd); - } catch (Exception e) { RPCResponse rpcResponse = new RPCResponse(); - rpcResponse.setId(smd.get("id").toString()); - rpcResponse.setError(new RPCError(e, RPCErrorCode.EXCEPTION, getDebug())); - + rpcResponse.setError(new RPCError(message, RPCErrorCode.INVALID_PROCEDURE_CALL)); result = rpcResponse; } } else { - String message = "SMD request was not in the right format. See http://json-rpc.org"; + String message = "Request with content type of 'application/json-rpc' was received but SMD is " + + "not enabled for this interceptor. Set 'enableSMD' to true to enable it"; RPCResponse rpcResponse = new RPCResponse(); - rpcResponse.setError(new RPCError(message, RPCErrorCode.INVALID_PROCEDURE_CALL)); + rpcResponse.setError(new RPCError(message, RPCErrorCode.SMD_DISABLED)); result = rpcResponse; } - } else { - String message = "Request with content type of 'application/json-rpc' was received but SMD is " - + "not enabled for this interceptor. Set 'enableSMD' to true to enable it"; - RPCResponse rpcResponse = new RPCResponse(); - rpcResponse.setError(new RPCError(message, RPCErrorCode.SMD_DISABLED)); - result = rpcResponse; + String json = JSONUtil.serialize(result, excludeProperties, getIncludeProperties(), + ignoreHierarchy, excludeNullProperties); + json = addCallbackIfApplicable(request, json); + boolean writeGzip = enableGZIP && JSONUtil.isGzipInRequest(request); + JSONUtil.writeJSONToResponse(new SerializationParams(response, this.defaultEncoding, + this.wrapWithComments, json, true, writeGzip, noCache, -1, -1, prefix, "application/json")); + + return Action.NONE; + } else { + LOG.debug("Accept header parameter must be 'application/json' or 'application/json-rpc'. Ignoring request with accept ", accept); + break; } - - String json = JSONUtil.serialize(result, excludeProperties, getIncludeProperties(), - ignoreHierarchy, excludeNullProperties); - json = addCallbackIfApplicable(request, json); - boolean writeGzip = enableGZIP && JSONUtil.isGzipInRequest(request); - JSONUtil.writeJSONToResponse(new SerializationParams(response, this.defaultEncoding, - this.wrapWithComments, json, true, writeGzip, noCache, -1, -1, prefix, "application/json")); - - return Action.NONE; - } else { - - LOG.debug("Accept header parameter must be 'application/json' or 'application/json-rpc'. Ignoring request with accept ", accept); } return invocation.invoke(); diff --git a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java index ddae716138..85e64ecb01 100644 --- a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java +++ b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java @@ -71,7 +71,7 @@ public void testBadToTheBoneJSON4() throws Exception { private void tryBadJSON(String fileName) throws Exception { // request setRequestContent(fileName); - this.request.addHeader("accept", "application/json-rpc"); + this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -92,7 +92,7 @@ private void tryBadJSON(String fileName) throws Exception { public void testSMDDisabledSMD() throws Exception { // request setRequestContent("smd-3.txt"); - this.request.addHeader("accept", "application/json-rpc"); + this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); JSONInterceptor interceptor = new JSONInterceptor(); SMDActionTest1 action = new SMDActionTest1(); @@ -111,7 +111,7 @@ public void testSMDDisabledSMD() throws Exception { public void testSMDAliasedMethodCall1() throws Exception { // request setRequestContent("smd-14.txt"); - this.request.addHeader("accept", "application/json-rpc"); + this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -129,7 +129,7 @@ public void testSMDAliasedMethodCall1() throws Exception { public void testSMDAliasedMethodCall2() throws Exception { // request setRequestContent("smd-15.txt"); - this.request.addHeader("accept", "application/json-rpc"); + this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -147,7 +147,7 @@ public void testSMDAliasedMethodCall2() throws Exception { public void testSMDNoMethod() throws Exception { // request setRequestContent("smd-4.txt"); - this.request.addHeader("accept", "application/json-rpc"); + this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -171,7 +171,7 @@ public void testSMDNoMethod() throws Exception { public void testSMDMethodWithoutAnnotations() throws Exception { // request setRequestContent("smd-9.txt"); - this.request.addHeader("accept", "application/json-rpc"); + this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -192,7 +192,7 @@ public void testSMDMethodWithoutAnnotations() throws Exception { public void testSMDPrimitivesNoResult() throws Exception { // request setRequestContent("smd-6.txt"); - this.request.addHeader("accept", "application/json-rpc"); + this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -227,7 +227,7 @@ public void testSMDPrimitivesNoResult() throws Exception { public void testSMDReturnObject() throws Exception { // request setRequestContent("smd-10.txt"); - this.request.addHeader("accept", "application/json-rpc"); + this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -252,7 +252,7 @@ public void testSMDReturnObject() throws Exception { public void testSMDObjectsNoResult() throws Exception { // request setRequestContent("smd-7.txt"); - this.request.addHeader("accept", "application/json-rpc"); + this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -300,7 +300,7 @@ public void testSMDObjectsNoResult() throws Exception { public void testReadEmpty() throws Exception { // request setRequestContent("json-6.txt"); - this.request.addHeader("accept", "application/json"); + this.request.addHeader("accept", "application/json, text/plain, */*"); // interceptor JSONInterceptor interceptor = new JSONInterceptor(); @@ -315,7 +315,7 @@ public void testReadEmpty() throws Exception { public void test() throws Exception { // request setRequestContent("json-1.txt"); - this.request.addHeader("accept", "application/json"); + this.request.addHeader("accept", "application/json, text/plain, */*"); // interceptor JSONInterceptor interceptor = new JSONInterceptor(); @@ -437,7 +437,7 @@ public void test() throws Exception { public void testRoot() throws Exception { setRequestContent("json-5.txt"); - this.request.addHeader("accept", "application/json"); + this.request.addHeader("accept", "application/json, text/plain, */*"); // interceptor JSONInterceptor interceptor = new JSONInterceptor(); @@ -462,7 +462,7 @@ public void testRoot() throws Exception { public void testJSONArray() throws Exception { setRequestContent("json-12.txt"); - this.request.addHeader("accept", "application/json"); + this.request.addHeader("accept", "application/json, text/plain, */*"); // interceptor JSONInterceptor interceptor = new JSONInterceptor(); @@ -488,7 +488,7 @@ public void testJSONArray() throws Exception { public void testJSONArray2() throws Exception { setRequestContent("json-12.txt"); - this.request.addHeader("accept", "application/json"); + this.request.addHeader("accept", "application/json, text/plain, */*"); // interceptor JSONInterceptor interceptor = new JSONInterceptor();