Skip to content

Commit 8386d8f

Browse files
committed
[CAMEL-9297] Expose more configuration options from Camel's XStream. Allow to configure the types/permissions in the Java DSL. Updated the unit tests to do it like the end user would do it.
1 parent 741d0da commit 8386d8f

File tree

15 files changed

+154
-83
lines changed

15 files changed

+154
-83
lines changed

camel-core/src/main/java/org/apache/camel/builder/DataFormatClause.java

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@
1616
*/
1717
package org.apache.camel.builder;
1818

19+
import java.nio.charset.Charset;
1920
import java.util.Map;
2021
import java.util.zip.Deflater;
2122

22-
import org.w3c.dom.Node;
23-
24-
2523
import org.apache.camel.model.DataFormatDefinition;
2624
import org.apache.camel.model.ProcessorDefinition;
2725
import org.apache.camel.model.dataformat.AvroDataFormat;
@@ -55,7 +53,9 @@
5553
import org.apache.camel.model.dataformat.XmlJsonDataFormat;
5654
import org.apache.camel.model.dataformat.ZipDataFormat;
5755
import org.apache.camel.model.dataformat.ZipFileDataFormat;
56+
import org.apache.camel.util.CollectionStringBuffer;
5857
import org.apache.camel.util.jsse.KeyStoreParameters;
58+
import org.w3c.dom.Node;
5959

6060
/**
6161
* An expression for constructing the different possible {@link org.apache.camel.spi.DataFormat}
@@ -720,17 +720,60 @@ public T tidyMarkup() {
720720
}
721721

722722
/**
723-
* Uses the XStream data format
723+
* Uses the XStream data format.
724+
* <p/>
725+
* Favor using {@link #xstream(String)} to pass in a permission
724726
*/
725727
public T xstream() {
726728
return dataFormat(new XStreamDataFormat());
727729
}
728730

