You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2022/10/17 06:54:11 UTC

[struts] branch WW-2815-xstream created (now bb7161029)

This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a change to branch WW-2815-xstream
in repository https://gitbox.apache.org/repos/asf/struts.git


      at bb7161029 WW-2815 Refactors XStreamHandler to allow to provide a custom configuration

This branch includes the following new commits:

     new bb7161029 WW-2815 Refactors XStreamHandler to allow to provide a custom configuration

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[struts] 01/01: WW-2815 Refactors XStreamHandler to allow to provide a custom configuration

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-2815-xstream
in repository https://gitbox.apache.org/repos/asf/struts.git

commit bb7161029669b6d2055ac42ff17de315ef1272f0
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Mon Oct 17 08:54:03 2022 +0200

    WW-2815 Refactors XStreamHandler to allow to provide a custom configuration
---
 .../struts2/rest/handler/XStreamHandler.java       |  33 +++--
 .../XStreamAllowedClassNames.java}                 |   4 +-
 .../XStreamAllowedClasses.java}                    |   4 +-
 .../{ => xstream}/XStreamPermissionProvider.java   |   2 +-
 .../XStreamProvider.java}                          |  12 +-
 .../struts2/rest/handler/XStreamHandlerTest.java   | 160 +++++++++++++++++++++
 6 files changed, 195 insertions(+), 20 deletions(-)

diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java
index 22e597561..d3534e32b 100644
--- a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java
+++ b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java
@@ -21,6 +21,7 @@ package org.apache.struts2.rest.handler;
 import com.opensymphony.xwork2.ActionInvocation;
 import com.opensymphony.xwork2.ModelDriven;
 import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.StaxDriver;
 import com.thoughtworks.xstream.security.ArrayTypePermission;
 import com.thoughtworks.xstream.security.ExplicitTypePermission;
 import com.thoughtworks.xstream.security.NoTypePermission;
@@ -29,12 +30,15 @@ import com.thoughtworks.xstream.security.PrimitiveTypePermission;
 import com.thoughtworks.xstream.security.TypePermission;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.apache.struts2.rest.handler.xstream.XStreamAllowedClassNames;
+import org.apache.struts2.rest.handler.xstream.XStreamAllowedClasses;
+import org.apache.struts2.rest.handler.xstream.XStreamPermissionProvider;
+import org.apache.struts2.rest.handler.xstream.XStreamProvider;
 
 import java.io.IOException;
 import java.io.Reader;
 import java.io.Writer;
 import java.util.Collection;
-import java.util.Date;
 import java.util.Map;
 import java.util.Set;
 
