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 <lukaszlen...@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;
+        }
+    }
+}

Reply via email to