731+
/**
732+
* Uses the xstream by setting the encoding or permission
733+
*
734+
* @param encodingOrPermission is either an encoding or permission syntax
735+
*/
736+
public T xstream(String encodingOrPermission) {
737+
// is it an encoding? if not we assume its a permission
738+
if (Charset.isSupported(encodingOrPermission)) {
739+
return xstream(encodingOrPermission, (String) null);
740+
} else {
741+
return xstream(null, encodingOrPermission);
742+
}
743+
}
744+
729745
/**
730746
* Uses the xstream by setting the encoding
731747
*/
732-
public T xstream(String encoding) {
733-
return dataFormat(new XStreamDataFormat(encoding));
748+
public T xstream(String encoding, String permission) {
749+
XStreamDataFormat xdf = new XStreamDataFormat();
750+
xdf.setPermissions(permission);
751+
xdf.setEncoding(encoding);
752+
return dataFormat(xdf);
753+
}
754+
755+
/**
756+
* Uses the xstream by permitting the java type
757+
*
758+
* @param type the pojo xstream should use as allowed permission
759+
*/
760+
public T xstream(Class<?> type) {
761+
return xstream(null, type);
762+
}
763+
764+
/**
765+
* Uses the xstream by permitting the java type
766+
*
767+
* @param encoding encoding to use
768+
* @param type the pojo class(es) xstream should use as allowed permission
769+
*/
770+
public T xstream(String encoding, Class<?>... type) {
771+
CollectionStringBuffer csb = new CollectionStringBuffer(",");
772+
for (Class<?> clazz : type) {
773+
csb.append("+");
774+
csb.append(clazz.getName());
775+
}
776+
return xstream(encoding, csb.toString());
734777
}
735778

736779
/**

camel-core/src/main/java/org/apache/camel/model/dataformat/JsonDataFormat.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.camel.spi.DataFormat;
2828
import org.apache.camel.spi.Metadata;
2929
import org.apache.camel.spi.RouteContext;
30+
import org.apache.camel.util.CollectionStringBuffer;
3031
import org.apache.camel.util.ObjectHelper;
3132

3233
/**
@@ -68,6 +69,8 @@ public class JsonDataFormat extends DataFormatDefinition {
6869
private String enableFeatures;
6970
@XmlAttribute
7071
private String disableFeatures;
72+
@XmlAttribute
73+
private String permissions;
7174

7275
public JsonDataFormat() {
7376
super("json");
@@ -253,6 +256,42 @@ public void setDisableFeatures(String disableFeatures) {
253256
this.disableFeatures = disableFeatures;
254257
}
255258

259+
public String getPermissions() {
260+
return permissions;
261+
}
262+
263+
/**
264+
* Adds permissions that controls which Java packages and classes XStream is allowed to use during
265+
* unmarshal from xml/json to Java beans.
266+
* <p/>
267+
* A permission must be configured either here or globally using a JVM system property. The permission
268+
* can be specified in a syntax where a plus sign is allow, and minus sign is deny.
269+
* <br/>
270+
* Wildcards is supported by using <tt>.*</tt> as prefix. For example to allow <tt>com.foo</tt> and all subpackages
271+
* then specfy <tt>+com.foo.*</tt>. Multiple permissions can be configured separated by comma, such as
272+
* <tt>+com.foo.*,-com.foo.bar.MySecretBean</tt>.
273+
* <br/>
274+
* The following default permission is always included: <tt>"-*,java.lang.*,java.util.*"</tt> unless
275+
* its overridden by specifying a JVM system property with they key <tt>org.apache.camel.xstream.permissions</tt>.
276+
*/
277+
public void setPermissions(String permissions) {
278+
this.permissions = permissions;
279+
}
280+
281+
/**
282+
* To add permission for the given pojo classes.
283+
* @param type the pojo class(es) xstream should use as allowed permission
284+
* @see #setPermissions(String)
285+
*/
286+
public void setPermissions(Class<?>... type) {
287+
CollectionStringBuffer csb = new CollectionStringBuffer(",");
288+
for (Class<?> clazz : type) {
289+
csb.append("+");
290+
csb.append(clazz.getName());
291+
}
292+
setPermissions(csb.toString());
293+
}
294+
256295
@Override
257296
public String getDataFormatName() {
258297
// json data format is special as the name can be from different bundles
@@ -325,6 +364,14 @@ protected void configureDataFormat(DataFormat dataFormat, CamelContext camelCont
325364
if (disableFeatures != null) {
326365
setProperty(camelContext, dataFormat, "disableFeatures", disableFeatures);
327366
}
367+
if (permissions != null) {
368+
setProperty(camelContext, dataFormat, "permissions", permissions);
369+
}
370+
// if we have the unmarshal type, but no permission set, then use it to be allowed
371+
if (permissions == null && unmarshalType != null) {
372+
String allow = "+" + unmarshalType.getName();
373+
setProperty(camelContext, dataFormat, "permissions", allow);
374+
}
328375
}
329376

330377
}

camel-core/src/main/java/org/apache/camel/model/dataformat/XStreamDataFormat.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.apache.camel.spi.Metadata;
3939
import org.apache.camel.spi.RouteContext;
4040
import org.apache.camel.util.CamelContextHelper;
41+
import org.apache.camel.util.CollectionStringBuffer;
4142
import org.apache.camel.util.ObjectHelper;
4243

4344
/**
@@ -49,6 +50,8 @@
4950
@XmlRootElement(name = "xstream")
5051
@XmlAccessorType(XmlAccessType.NONE)
5152
public class XStreamDataFormat extends DataFormatDefinition {
53+
@XmlAttribute
54+
private String permissions;
5255
@XmlAttribute
5356
private String encoding;
5457
@XmlAttribute
@@ -57,9 +60,7 @@ public class XStreamDataFormat extends DataFormatDefinition {
5760
private String driverRef;
5861
@XmlAttribute
5962
private String mode;
60-
@XmlAttribute
61-
private String permissions;
62-
63+
6364
@XmlJavaTypeAdapter(ConvertersAdapter.class)
6465
@XmlElement(name = "converters")
6566
private List<String> converters;
@@ -187,12 +188,37 @@ public String getPermissions() {
187188
}
188189

189190
/**
190-
* Adds permissionsList
191+
* Adds permissions that controls which Java packages and classes XStream is allowed to use during
192+
* unmarshal from xml/json to Java beans.
193+
* <p/>
194+
* A permission must be configured either here or globally using a JVM system property. The permission
195+
* can be specified in a syntax where a plus sign is allow, and minus sign is deny.
196+
* <br/>
197+
* Wildcards is supported by using <tt>.*</tt> as prefix. For example to allow <tt>com.foo</tt> and all subpackages
198+
* then specfy <tt>+com.foo.*</tt>. Multiple permissions can be configured separated by comma, such as
199+
* <tt>+com.foo.*,-com.foo.bar.MySecretBean</tt>.
200+
* <br/>
201+
* The following default permission is always included: <tt>"-*,java.lang.*,java.util.*"</tt> unless
202+
* its overridden by specifying a JVM system property with they key <tt>org.apache.camel.xstream.permissions</tt>.
191203
*/
192204
public void setPermissions(String permissions) {
193205
this.permissions = permissions;
194206
}
195207

208+
/**
209+
* To add permission for the given pojo classes.
210+
* @param type the pojo class(es) xstream should use as allowed permission
211+
* @see #setPermissions(String)
212+
*/
213+
public void setPermissions(Class<?>... type) {
214+
CollectionStringBuffer csb = new CollectionStringBuffer(",");
215+
for (Class<?> clazz : type) {
216+
csb.append("+");
217+
csb.append(clazz.getName());
218+
}
219+
setPermissions(csb.toString());
220+
}
221+
196222
@Override
197223
protected DataFormat createDataFormat(RouteContext routeContext) {
198224
if ("json".equals(this.driver)) {
@@ -208,6 +234,9 @@ protected DataFormat createDataFormat(RouteContext routeContext) {
208234

209235
@Override
210236
protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) {
237+
if (this.permissions != null) {
238+
setProperty(camelContext, dataFormat, "permissions", this.permissions);
239+
}
211240
if (encoding != null) {
212241
setProperty(camelContext, dataFormat, "encoding", encoding);
213242
}
@@ -223,9 +252,6 @@ protected void configureDataFormat(DataFormat dataFormat, CamelContext camelCont
223252
if (this.implicitCollections != null) {
224253
setProperty(camelContext, dataFormat, "implicitCollections", this.implicitCollections);
225254
}
226-
if (this.permissions != null) {
227-
setProperty(camelContext, dataFormat, "permissions", this.permissions);
228-
}
229255
if (this.mode != null) {
230256
setProperty(camelContext, dataFormat, "mode", mode);
231257
}

components/camel-xstream/src/test/java/org/apache/camel/dataformat/xstream/MarshalDomainObjectJSONTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import org.apache.camel.builder.RouteBuilder;
2020
import org.apache.camel.component.mock.MockEndpoint;
21+
import org.apache.camel.model.dataformat.JsonLibrary;
2122
import org.junit.Test;
2223

2324
public class MarshalDomainObjectJSONTest extends MarshalDomainObjectTest {
@@ -57,10 +58,10 @@ public void configure() throws Exception {
5758
// just used for helping to marshal
5859
from("direct:marshal").marshal().json();
5960

60-
from("direct:reverse").unmarshal().json().to("mock:reverse");
61+
from("direct:reverse").unmarshal().json(JsonLibrary.XStream, PurchaseOrder.class).to("mock:reverse");
6162

6263
from("direct:inPretty").marshal().json(true);
63-
from("direct:backPretty").unmarshal().json().to("mock:reverse");
64+
from("direct:backPretty").unmarshal().json(JsonLibrary.XStream, PurchaseOrder.class, true).to("mock:reverse");
6465
}
6566
};
6667
}

components/camel-xstream/src/test/java/org/apache/camel/dataformat/xstream/MarshalDomainObjectTest.java

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,13 @@
1919
import org.apache.camel.builder.RouteBuilder;
2020
import org.apache.camel.component.mock.MockEndpoint;
2121
import org.apache.camel.test.junit4.CamelTestSupport;
22-
import org.junit.AfterClass;
23-
import org.junit.BeforeClass;
2422
import org.junit.Test;
2523

2624
/**
2725
* Marshal tests with domain objects.
2826
*/
2927
public class MarshalDomainObjectTest extends CamelTestSupport {
3028

31-
@BeforeClass
32-
public static void setup() {
33-
XStreamTestUtils.setPermissionSystemProperty("");
34-
}
35-
36-
@AfterClass
37-
public static void cleanup() {
38-
XStreamTestUtils.revertPermissionSystemProperty();
39-
}
40-
4129
@Test
4230
public void testMarshalDomainObject() throws Exception {
4331
MockEndpoint mock = getMockEndpoint("mock:result");
@@ -96,12 +84,12 @@ public void testMarshalAndUnmarshal() throws Exception {
9684
protected RouteBuilder createRouteBuilder() throws Exception {
9785
return new RouteBuilder() {
9886
public void configure() throws Exception {
99-
from("direct:in").marshal().xstream().to("mock:result");
87+
from("direct:in").marshal().xstream(PurchaseOrder.class).to("mock:result");
10088

10189
// just used for helping to marshal
102-
from("direct:marshal").marshal().xstream("UTF-8");
90+
from("direct:marshal").marshal().xstream("UTF-8", PurchaseOrder.class);
10391

104-
from("direct:reverse").unmarshal().xstream("UTF-8").to("mock:reverse");
92+
from("direct:reverse").unmarshal().xstream("UTF-8", PurchaseOrder.class).to("mock:reverse");
10593
}
10694
};
10795
}

components/camel-xstream/src/test/java/org/apache/camel/dataformat/xstream/UnmarshalThenMarshalJSONTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,20 @@
1919
import org.apache.camel.Exchange;
2020
import org.apache.camel.Processor;
2121
import org.apache.camel.builder.RouteBuilder;
22+
import org.apache.camel.model.dataformat.JsonLibrary;
2223

2324
public class UnmarshalThenMarshalJSONTest extends UnmarshalThenMarshalTest {
2425
protected RouteBuilder createRouteBuilder() {
2526
return new RouteBuilder() {
2627
public void configure() {
2728
from("direct:start").
28-
marshal().json().
29+
marshal().json(JsonLibrary.XStream, PurchaseOrder.class).
2930
process(new Processor() {
3031
public void process(Exchange exchange) throws Exception {
3132
log.debug("marshalled: " + exchange.getIn().getBody(String.class));
3233
}
3334
}).
34-
unmarshal().json().
35+
unmarshal().json(JsonLibrary.XStream, PurchaseOrder.class).
3536
to("mock:result");
3637
}
3738
};

components/camel-xstream/src/test/java/org/apache/camel/dataformat/xstream/UnmarshalThenMarshalTest.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,13 @@
2323
import org.apache.camel.builder.RouteBuilder;
2424
import org.apache.camel.component.mock.MockEndpoint;
2525
import org.apache.camel.test.junit4.CamelTestSupport;
26-
import org.junit.AfterClass;
27-
import org.junit.BeforeClass;
2826
import org.junit.Test;
2927

3028
/**
3129
* @version
3230
*/
3331
public class UnmarshalThenMarshalTest extends CamelTestSupport {
3432

35-
@BeforeClass
36-
public static void setup() {
37-
XStreamTestUtils.setPermissionSystemProperty("");
38-
}
39-
40-
@AfterClass
41-
public static void cleanup() {
42-
XStreamTestUtils.revertPermissionSystemProperty();
43-
}
44-
4533
@Test
4634
public void testSendXmlAndUnmarshal() throws Exception {
4735

@@ -69,13 +57,13 @@ protected RouteBuilder createRouteBuilder() {
6957
return new RouteBuilder() {
7058
public void configure() {
7159
from("direct:start").
72-
marshal().xstream().
60+
marshal().xstream(PurchaseOrder.class).
7361
process(new Processor() {
7462
public void process(Exchange exchange) throws Exception {
7563
log.debug("marshalled: " + exchange.getIn().getBody(String.class));
7664
}
7765
}).
78-
unmarshal().xstream().
66+
unmarshal().xstream(PurchaseOrder.class).
7967
to("mock:result");
8068
}
8169
};

0 commit comments

Comments
 (0)