@@ -68,7 +72,15 @@ public class XStreamHandler extends AbstractContentTypeHandler {
     }
 
     protected XStream createXStream(ActionInvocation invocation) {
-        XStream stream = new XStream();
+        XStream stream;
+        if (invocation.getAction() instanceof XStreamProvider) {
+            LOG.debug("Using provider {} to create instance of XStream", invocation.getAction().getClass().getSimpleName());
+            stream = ((XStreamProvider) invocation.getAction()).createXStream();
+        } else {
+            LOG.debug("Creating default XStream instance using Stax driver: {}", StaxDriver.class.getSimpleName());
+            stream = new XStream(new StaxDriver());
+        }
+
         LOG.debug("Clears existing permissions");
         stream.addPermission(NoTypePermission.NONE);
 
@@ -82,13 +94,13 @@ public class XStreamHandler extends AbstractContentTypeHandler {
 
     private void addPerActionPermission(ActionInvocation invocation, XStream stream) {
         Object action = invocation.getAction();
-        if (action instanceof AllowedClasses) {
-            Set<Class<?>> allowedClasses = ((AllowedClasses) action).allowedClasses();
-            stream.addPermission(new ExplicitTypePermission(allowedClasses.toArray(new Class[allowedClasses.size()])));
+        if (action instanceof XStreamAllowedClasses) {
+            Set<Class<?>> allowedClasses = ((XStreamAllowedClasses) action).allowedClasses();
+            stream.addPermission(new ExplicitTypePermission(allowedClasses.toArray(new Class[0])));
         }
-        if (action instanceof AllowedClassNames) {
-            Set<String> allowedClassNames = ((AllowedClassNames) action).allowedClassNames();
-            stream.addPermission(new ExplicitTypePermission(allowedClassNames.toArray(new String[allowedClassNames.size()])));
+        if (action instanceof XStreamAllowedClassNames) {
+            Set<String> allowedClassNames = ((XStreamAllowedClassNames) action).allowedClassNames();
+            stream.addPermission(new ExplicitTypePermission(allowedClassNames.toArray(new String[0])));
         }
         if (action instanceof XStreamPermissionProvider) {
             Collection<TypePermission> permissions = ((XStreamPermissionProvider) action).getTypePermissions();
@@ -101,13 +113,12 @@ public class XStreamHandler extends AbstractContentTypeHandler {
     protected void addDefaultPermissions(ActionInvocation invocation, XStream stream) {
         stream.addPermission(new ExplicitTypePermission(new Class[]{invocation.getAction().getClass()}));
         if (invocation.getAction() instanceof ModelDriven) {
-            stream.addPermission(new ExplicitTypePermission(new Class[]{((ModelDriven) invocation.getAction()).getModel().getClass()}));
+            stream.addPermission(new ExplicitTypePermission(new Class[]{((ModelDriven<?>) invocation.getAction()).getModel().getClass()}));
         }
         stream.addPermission(NullPermission.NULL);
         stream.addPermission(PrimitiveTypePermission.PRIMITIVES);
         stream.addPermission(ArrayTypePermission.ARRAYS);
         stream.addPermission(CollectionTypePermission.COLLECTIONS);
-        stream.addPermission(new ExplicitTypePermission(new Class[]{Date.class}));
     }
 
     public String getContentType() {
@@ -125,7 +136,7 @@ public class XStreamHandler extends AbstractContentTypeHandler {
         @Override
         public boolean allows(Class type) {
             return type != null && type.isInterface() &&
-                    (Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type));
+                (Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type));
         }
 
     }
diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/AllowedClassNames.java b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamAllowedClassNames.java
similarity index 90%
copy from plugins/rest/src/main/java/org/apache/struts2/rest/handler/AllowedClassNames.java
copy to plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamAllowedClassNames.java
index c7c23ba58..340ac9c9b 100644
--- a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/AllowedClassNames.java
+++ b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamAllowedClassNames.java
@@ -16,10 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.rest.handler;
+package org.apache.struts2.rest.handler.xstream;
 
 import java.util.Set;
 
-public interface AllowedClassNames {
+public interface XStreamAllowedClassNames {
     Set<String> allowedClassNames();
 }
diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/AllowedClasses.java b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamAllowedClasses.java
similarity index 90%
rename from plugins/rest/src/main/java/org/apache/struts2/rest/handler/AllowedClasses.java
rename to plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamAllowedClasses.java
index 149a32c90..504c35f89 100644
--- a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/AllowedClasses.java
+++ b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamAllowedClasses.java
@@ -16,10 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.rest.handler;
+package org.apache.struts2.rest.handler.xstream;
 
 import java.util.Set;
 
-public interface AllowedClasses {
+public interface XStreamAllowedClasses {
     Set<Class<?>> allowedClasses();
 }
diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamPermissionProvider.java b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamPermissionProvider.java
similarity index 95%
rename from plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamPermissionProvider.java
rename to plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamPermissionProvider.java
index b58bf91db..f163912cf 100644
--- a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamPermissionProvider.java
+++ b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamPermissionProvider.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.rest.handler;
+package org.apache.struts2.rest.handler.xstream;
 
 import com.thoughtworks.xstream.security.TypePermission;
 
diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/AllowedClassNames.java b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamProvider.java
similarity index 73%
rename from plugins/rest/src/main/java/org/apache/struts2/rest/handler/AllowedClassNames.java
rename to plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamProvider.java
index c7c23ba58..517029d74 100644
--- a/plugins/rest/src/main/java/org/apache/struts2/rest/handler/AllowedClassNames.java
+++ b/plugins/rest/src/main/java/org/apache/struts2/rest/handler/xstream/XStreamProvider.java
@@ -16,10 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.struts2.rest.handler;
+package org.apache.struts2.rest.handler.xstream;
 
-import java.util.Set;
+import com.thoughtworks.xstream.XStream;
 
-public interface AllowedClassNames {
-    Set<String> allowedClassNames();
+/**
+ * An interface to be implemented by an action to create/provide an instance
+ * of XStream - it allows customisation per action
+ */
+public interface XStreamProvider {
+    XStream createXStream();
 }
diff --git a/plugins/rest/src/test/java/org/apache/struts2/rest/handler/XStreamHandlerTest.java b/plugins/rest/src/test/java/org/apache/struts2/rest/handler/XStreamHandlerTest.java
new file mode 100644
index 000000000..3510634ed
--- /dev/null
+++ b/plugins/rest/src/test/java/org/apache/struts2/rest/handler/XStreamHandlerTest.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.rest.handler;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionSupport;
+import com.opensymphony.xwork2.XWorkTestCase;
+import com.opensymphony.xwork2.mock.MockActionInvocation;
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.StaxDriver;
+import com.thoughtworks.xstream.security.ExplicitTypePermission;
+import com.thoughtworks.xstream.security.TypePermission;
+import org.apache.struts2.rest.handler.xstream.XStreamAllowedClassNames;
+import org.apache.struts2.rest.handler.xstream.XStreamAllowedClasses;
+import org.apache.struts2.rest.handler.xstream.XStreamPermissionProvider;
+import org.apache.struts2.rest.handler.xstream.XStreamProvider;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class XStreamHandlerTest extends XWorkTestCase {
+
+    private XStreamHandler handler;
+    private MockActionInvocation ai;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        handler = new XStreamHandler();
+        ai = new MockActionInvocation();
+        ActionSupport action = new ActionSupport();
+        ActionContext context = ActionContext.of(new HashMap<>()).withLocale(Locale.US);
+        ai.setInvocationContext(context);
+        ai.setAction(action);
+    }
+
+    public void testObjectToXml() throws Exception {
+        // given
+        SimpleBean obj = new SimpleBean();
+        obj.setName("Jan");
+        obj.setAge(12L);
+        obj.setParents(Arrays.asList("Adam", "Ewa"));
+
+        // when
+        Writer stream = new StringWriter();
+        handler.fromObject(ai, obj, null, stream);
+
+        // then
+        stream.flush();
+        assertThat(stream.toString())
+            .contains("<org.apache.struts2.rest.handler.SimpleBean>")
+            .contains("<name>Jan</name>")
+            .contains("<age>12</age>")
+            .contains("<parents class=\"java.util.Arrays$ArrayList\">")
+            .contains("<string>Adam</string>")
+            .contains("<string>Ewa</string>")
+            .contains("</org.apache.struts2.rest.handler.SimpleBean>");
+    }
+
+    public void testXmlToObject() {
+        // given
+        String xml = "<?xml version='1.0' encoding='UTF-8'?><org.apache.struts2.rest.handler.SimpleBean><name>Jan</name><age>12</age><parents class=\"java.util.ArrayList\"><string>Adam</string><string>Ewa</string></parents></org.apache.struts2.rest.handler.SimpleBean>";
+
+        SimpleBean obj = new SimpleBean();
+        ai.setAction(new SimpleAction());
+
+        // when
+        Reader in = new StringReader(xml);
+        handler.toObject(ai, in, obj);
+
+        // then
+        assertNotNull(obj);
+        assertEquals("Jan", obj.getName());
+        assertEquals(12L, obj.getAge().longValue());
+        assertNotNull(obj.getParents());
+        assertThat(obj.getParents())
+            .hasSize(2)
+            .containsExactly("Adam", "Ewa");
+    }
+
+    public void testXmlToObjectWithAliases() {
+        // given
+        String xml = "<?xml version='1.0' encoding='UTF-8'?><data><name>Jan</name><age>12</age><parents><string>Adam</string><string>Ewa</string></parents></data>";
+
+        SimpleBean obj = new SimpleBean();
+        ai.setAction(new SimpleAliasAction());
+
+        // when
+        Reader in = new StringReader(xml);
+        handler.toObject(ai, in, obj);
+
+        // then
+        assertNotNull(obj);
+        assertEquals("Jan", obj.getName());
+        assertEquals(12L, obj.getAge().longValue());
+        assertNotNull(obj.getParents());
+        assertThat(obj.getParents())
+            .hasSize(2)
+            .containsExactly("Adam", "Ewa");
+    }
+
+    private static class SimpleAction implements XStreamAllowedClasses, XStreamAllowedClassNames, XStreamPermissionProvider {
+        @Override
+        public Set<Class<?>> allowedClasses() {
+            Set<Class<?>> classes = new HashSet<>();
+            classes.add(SimpleBean.class);
+            return classes;
+        }
+
+        @Override
+        public Set<String> allowedClassNames() {
+            HashSet<String> strings = new HashSet<>();
+            strings.add(ArrayList.class.getName());
+            return strings;
+        }
+
+        @Override
+        public Collection<TypePermission> getTypePermissions() {
+            ArrayList<TypePermission> permissions = new ArrayList<>();
+            permissions.add(new ExplicitTypePermission(new Class[]{String.class}));
+            return permissions;
+        }
+    }
+
+    private static class SimpleAliasAction extends SimpleAction implements XStreamProvider {
+        @Override
+        public XStream createXStream() {
+            XStream stream = new XStream(new StaxDriver());
+            stream.alias("parents", ArrayList.class);
+            stream.alias("data", SimpleBean.class);
+            return stream;
+        }
+    }
+}