You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ta...@apache.org on 2016/06/27 15:31:53 UTC

[1/2] qpid-jms git commit: QPIDJMS-188 Further improvements to the ObjectMessage handling.

Repository: qpid-jms
Updated Branches:
  refs/heads/master b05d577c1 -> 669cfff83


http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStreamTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStreamTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStreamTest.java
new file mode 100644
index 0000000..82de42c
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStreamTest.java
@@ -0,0 +1,569 @@
+/*
+ * 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.qpid.jms.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.UUID;
+import java.util.Vector;
+
+import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream.TrustedClassFilter;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+public class ClassLoadingAwareObjectInputStreamTest {
+
+    private final TrustedClassFilter ACCEPTS_ALL_FILTER = new TrustedClassFilter() {
+
+        @Override
+        public boolean isTrusted(Class<?> clazz) {
+            return true;
+        }
+    };
+
+    private final TrustedClassFilter ACCEPTS_NONE_FILTER = new TrustedClassFilter() {
+
+        @Override
+        public boolean isTrusted(Class<?> clazz) {
+            return false;
+        }
+    };
+
+    @Rule
+    public TestName name = new TestName();
+
+    //----- Test for serialized objects --------------------------------------//
+
+    @Test
+    public void testReadObject() throws Exception {
+        // Expect to succeed
+        doTestReadObject(new SimplePojo(name.getMethodName()), ACCEPTS_ALL_FILTER);
+
+        // Expect to fail
+        try {
+            doTestReadObject(new SimplePojo(name.getMethodName()), ACCEPTS_NONE_FILTER);
+            fail("Should have failed to read");
+        } catch (ClassNotFoundException cnfe) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void testReadObjectWithAnonymousClass() throws Exception {
+        AnonymousSimplePojoParent pojoParent = new AnonymousSimplePojoParent(name.getMethodName());
+
+        byte[] serialized = serializeObject(pojoParent);
+
+        TrustedClassFilter myFilter = new TrustedClassFilter() {
+            @Override
+            public boolean isTrusted(Class<?> clazz) {
+                return clazz.equals(AnonymousSimplePojoParent.class);
+            }
+        };
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+                ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, myFilter)) {
+
+            Object obj = reader.readObject();
+
+            assertTrue(obj instanceof AnonymousSimplePojoParent);
+            assertEquals("Unexpected payload", pojoParent.getPayload(), ((AnonymousSimplePojoParent)obj).getPayload());
+        }
+    }
+
+    @Test
+    public void testReadObjectWitLocalClass() throws Exception {
+        LocalSimplePojoParent pojoParent = new LocalSimplePojoParent(name.getMethodName());
+
+        byte[] serialized = serializeObject(pojoParent);
+
+        TrustedClassFilter myFilter = new TrustedClassFilter() {
+            @Override
+            public boolean isTrusted(Class<?> clazz) {
+                return clazz.equals(LocalSimplePojoParent.class);
+            }
+        };
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+             ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, myFilter)) {
+
+            Object obj = reader.readObject();
+
+            assertTrue(obj instanceof LocalSimplePojoParent);
+            assertEquals("Unexpected payload", pojoParent.getPayload(), ((LocalSimplePojoParent)obj).getPayload());
+        }
+    }
+
+    @Test
+    public void testReadObjectByte() throws Exception {
+        doTestReadObject(Byte.valueOf((byte) 255), ACCEPTS_ALL_FILTER);
+    }
+
+    @Test
+    public void testReadObjectShort() throws Exception {
+        doTestReadObject(Short.valueOf((short) 255), ACCEPTS_ALL_FILTER);
+    }
+
+    @Test
+    public void testReadObjectInteger() throws Exception {
+        doTestReadObject(Integer.valueOf(255), ACCEPTS_ALL_FILTER);
+    }
+
+    @Test
+    public void testReadObjectLong() throws Exception {
+        doTestReadObject(Long.valueOf(255l), ACCEPTS_ALL_FILTER);
+    }
+
+    @Test
+    public void testReadObjectFloat() throws Exception {
+        doTestReadObject(Float.valueOf(255.0f), ACCEPTS_ALL_FILTER);
+    }
+
+    @Test
+    public void testReadObjectDouble() throws Exception {
+        doTestReadObject(Double.valueOf(255.0), ACCEPTS_ALL_FILTER);
+    }
+
+    @Test
+    public void testReadObjectBoolean() throws Exception {
+        doTestReadObject(Boolean.FALSE, ACCEPTS_ALL_FILTER);
+    }
+
+    @Test
+    public void testReadObjectString() throws Exception {
+        doTestReadObject(new String(name.getMethodName()), ACCEPTS_ALL_FILTER);
+    }
+
+    //----- Test that arrays of objects can be read --------------------------//
+
+    @Test
+    public void testReadObjectStringArray() throws Exception {
+        String[] value = new String[2];
+
+        value[0] = name.getMethodName() + "-1";
+        value[1] = name.getMethodName() + "-2";
+
+        doTestReadObject(value, ACCEPTS_ALL_FILTER);
+    }
+
+    @Test
+    public void testReadObjectMultiDimensionalArray() throws Exception {
+        String[][][] value = new String[2][2][1];
+
+        value[0][0][0] = "0-0-0";
+        value[0][1][0] = "0-1-0";
+        value[1][0][0] = "1-0-0";
+        value[1][1][0] = "1-1-0";
+
+        doTestReadObject(value, ACCEPTS_ALL_FILTER);
+    }
+
+    //----- Test that primitive types are not filtered -----------------------//
+
+    @Test
+    public void testPrimitiveByteNotFiltered() throws Exception {
+        doTestReadPrimitive((byte) 255, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveShortNotFiltered() throws Exception {
+        doTestReadPrimitive((short) 255, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveIntegerNotFiltered() throws Exception {
+        doTestReadPrimitive(255, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveLongNotFiltered() throws Exception {
+        doTestReadPrimitive((long) 255, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveFloatNotFiltered() throws Exception {
+        doTestReadPrimitive((float) 255.0, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveDoubleNotFiltered() throws Exception {
+        doTestReadPrimitive(255.0, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveBooleanNotFiltered() throws Exception {
+        doTestReadPrimitive(false, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitveCharNotFiltered() throws Exception {
+        doTestReadPrimitive('c', ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testReadObjectStringNotFiltered() throws Exception {
+        doTestReadObject(new String(name.getMethodName()), ACCEPTS_NONE_FILTER);
+    }
+
+    //----- Test that primitive arrays get past filters ----------------------//
+
+    @Test
+    public void testPrimitiveByteArrayNotFiltered() throws Exception {
+        byte[] value = new byte[2];
+
+        value[0] = 1;
+        value[1] = 2;
+
+        doTestReadPrimitiveArray(value, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveShortArrayNotFiltered() throws Exception {
+        short[] value = new short[2];
+
+        value[0] = 1;
+        value[1] = 2;
+
+        doTestReadPrimitiveArray(value, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveIntegerArrayNotFiltered() throws Exception {
+        int[] value = new int[2];
+
+        value[0] = 1;
+        value[1] = 2;
+
+        doTestReadPrimitiveArray(value, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveLongArrayNotFiltered() throws Exception {
+        long[] value = new long[2];
+
+        value[0] = 1;
+        value[1] = 2;
+
+        doTestReadPrimitiveArray(value, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveFloatArrayNotFiltered() throws Exception {
+        float[] value = new float[2];
+
+        value[0] = 1.1f;
+        value[1] = 2.1f;
+
+        doTestReadPrimitiveArray(value, ACCEPTS_NONE_FILTER);
+    }
+
+    @Test
+    public void testPrimitiveDoubleArrayNotFiltered() throws Exception {
+        double[] value = new double[2];
+
+        value[0] = 1.1;
+        value[1] = 2.1;
+
+        doTestReadPrimitiveArray(value, ACCEPTS_NONE_FILTER);
+    }
+
+    //----- Tests for types that should be filtered --------------------------//
+
+    @Test
+    public void testReadObjectStringArrayFiltered() throws Exception {
+        String[] value = new String[2];
+
+        value[0] = name.getMethodName() + "-1";
+        value[1] = name.getMethodName() + "-2";
+
+        byte[] serialized = serializeObject(value);
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+             ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, ACCEPTS_NONE_FILTER)) {
+
+            try {
+                reader.readObject();
+                fail("Should not be able to read the payload.");
+            } catch (ClassNotFoundException ex) {}
+        }
+    }
+
+    @Test
+    public void testReadObjectMixedTypeArrayGetsFiltered() throws Exception {
+        Object[] value = new Object[4];
+
+        value[0] = name.getMethodName();
+        value[1] = UUID.randomUUID();
+        value[2] = new Vector<Object>();
+        value[3] = new SimplePojo(name.getMethodName());
+
+        byte[] serialized = serializeObject(value);
+
+        TrustedClassFilter myFilter = new TrustedClassFilter() {
+
+            @Override
+            public boolean isTrusted(Class<?> clazz) {
+                return !clazz.equals(SimplePojo.class);
+            }
+        };
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+             ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, myFilter)) {
+
+            try {
+                reader.readObject();
+                fail("Should not be able to read the payload.");
+            } catch (ClassNotFoundException ex) {}
+        }
+
+        // Replace the filtered type and try again
+        value[3] = new Integer(20);
+
+        serialized = serializeObject(value);
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+            ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, myFilter)) {
+
+           try {
+               Object result = reader.readObject();
+
+               assertNotNull(result);
+               assertTrue(result.getClass().isArray());
+           } catch (ClassNotFoundException ex) {
+               fail("Should be able to read the payload.");
+           }
+       }
+    }
+
+    @Test
+    public void testReadObjectMultiDimensionalStringArrayFiltered() throws Exception {
+        String[][] value = new String[2][2];
+
+        value[0][0] = name.getMethodName() + "-0-0";
+        value[0][1] = name.getMethodName() + "-0-1";
+        value[1][0] = name.getMethodName() + "-1-0";
+        value[1][1] = name.getMethodName() + "-1-1";
+
+        byte[] serialized = serializeObject(value);
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+             ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, ACCEPTS_NONE_FILTER)) {
+
+            try {
+                reader.readObject();
+                fail("Should not be able to read the payload.");
+            } catch (ClassNotFoundException ex) {}
+        }
+    }
+
+    @Test
+    public void testReadObjectFailsWithUntrustedType() throws Exception {
+        byte[] serialized = serializeObject(new SimplePojo(name.getMethodName()));
+
+        TrustedClassFilter myFilter = new TrustedClassFilter() {
+
+            @Override
+            public boolean isTrusted(Class<?> clazz) {
+                return !clazz.equals(SimplePojo.class);
+            }
+        };
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+             ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, myFilter)) {
+
+            try {
+                reader.readObject();
+                fail("Should not be able to read the payload.");
+            } catch (ClassNotFoundException ex) {}
+        }
+
+        serialized = serializeObject(UUID.randomUUID());
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+             ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, myFilter)) {
+
+            try {
+                reader.readObject();
+            } catch (ClassNotFoundException ex) {
+                fail("Should be able to read the payload.");
+            }
+        }
+    }
+
+    @Test
+    public void testReadObjectFailsWithUnstrustedContentInTrustedType() throws Exception {
+        byte[] serialized = serializeObject(new SimplePojo(UUID.randomUUID()));
+
+        TrustedClassFilter myFilter = new TrustedClassFilter() {
+
+            @Override
+            public boolean isTrusted(Class<?> clazz) {
+                return clazz.equals(SimplePojo.class);
+            }
+        };
+
+        ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+        try (ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, myFilter)) {
+            try {
+                reader.readObject();
+                fail("Should not be able to read the payload.");
+            } catch (ClassNotFoundException ex) {}
+        }
+
+        serialized = serializeObject(UUID.randomUUID());
+        input = new ByteArrayInputStream(serialized);
+        try (ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, myFilter)) {
+            try {
+                reader.readObject();
+                fail("Should not be able to read the payload.");
+            } catch (ClassNotFoundException ex) {
+            }
+        }
+    }
+
+    //----- Internal methods -------------------------------------------------//
+
+    private void doTestReadObject(Object value, TrustedClassFilter filter) throws Exception {
+        byte[] serialized = serializeObject(value);
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+             ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, filter)) {
+
+            Object result = reader.readObject();
+            assertNotNull(result);
+            assertEquals(value.getClass(), result.getClass());
+            if (result.getClass().isArray()) {
+                assertTrue(Arrays.deepEquals((Object[]) value, (Object[]) result));
+            } else {
+                assertEquals(value, result);
+            }
+        }
+    }
+
+    private byte[] serializeObject(Object value) throws IOException {
+        byte[] result = new byte[0];
+
+        if (value != null) {
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                 ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+
+                oos.writeObject(value);
+                oos.flush();
+                oos.close();
+
+                result = baos.toByteArray();
+            }
+        }
+
+        return result;
+    }
+
+    private void doTestReadPrimitive(Object value, TrustedClassFilter filter) throws Exception {
+        byte[] serialized = serializePrimitive(value);
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+             ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, filter)) {
+
+            Object result = null;
+
+            if (value instanceof Byte) {
+                result = reader.readByte();
+            } else if (value instanceof Short) {
+                result = reader.readShort();
+            } else if (value instanceof Integer) {
+                result = reader.readInt();
+            } else if (value instanceof Long) {
+                result = reader.readLong();
+            } else if (value instanceof Float) {
+                result = reader.readFloat();
+            } else if (value instanceof Double) {
+                result = reader.readDouble();
+            } else if (value instanceof Boolean) {
+                result = reader.readBoolean();
+            } else if (value instanceof Character) {
+                result = reader.readChar();
+            } else {
+                throw new IllegalArgumentException("unsuitable type for primitive deserialization");
+            }
+
+            assertNotNull(result);
+            assertEquals(value.getClass(), result.getClass());
+            assertEquals(value, result);
+        }
+    }
+
+    private void doTestReadPrimitiveArray(Object value, TrustedClassFilter filter) throws Exception {
+        byte[] serialized = serializeObject(value);
+
+        try (ByteArrayInputStream input = new ByteArrayInputStream(serialized);
+             ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, filter)) {
+
+            Object result = reader.readObject();
+
+            assertNotNull(result);
+            assertEquals(value.getClass(), result.getClass());
+            assertTrue(result.getClass().isArray());
+            assertEquals(value.getClass().getComponentType(), result.getClass().getComponentType());
+            assertTrue(result.getClass().getComponentType().isPrimitive());
+        }
+    }
+
+    private byte[] serializePrimitive(Object value) throws IOException {
+        byte[] result = new byte[0];
+
+        if (value != null) {
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                 ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+
+                if (value instanceof Byte) {
+                    oos.writeByte((byte) value);
+                } else if (value instanceof Short) {
+                    oos.writeShort((short) value);
+                } else if (value instanceof Integer) {
+                    oos.writeInt((int) value);
+                } else if (value instanceof Long) {
+                    oos.writeLong((long) value);
+                } else if (value instanceof Float) {
+                    oos.writeFloat((float) value);
+                } else if (value instanceof Double) {
+                    oos.writeDouble((double) value);
+                } else if (value instanceof Boolean) {
+                    oos.writeBoolean((boolean) value);
+                } else if (value instanceof Character) {
+                    oos.writeChar((char) value);
+                } else {
+                    throw new IllegalArgumentException("unsuitable type for primitive serialization");
+                }
+
+                oos.flush();
+                oos.close();
+
+                result = baos.toByteArray();
+            }
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/LocalSimplePojoParent.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/LocalSimplePojoParent.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/LocalSimplePojoParent.java
new file mode 100644
index 0000000..45c1bd0
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/LocalSimplePojoParent.java
@@ -0,0 +1,46 @@
+/*
+ * 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.qpid.jms.util;
+
+import java.io.Serializable;
+
+public class LocalSimplePojoParent implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private SimplePojo payload;
+
+    public LocalSimplePojoParent(Object simplePojoPayload) {
+        // Create an LOCAL simple payload, itself serializable, like we
+        // have to be since the object references us and is used
+        // during the serialization.
+
+        class LocalSimplPojo extends SimplePojo {
+            private static final long serialVersionUID = 1L;
+
+            LocalSimplPojo(Object simplePojoPayload) {
+                super(simplePojoPayload);
+            }
+        }
+
+        payload = new LocalSimplPojo(simplePojoPayload);
+    }
+
+    public SimplePojo getPayload() {
+        return payload;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/PropertyUtilTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/PropertyUtilTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/PropertyUtilTest.java
index 797f5ee..261b843 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/PropertyUtilTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/PropertyUtilTest.java
@@ -246,6 +246,17 @@ public class PropertyUtilTest {
     }
 
     @Test
+    public void testParseParametersFromStringWithNoValues() throws Exception {
+        Map<String, String> result = PropertyUtil.parseParameters("http://www.example.com?option=&another=");
+
+        assertTrue(result.size() == 2);
+        assertTrue(result.containsKey("option"));
+        assertTrue(result.containsKey("another"));
+        assertEquals("", result.get("option"));
+        assertEquals("", result.get("another"));
+    }
+
+    @Test
     public void testParseParametersFromURIStringWithNoQuery() throws Exception {
         Map<String, String> result = PropertyUtil.parseParameters("http://www.example.com");
         assertNotNull(result);

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/SimplePojo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/SimplePojo.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/SimplePojo.java
new file mode 100644
index 0000000..00598da
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/SimplePojo.java
@@ -0,0 +1,73 @@
+/*
+ * 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.qpid.jms.util;
+
+import java.io.Serializable;
+
+public class SimplePojo implements Serializable {
+
+    private static final long serialVersionUID = 3258560248864895099L;
+
+    private Object payload;
+
+    public SimplePojo() {
+    }
+
+    public SimplePojo(Object payload) {
+        this.payload = payload;
+    }
+
+    public Object getPayload() {
+        return payload;
+    }
+
+    public void setPayload(Object payload) {
+        this.payload = payload;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((payload == null) ? 0 : payload.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        SimplePojo other = (SimplePojo) obj;
+        if (payload == null) {
+            if (other.payload != null) {
+                return false;
+            }
+        } else if (!payload.equals(other.payload)) {
+            return false;
+        }
+
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
index b936b90..6495858 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
@@ -16,22 +16,28 @@
  */
 package org.apache.qpid.jms.util;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.HashMap;
 import java.util.Map;
 
-import junit.framework.TestCase;
-
 import org.apache.qpid.jms.util.URISupport.CompositeData;
+import org.junit.Test;
 
-public class URISupportTest extends TestCase {
+public class URISupportTest {
 
+    @Test
     public void testEmptyCompositePath() throws Exception {
         CompositeData data = URISupport.parseComposite(new URI("broker:()/localhost?persistent=false"));
         assertEquals(0, data.getComponents().size());
     }
 
+    @Test
     public void testCompositePath() throws Exception {
         CompositeData data = URISupport.parseComposite(new URI("test:(path)/path"));
         assertEquals("path", data.getPath());
@@ -39,17 +45,20 @@ public class URISupportTest extends TestCase {
         assertNull(data.getPath());
     }
 
+    @Test
     public void testSimpleComposite() throws Exception {
         CompositeData data = URISupport.parseComposite(new URI("test:part1"));
         assertEquals(1, data.getComponents().size());
     }
 
+    @Test
     public void testComposite() throws Exception {
         URI uri = new URI("test:(part1://host,part2://(sub1://part,sube2:part))");
         CompositeData data = URISupport.parseComposite(uri);
         assertEquals(2, data.getComponents().size());
     }
 
+    @Test
     public void testEmptyCompositeWithParenthesisInParam() throws Exception {
         URI uri = new URI("failover://()?updateURIsURL=file:/C:/Dir(1)/a.csv");
         CompositeData data = URISupport.parseComposite(uri);
@@ -59,6 +68,7 @@ public class URISupportTest extends TestCase {
         assertEquals("file:/C:/Dir(1)/a.csv", data.getParameters().get("updateURIsURL"));
     }
 
+    @Test
     public void testCompositeWithParenthesisInParam() throws Exception {
         URI uri = new URI("failover://(test)?updateURIsURL=file:/C:/Dir(1)/a.csv");
         CompositeData data = URISupport.parseComposite(uri);
@@ -68,6 +78,7 @@ public class URISupportTest extends TestCase {
         assertEquals("file:/C:/Dir(1)/a.csv", data.getParameters().get("updateURIsURL"));
     }
 
+    @Test
     public void testCompositeWithComponentParam() throws Exception {
         CompositeData data = URISupport.parseComposite(new URI("test:(part1://host?part1=true)?outside=true"));
         assertEquals(1, data.getComponents().size());
@@ -77,6 +88,7 @@ public class URISupportTest extends TestCase {
         assertTrue(part1Params.containsKey("part1"));
     }
 
+    @Test
     public void testParsingURI() throws Exception {
         URI source = new URI("tcp://localhost:61626/foo/bar?cheese=Edam&x=123");
 
@@ -91,16 +103,33 @@ public class URISupportTest extends TestCase {
         assertEquals("result", new URI("tcp://localhost:61626/foo/bar"), result);
     }
 
+    @Test
+    public void testParsingURIWithEmptyValuesInOptions() throws Exception {
+        URI source = new URI("tcp://localhost:61626/foo/bar?cheese=&x=");
+
+        Map<String, String> map = PropertyUtil.parseParameters(source);
+
+        assertEquals("Size: " + map, 2, map.size());
+        assertMapKey(map, "cheese", "");
+        assertMapKey(map, "x", "");
+
+        URI result = URISupport.removeQuery(source);
+
+        assertEquals("result", new URI("tcp://localhost:61626/foo/bar"), result);
+    }
+
     protected void assertMapKey(Map<String, String> map, String key, Object expected) {
         assertEquals("Map key: " + key, map.get(key), expected);
     }
 
+    @Test
     public void testParsingCompositeURI() throws URISyntaxException {
         CompositeData data = URISupport.parseComposite(new URI("broker://(tcp://localhost:61616)?name=foo"));
         assertEquals("one component", 1, data.getComponents().size());
         assertEquals("Size: " + data.getParameters(), 1, data.getParameters().size());
     }
 
+    @Test
     public void testCheckParenthesis() throws Exception {
         String str = "fred:(((ddd))";
         assertFalse(URISupport.checkParenthesis(str));
@@ -108,6 +137,7 @@ public class URISupportTest extends TestCase {
         assertTrue(URISupport.checkParenthesis(str));
     }
 
+    @Test
     public void testCreateWithQuery() throws Exception {
         URI source = new URI("vm://localhost");
         URI dest = PropertyUtil.replaceQuery(source, "network=true&one=two");
@@ -118,6 +148,7 @@ public class URISupportTest extends TestCase {
         assertFalse("same uri, ssp", dest.getQuery().equals(source.getQuery()));
     }
 
+    @Test
     public void testParsingParams() throws Exception {
         URI uri = new URI("static:(http://localhost:61617?proxyHost=jo&proxyPort=90)?proxyHost=localhost&proxyPort=80");
         Map<String,String>parameters = URISupport.parseParameters(uri);
@@ -129,6 +160,7 @@ public class URISupportTest extends TestCase {
         parameters = URISupport.parseParameters(uri);
     }
 
+    @Test
     public void testCompositeCreateURIWithQuery() throws Exception {
         String queryString = "query=value";
         URI originalURI = new URI("outerscheme:(innerscheme:innerssp)");
@@ -151,6 +183,7 @@ public class URISupportTest extends TestCase {
         assertEquals(new URI(querylessURI + "?" + queryString), PropertyUtil.replaceQuery(originalURI, queryString));
     }
 
+    @Test
     public void testApplyParameters() throws Exception {
 
         URI uri = new URI("http://0.0.0.0:61616");
@@ -178,6 +211,7 @@ public class URISupportTest extends TestCase {
         assertEquals(parameters.get("proxyPort"), "80");
     }
 
+    @Test
     public void testIsCompositeURIWithQueryNoSlashes() throws URISyntaxException {
         URI[] compositeURIs = new URI[] { new URI("test:(part1://host?part1=true)?outside=true"), new URI("broker:(tcp://localhost:61616)?name=foo") };
         for (URI uri : compositeURIs) {
@@ -185,6 +219,7 @@ public class URISupportTest extends TestCase {
         }
     }
 
+    @Test
     public void testIsCompositeURIWithQueryAndSlashes() throws URISyntaxException {
         URI[] compositeURIs = new URI[] { new URI("test://(part1://host?part1=true)?outside=true"), new URI("broker://(tcp://localhost:61616)?name=foo") };
         for (URI uri : compositeURIs) {
@@ -192,6 +227,7 @@ public class URISupportTest extends TestCase {
         }
     }
 
+    @Test
     public void testIsCompositeURINoQueryNoSlashes() throws URISyntaxException {
         URI[] compositeURIs = new URI[] { new URI("test:(part1://host,part2://(sub1://part,sube2:part))"), new URI("test:(path)/path") };
         for (URI uri : compositeURIs) {
@@ -199,10 +235,12 @@ public class URISupportTest extends TestCase {
         }
     }
 
+    @Test
     public void testIsCompositeURINoQueryNoSlashesNoParentheses() throws URISyntaxException {
         assertFalse("test:part1" + " must be detected as non-composite URI", URISupport.isCompositeURI(new URI("test:part1")));
     }
 
+    @Test
     public void testIsCompositeURINoQueryWithSlashes() throws URISyntaxException {
         URI[] compositeURIs = new URI[] { new URI("failover://(tcp://bla:61616,tcp://bla:61617)"),
                 new URI("failover://(tcp://localhost:61616,ssl://anotherhost:61617)") };
@@ -210,5 +248,4 @@ public class URISupportTest extends TestCase {
             assertTrue(uri + " must be detected as composite URI", URISupport.isCompositeURI(uri));
         }
     }
-
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-docs/Configuration.md
----------------------------------------------------------------------
diff --git a/qpid-jms-docs/Configuration.md b/qpid-jms-docs/Configuration.md
index 6e04a6b..6ff5820 100644
--- a/qpid-jms-docs/Configuration.md
+++ b/qpid-jms-docs/Configuration.md
@@ -99,7 +99,7 @@ The options apply to the behaviour of the JMS objects such as Connection, Sessio
 + **jms.connectionIDPrefix** Optional prefix value that is used for generated Connection ID values when a new Connection is created for the JMS ConnectionFactory.  This connection ID is used when logging some information from the JMS Connection object so a configurable prefix can make breadcrumbing the logs easier.  The default prefix is 'ID:'.
 + **jms.populateJMSXUserID** Controls whether a MessageProducer will populate the JMSXUserID value for each sent message using the authenticated username from the connection.  This value defaults to false and the JMSXUserID for all sent message will not be populated.
 
-These values control how many messages the remote peer can send to the client and be held in a prefetch buffer for each consumer instance.
+The Prefetch Policy controls how many messages the remote peer can send to the client and be held in a prefetch buffer for each consumer instance.
 
 + **jms.prefetchPolicy.queuePrefetch** defaults to 1000
 + **jms.prefetchPolicy.topicPrefetch** defaults to 1000
@@ -107,7 +107,7 @@ These values control how many messages the remote peer can send to the client an
 + **jms.prefetchPolicy.durableTopicPrefetch** defaults to 1000
 + **jms.prefetchPolicy.all** used to set all prefetch values at once.
 
-The RedeliveryPolicy controls how redelivered messages are handled on the client.
+The Redelivery Policy controls how redelivered messages are handled on the client.
 
 + **jms.redeliveryPolicy.maxRedeliveries** controls when an incoming message is rejected based on the number of times it has been redelivered, the default value is (-1) disabled.  A value of zero would indicate no message redeliveries are accepted, a value of five would allow a message to be redelivered five times, etc.
 
@@ -115,7 +115,7 @@ The MessageID Policy controls the type of the Message ID assigned to messages se
 
 + **jms.messageIDPolicy.messageIDType** By default a generated String value is used for the MessageID on outgoing messages. Other available types are UUID and UUID_STRING.
 
-The PresettlePolicy controls when a producer or consumer instance will be configured to use AMQP presettled messaging semantics.
+The Presettle Policy controls when a producer or consumer instance will be configured to use AMQP presettled messaging semantics.
 
 + **jms.presettlePolicy.presettleAll** when true all producers and non-transacted consumers created operate in presettled mode, defaults to false.
 + **jms.presettlePolicy.presettleProducers** when true all producers operate in presettled mode, defaults to false.
@@ -126,6 +126,11 @@ The PresettlePolicy controls when a producer or consumer instance will be config
 + **jms.presettlePolicy.presettleTopicConsumers** when true any consumer that is receiving from a Topic or Temporary Topic destination will operate in presettled mode, defaults to false.
 + **jms.presettlePolicy.presettleQueueConsumers** when true any consumer that is receiving from a Queue or Temporary Queue destination will operate in presettled mode, defaults to false.
 
+The Deserialization Policy provides a means of controlling which types are trusted to be deserialized from the object stream while retrieving the body from an incoming JMS ObjectMessage composed of serialized Java Object content. By default all types are trusted during attempt to deserialize the body. The default Deserialization Policy object provides URI options that allow specifying a whitelist and a blacklist of Java class or package names.
+
+**jms.deserializationPolicy.whiteList** A comma separated list of class/package names that should be allowed when deserializing the contents of a JMS ObjectMessage, unless overridden by the blackList. The names in this list are not pattern values, the exact class or package name must be configured, e.g "java.util.Map" or "java.util". Package matches include sub-packages. Default is to allow all.
+**jms.deserializationPolicy.blackList** A comma separated list of class/package names that should be rejected when deserializing the contents of a JMS ObjectMessage. The names in this list are not pattern values, the exact class or package name must be configured, e.g "java.util.Map" or "java.util". Package matches include sub-packages. Default is to prevent none.
+
 ### TCP Transport Configuration options
 
 When connected to a remote using plain TCP these options configure the behaviour of the underlying socket.  These options are appended to the connection URI along with the other configuration options, for example:


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[2/2] qpid-jms git commit: QPIDJMS-188 Further improvements to the ObjectMessage handling.

Posted by ta...@apache.org.
QPIDJMS-188 Further improvements to the ObjectMessage handling.

Project: http://git-wip-us.apache.org/repos/asf/qpid-jms/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-jms/commit/669cfff8
Tree: http://git-wip-us.apache.org/repos/asf/qpid-jms/tree/669cfff8
Diff: http://git-wip-us.apache.org/repos/asf/qpid-jms/diff/669cfff8

Branch: refs/heads/master
Commit: 669cfff838d2798fa89b9db546823e6245433d4e
Parents: b05d577
Author: Timothy Bish <ta...@gmail.com>
Authored: Mon Jun 27 11:31:44 2016 -0400
Committer: Timothy Bish <ta...@gmail.com>
Committed: Mon Jun 27 11:31:44 2016 -0400

----------------------------------------------------------------------
 .../java/org/apache/qpid/jms/JmsConnection.java |   9 +
 .../apache/qpid/jms/JmsConnectionFactory.java   |  23 +
 .../org/apache/qpid/jms/JmsMessageConsumer.java |   3 +
 .../java/org/apache/qpid/jms/JmsSession.java    |   6 +
 .../apache/qpid/jms/meta/JmsConnectionInfo.java |  15 +
 .../apache/qpid/jms/meta/JmsConsumerInfo.java   |  15 +
 .../apache/qpid/jms/meta/JmsSessionInfo.java    |  15 +
 .../policy/JmsDefaultDeserializationPolicy.java | 244 ++++++++
 .../jms/policy/JmsDeserializationPolicy.java    |  45 ++
 .../amqp/message/AmqpJmsMessageFacade.java      |   4 +
 .../amqp/message/AmqpJmsMessageFactory.java     |   3 +-
 .../message/AmqpJmsObjectMessageFacade.java     |  31 +-
 .../amqp/message/AmqpObjectTypeDelegate.java    |  10 +
 .../message/AmqpSerializedObjectDelegate.java   |  59 +-
 .../amqp/message/AmqpTypedObjectDelegate.java   |  58 +-
 .../ClassLoadingAwareObjectInputStream.java     |  57 +-
 .../qpid/jms/JmsConnectionFactoryTest.java      |  75 ++-
 .../ObjectMessageIntegrationTest.java           | 125 +++-
 .../facade/test/JmsTestObjectMessageFacade.java |   2 +-
 .../JmsDefaultDeserializationPolicyTest.java    | 328 +++++++++++
 .../amqp/message/AmqpJmsMessageBuilderTest.java |   5 +
 .../amqp/message/AmqpJmsMessageFactoryTest.java |  11 +-
 .../message/AmqpJmsMessageTypesTestCase.java    |  15 +-
 .../jms/util/AnonymousSimplePojoParent.java     |  39 ++
 .../ClassLoadingAwareObjectInputStreamTest.java | 569 +++++++++++++++++++
 .../qpid/jms/util/LocalSimplePojoParent.java    |  46 ++
 .../apache/qpid/jms/util/PropertyUtilTest.java  |  11 +
 .../org/apache/qpid/jms/util/SimplePojo.java    |  73 +++
 .../apache/qpid/jms/util/URISupportTest.java    |  45 +-
 qpid-jms-docs/Configuration.md                  |  11 +-
 30 files changed, 1897 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
index 7375c3f..827da11 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
@@ -66,6 +66,7 @@ import org.apache.qpid.jms.meta.JmsSessionId;
 import org.apache.qpid.jms.meta.JmsSessionInfo;
 import org.apache.qpid.jms.meta.JmsTransactionId;
 import org.apache.qpid.jms.meta.JmsTransactionInfo;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
 import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -873,6 +874,14 @@ public class JmsConnection implements AutoCloseable, Connection, TopicConnection
         connectionInfo.setPresettlePolicy(presettlePolicy);
     }
 
+    public JmsDeserializationPolicy getDeserializationPolicy() {
+        return connectionInfo.getDeserializationPolicy();
+    }
+
+    public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+        connectionInfo.setDeserializationPolicy(deserializationPolicy);
+    }
+
     public boolean isReceiveLocalOnly() {
         return connectionInfo.isReceiveLocalOnly();
     }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
index 32cb39a..0f2c1ba 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
@@ -35,10 +35,12 @@ import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
 import org.apache.qpid.jms.jndi.JNDIStorable;
 import org.apache.qpid.jms.message.JmsMessageIDBuilder;
 import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultMessageIDPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultPresettlePolicy;
 import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
 import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -96,6 +98,7 @@ public class JmsConnectionFactory extends JNDIStorable implements ConnectionFact
     private JmsRedeliveryPolicy redeliveryPolicy = new JmsDefaultRedeliveryPolicy();
     private JmsPresettlePolicy presettlePolicy = new JmsDefaultPresettlePolicy();
     private JmsMessageIDPolicy messageIDPolicy = new JmsDefaultMessageIDPolicy();
+    private JmsDeserializationPolicy deserializationPolicy = new JmsDefaultDeserializationPolicy();
 
     public JmsConnectionFactory() {
     }
@@ -580,6 +583,26 @@ public class JmsConnectionFactory extends JNDIStorable implements ConnectionFact
     }
 
     /**
+     * @return the deserializationPolicy that is currently configured.
+     */
+    public JmsDeserializationPolicy getDeserializationPolicy() {
+        return deserializationPolicy;
+    }
+
+    /**
+     * Sets the JmsDeserializationPolicy that is applied when a new connection is created.
+     *
+     * @param deserializationPolicy
+     *      the deserializationPolicy that will be applied to new connections.
+     */
+    public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+        if (deserializationPolicy == null) {
+            deserializationPolicy = new JmsDefaultDeserializationPolicy();
+        }
+        this.deserializationPolicy = deserializationPolicy;
+    }
+
+    /**
      * @return the currently configured client ID prefix for auto-generated client IDs.
      */
     public synchronized String getClientIDPrefix() {

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
index d797918..893a576 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
@@ -34,6 +34,7 @@ import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
 import org.apache.qpid.jms.message.JmsMessage;
 import org.apache.qpid.jms.meta.JmsConsumerId;
 import org.apache.qpid.jms.meta.JmsConsumerInfo;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsRedeliveryPolicy;
 import org.apache.qpid.jms.provider.Provider;
@@ -88,6 +89,7 @@ public class JmsMessageConsumer implements AutoCloseable, MessageConsumer, JmsMe
 
         JmsPrefetchPolicy prefetchPolicy = session.getPrefetchPolicy();
         JmsRedeliveryPolicy redeliveryPolicy = session.getRedeliveryPolicy().copy();
+        JmsDeserializationPolicy deserializationPolicy = session.getDeserializationPolicy().copy();
 
         consumerInfo = new JmsConsumerInfo(consumerId);
         consumerInfo.setClientId(connection.getClientID());
@@ -102,6 +104,7 @@ public class JmsMessageConsumer implements AutoCloseable, MessageConsumer, JmsMe
         consumerInfo.setRedeliveryPolicy(redeliveryPolicy);
         consumerInfo.setLocalMessageExpiry(connection.isLocalMessageExpiry());
         consumerInfo.setPresettle(session.getPresettlePolicy().isConsumerPresttled(session, destination));
+        consumerInfo.setDeserializationPolicy(deserializationPolicy);
 
         session.getConnection().createResource(consumerInfo);
     }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
index ff28e59..b8aded8 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
@@ -68,6 +68,7 @@ import org.apache.qpid.jms.meta.JmsProducerId;
 import org.apache.qpid.jms.meta.JmsProducerInfo;
 import org.apache.qpid.jms.meta.JmsSessionId;
 import org.apache.qpid.jms.meta.JmsSessionInfo;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
 import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -123,6 +124,7 @@ public class JmsSession implements AutoCloseable, Session, QueueSession, TopicSe
         sessionInfo.setPrefetchPolicy(connection.getPrefetchPolicy().copy());
         sessionInfo.setPresettlePolicy(connection.getPresettlePolicy().copy());
         sessionInfo.setRedeliveryPolicy(connection.getRedeliveryPolicy().copy());
+        sessionInfo.setDeserializationPolicy(connection.getDeserializationPolicy());
 
         connection.createResource(sessionInfo);
 
@@ -942,6 +944,10 @@ public class JmsSession implements AutoCloseable, Session, QueueSession, TopicSe
         return sessionInfo.getRedeliveryPolicy();
     }
 
+    public JmsDeserializationPolicy getDeserializationPolicy() {
+        return sessionInfo.getDeserializationPolicy();
+    }
+
     @Override
     public void onInboundMessage(JmsInboundMessageDispatch envelope) {
         if (started.get()) {

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
index b98af14..bc723c0 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
@@ -19,10 +19,12 @@ package org.apache.qpid.jms.meta;
 import java.net.URI;
 import java.nio.charset.Charset;
 
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultMessageIDPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultPresettlePolicy;
 import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
 import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -67,6 +69,7 @@ public final class JmsConnectionInfo implements JmsResource, Comparable<JmsConne
     private JmsRedeliveryPolicy redeliveryPolicy;
     private JmsPresettlePolicy presettlePolicy;
     private JmsMessageIDPolicy messageIDPolicy;
+    private JmsDeserializationPolicy deserializationPolicy;
 
     private volatile byte[] encodedUserId;
 
@@ -101,6 +104,7 @@ public final class JmsConnectionInfo implements JmsResource, Comparable<JmsConne
         copy.prefetchPolicy = getPrefetchPolicy().copy();
         copy.redeliveryPolicy = getRedeliveryPolicy().copy();
         copy.presettlePolicy = getPresettlePolicy().copy();
+        copy.deserializationPolicy = getDeserializationPolicy().copy();
     }
 
     public boolean isForceAsyncSend() {
@@ -320,6 +324,17 @@ public final class JmsConnectionInfo implements JmsResource, Comparable<JmsConne
         return encodedUserId;
     }
 
+    public JmsDeserializationPolicy getDeserializationPolicy() {
+        if (deserializationPolicy == null) {
+            deserializationPolicy = new JmsDefaultDeserializationPolicy();
+        }
+        return deserializationPolicy;
+    }
+
+    public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+        this.deserializationPolicy = deserializationPolicy;
+    }
+
     @Override
     public String toString() {
         return "JmsConnectionInfo { " + getId() +

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
index ab72d7c..dd34397 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
@@ -17,7 +17,9 @@
 package org.apache.qpid.jms.meta;
 
 import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsRedeliveryPolicy;
 
 public final class JmsConsumerInfo implements JmsResource, Comparable<JmsConsumerInfo> {
@@ -35,6 +37,7 @@ public final class JmsConsumerInfo implements JmsResource, Comparable<JmsConsume
     private boolean presettle;
 
     private JmsRedeliveryPolicy redeliveryPolicy;
+    private JmsDeserializationPolicy deserializationPolicy;
 
     // Can be used to track the last consumed message.
     private transient long lastDeliveredSequenceId;
@@ -71,6 +74,7 @@ public final class JmsConsumerInfo implements JmsResource, Comparable<JmsConsume
         info.acknowledgementMode = acknowledgementMode;
         info.lastDeliveredSequenceId = lastDeliveredSequenceId;
         info.redeliveryPolicy = getRedeliveryPolicy().copy();
+        info.deserializationPolicy = getDeserializationPolicy().copy();
     }
 
     public boolean isDurable() {
@@ -177,6 +181,17 @@ public final class JmsConsumerInfo implements JmsResource, Comparable<JmsConsume
         this.redeliveryPolicy = redeliveryPolicy;
     }
 
+    public JmsDeserializationPolicy getDeserializationPolicy() {
+        if (deserializationPolicy == null) {
+            deserializationPolicy = new JmsDefaultDeserializationPolicy();
+        }
+        return deserializationPolicy;
+    }
+
+    public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+        this.deserializationPolicy = deserializationPolicy;
+    }
+
     public boolean isPresettle() {
         return presettle;
     }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
index 6e87480..1b7c3da 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
@@ -18,10 +18,12 @@ package org.apache.qpid.jms.meta;
 
 import javax.jms.Session;
 
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultMessageIDPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultPresettlePolicy;
 import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsMessageIDPolicy;
 import org.apache.qpid.jms.policy.JmsPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsPresettlePolicy;
@@ -37,6 +39,7 @@ public final class JmsSessionInfo implements JmsResource, Comparable<JmsSessionI
     private JmsPrefetchPolicy prefetchPolicy;
     private JmsPresettlePolicy presettlePolicy;
     private JmsRedeliveryPolicy redeliveryPolicy;
+    private JmsDeserializationPolicy deserializationPolicy;
 
     public JmsSessionInfo(JmsConnectionInfo connectionInfo, long sessionId) {
         if (connectionInfo == null) {
@@ -66,6 +69,7 @@ public final class JmsSessionInfo implements JmsResource, Comparable<JmsSessionI
         copy.presettlePolicy = getPresettlePolicy().copy();
         copy.prefetchPolicy = getPrefetchPolicy().copy();
         copy.messageIDPolicy = getMessageIDPolicy().copy();
+        copy.deserializationPolicy = getDeserializationPolicy().copy();
     }
 
     @Override
@@ -172,4 +176,15 @@ public final class JmsSessionInfo implements JmsResource, Comparable<JmsSessionI
     public void setRedeliveryPolicy(JmsRedeliveryPolicy redeliveryPolicy) {
         this.redeliveryPolicy = redeliveryPolicy;
     }
+
+    public JmsDeserializationPolicy getDeserializationPolicy() {
+        if (deserializationPolicy == null) {
+            deserializationPolicy = new JmsDefaultDeserializationPolicy();
+        }
+        return deserializationPolicy;
+    }
+
+    public void setDeserializationPolicy(JmsDeserializationPolicy deserializationPolicy) {
+        this.deserializationPolicy = deserializationPolicy;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicy.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicy.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicy.java
new file mode 100644
index 0000000..2bcbed4
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicy.java
@@ -0,0 +1,244 @@
+/*
+ * 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.qpid.jms.policy;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.qpid.jms.JmsDestination;
+
+/**
+ * Default implementation of the deserialization policy that can read white and black list of
+ * classes/packages from the environment, and be updated by the connection uri options.
+ *
+ * The policy reads a default blackList string value (comma separated) from the system property
+ * {@value #BLACKLIST_PROPERTY} which defaults to null which indicates an empty blacklist.
+ *
+ * The policy reads a default whitelist string value (comma separated) from the system property
+ * {@value #WHITELIST_PROPERTY} which defaults to a {@value #CATCH_ALL_WILDCARD} which
+ * indicates that all classes are whitelisted.
+ *
+ * The blacklist overrides the whitelist, entries that could match both are counted as blacklisted.
+ *
+ * If the policy should treat all classes as untrusted the blacklist should be set to
+ * {@value #CATCH_ALL_WILDCARD}".
+ */
+public class JmsDefaultDeserializationPolicy implements JmsDeserializationPolicy {
+
+    /**
+     * Value used to indicate that all classes should be white or black listed,
+     */
+    public static final String CATCH_ALL_WILDCARD = "*";
+
+    public static final String WHITELIST_PROPERTY = "org.apache.qpid.jms.deserialization.white_list";
+    public static final String BLACKLIST_PROPERTY = "org.apache.qpid.jms.deserialization.black_list";
+
+    private List<String> whiteList = new ArrayList<String>();
+    private List<String> blackList = new ArrayList<String>();
+
+    /**
+     * Creates an instance of this policy with default configuration.
+     */
+    public JmsDefaultDeserializationPolicy() {
+        String whitelist = System.getProperty(WHITELIST_PROPERTY, CATCH_ALL_WILDCARD);
+        setWhiteList(whitelist);
+
+        String blackList = System.getProperty(BLACKLIST_PROPERTY);
+        setBlackList(blackList);
+    }
+
+    /**
+     * @param source
+     *      The instance whose configuration should be copied from.
+     */
+    public JmsDefaultDeserializationPolicy(JmsDefaultDeserializationPolicy source) {
+        this.whiteList.addAll(source.whiteList);
+        this.blackList.addAll(source.blackList);
+    }
+
+    @Override
+    public JmsDeserializationPolicy copy() {
+        return new JmsDefaultDeserializationPolicy(this);
+    }
+
+    @Override
+    public boolean isTrustedType(JmsDestination destination, Class<?> clazz) {
+        if (clazz == null) {
+            return true;
+        }
+
+        String className = clazz.getCanonicalName();
+        if (className == null) {
+            // Shouldn't happen as we pre-processed things, but just in case..
+            className = clazz.getName();
+        }
+
+        for (String blackListEntry : blackList) {
+            if (CATCH_ALL_WILDCARD.equals(blackListEntry)) {
+                return false;
+            } else if (isClassOrPackageMatch(className, blackListEntry)) {
+                return false;
+            }
+        }
+
+        for (String whiteListEntry : whiteList) {
+            if (CATCH_ALL_WILDCARD.equals(whiteListEntry)) {
+                return true;
+            } else if (isClassOrPackageMatch(className, whiteListEntry)) {
+                return true;
+            }
+        }
+
+        // Failing outright rejection or allow from above, reject.
+        return false;
+    }
+
+    private final boolean isClassOrPackageMatch(String className, String listEntry) {
+        if (className == null) {
+            return false;
+        }
+
+        // Check if class is an exact match of the entry
+        if (className.equals(listEntry)) {
+            return true;
+        }
+
+        // Check if class is from a [sub-]package matching the entry
+        int entryLength = listEntry.length();
+        if (className.length() > entryLength && className.startsWith(listEntry) && '.' == className.charAt(entryLength)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @return the whiteList configured on this policy instance.
+     */
+    public String getWhiteList() {
+        Iterator<String> entries = whiteList.iterator();
+        StringBuilder builder = new StringBuilder();
+
+        while (entries.hasNext()) {
+            builder.append(entries.next());
+            if (entries.hasNext()) {
+                builder.append(",");
+            }
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * @return the blackList configured on this policy instance.
+     */
+    public String getBlackList() {
+        Iterator<String> entries = blackList.iterator();
+        StringBuilder builder = new StringBuilder();
+
+        while (entries.hasNext()) {
+            builder.append(entries.next());
+            if (entries.hasNext()) {
+                builder.append(",");
+            }
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * Replaces the currently configured whiteList with a comma separated
+     * string containing the new whiteList. Null or empty string denotes
+     * no whiteList entries, {@value #CATCH_ALL_WILDCARD} indicates that
+     * all classes are whiteListed.
+     *
+     * @param whiteList
+     *      the whiteList that this policy is configured to recognize.
+     */
+    public void setWhiteList(String whiteList) {
+        ArrayList<String> list = new ArrayList<String>();
+        if (whiteList != null && !whiteList.isEmpty()) {
+            list.addAll(Arrays.asList(whiteList.split(",")));
+        }
+
+        this.whiteList = list;
+    }
+
+    /**
+     * Replaces the currently configured blackList with a comma separated
+     * string containing the new blackList. Null or empty string denotes
+     * no blacklist entries, {@value #CATCH_ALL_WILDCARD} indicates that
+     * all classes are blacklisted.
+     *
+     * @param blackList
+     *      the blackList that this policy is configured to recognize.
+     */
+    public void setBlackList(String blackList) {
+        ArrayList<String> list = new ArrayList<String>();
+        if (blackList != null && !blackList.isEmpty()) {
+            list.addAll(Arrays.asList(blackList.split(",")));
+        }
+
+        this.blackList = list;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((whiteList == null) ? 0 : whiteList.hashCode());
+        result = prime * result + ((blackList == null) ? 0 : blackList.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        JmsDefaultDeserializationPolicy other = (JmsDefaultDeserializationPolicy) obj;
+
+        if (whiteList == null) {
+            if (other.whiteList != null) {
+                return false;
+            }
+        } else if (!whiteList.equals(other.whiteList)) {
+            return false;
+        }
+
+        if (blackList == null) {
+            if (other.blackList != null) {
+                return false;
+            }
+        } else if (!blackList.equals(other.blackList)) {
+            return false;
+        }
+
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDeserializationPolicy.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDeserializationPolicy.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDeserializationPolicy.java
new file mode 100644
index 0000000..bb70947
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/policy/JmsDeserializationPolicy.java
@@ -0,0 +1,45 @@
+/*
+ * 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.qpid.jms.policy;
+
+import javax.jms.ObjectMessage;
+
+import org.apache.qpid.jms.JmsDestination;
+
+/**
+ * Defines the interface for a policy object that controls what types of message
+ * content are permissible when the body of an incoming ObjectMessage is being
+ * deserialized.
+ */
+public interface JmsDeserializationPolicy {
+
+    JmsDeserializationPolicy copy();
+
+    /**
+     * Returns whether the given class is a trusted type and can be deserialized
+     * by the client when calls to {@link ObjectMessage#getObject()} are made.
+     *
+     * @param destination
+     *      the Destination for the message containing the type to be deserialized.
+     * @param clazz
+     *      the Type of the object that is about to be read.
+     *
+     * @return true if the type is trusted or false if not.
+     */
+    boolean isTrustedType(JmsDestination destination, Class<?> clazz);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
index a739999..ff36db7 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
@@ -857,6 +857,10 @@ public class AmqpJmsMessageFacade implements JmsMessageFacade {
         this.message.setReplyTo(address);
     }
 
+    JmsDestination getConsumerDestination() {
+        return this.consumerDestination;
+    }
+
     private Long getAbsoluteExpiryTime() {
         Long result = null;
         if (message.getProperties() != null) {

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
index e0cc8c4..5b78556 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
@@ -95,7 +95,8 @@ public class AmqpJmsMessageFactory implements JmsMessageFactory {
 
     @Override
     public JmsObjectMessage createObjectMessage(Serializable payload) throws JMSException {
-        JmsObjectMessageFacade facade = new AmqpJmsObjectMessageFacade(connection, connection.isObjectMessageUsesAmqpTypes());
+        JmsObjectMessageFacade facade = new AmqpJmsObjectMessageFacade(
+            connection, connection.isObjectMessageUsesAmqpTypes());
 
         if (payload != null) {
             try {

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
index 4db872a..fabefed 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
@@ -26,6 +26,7 @@ import javax.jms.JMSException;
 
 import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
 import org.apache.qpid.jms.message.facade.JmsObjectMessageFacade;
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
 import org.apache.qpid.jms.provider.amqp.AmqpConnection;
 import org.apache.qpid.jms.provider.amqp.AmqpConsumer;
 import org.apache.qpid.proton.message.Message;
@@ -40,8 +41,10 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
 
     private AmqpObjectTypeDelegate delegate;
 
+    private final JmsDeserializationPolicy deserializationPolicy;
+
     /**
-     * Creates a new facade instance
+     * Creates a new facade instance for outgoing message
      *
      * @param connection
      *        the AmqpConnection that under which this facade was created.
@@ -49,9 +52,14 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
      *        controls the type used to encode the body.
      */
     public AmqpJmsObjectMessageFacade(AmqpConnection connection, boolean isAmqpTypeEncoded) {
+        this(connection, isAmqpTypeEncoded, null);
+    }
+
+    private AmqpJmsObjectMessageFacade(AmqpConnection connection, boolean isAmqpTypeEncoded, JmsDeserializationPolicy deserializationPolicy) {
         super(connection);
-        setMessageAnnotation(JMS_MSG_TYPE, JMS_OBJECT_MESSAGE);
+        this.deserializationPolicy = deserializationPolicy;
 
+        setMessageAnnotation(JMS_MSG_TYPE, JMS_OBJECT_MESSAGE);
         initDelegate(isAmqpTypeEncoded, null);
     }
 
@@ -68,6 +76,7 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
      */
     public AmqpJmsObjectMessageFacade(AmqpConsumer consumer, Message message, ByteBuf messageBytes) {
         super(consumer, message);
+        deserializationPolicy = consumer.getResourceInfo().getDeserializationPolicy();
 
         boolean javaSerialized = AmqpMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE.equals(message.getContentType());
         initDelegate(!javaSerialized, messageBytes);
@@ -87,15 +96,13 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
 
     @Override
     public AmqpJmsObjectMessageFacade copy() throws JMSException {
-        AmqpJmsObjectMessageFacade copy = new AmqpJmsObjectMessageFacade(connection, isAmqpTypedEncoding());
+        AmqpJmsObjectMessageFacade copy = new AmqpJmsObjectMessageFacade(connection, isAmqpTypedEncoding(), deserializationPolicy);
         copyInto(copy);
-
         try {
-            copy.setObject(getObject());
-        } catch (Exception e) {
-            throw JmsExceptionSupport.create("Failed to copy object value", e);
+            delegate.copyInto(copy.delegate);
+        } catch (Exception ex) {
+            throw JmsExceptionSupport.create(ex);
         }
-
         return copy;
     }
 
@@ -130,9 +137,9 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
 
                 AmqpObjectTypeDelegate newDelegate = null;
                 if (useAmqpTypedEncoding) {
-                    newDelegate = new AmqpTypedObjectDelegate(message, null);
+                    newDelegate = new AmqpTypedObjectDelegate(this, null);
                 } else {
-                    newDelegate = new AmqpSerializedObjectDelegate(message, null);
+                    newDelegate = new AmqpSerializedObjectDelegate(this, null, deserializationPolicy);
                 }
 
                 newDelegate.setObject(existingObject);
@@ -146,9 +153,9 @@ public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements
 
     private void initDelegate(boolean useAmqpTypes, ByteBuf messageBytes) {
         if (!useAmqpTypes) {
-            delegate = new AmqpSerializedObjectDelegate(getAmqpMessage(), messageBytes);
+            delegate = new AmqpSerializedObjectDelegate(this, messageBytes, deserializationPolicy);
         } else {
-            delegate = new AmqpTypedObjectDelegate(getAmqpMessage(), messageBytes);
+            delegate = new AmqpTypedObjectDelegate(this, messageBytes);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
index d14ff93..7657343 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
@@ -53,5 +53,15 @@ public interface AmqpObjectTypeDelegate {
      */
     void onSend();
 
+    /**
+     * Copy the internal data into the given instance.
+     *
+     * @param copy
+     *      the new delegate that will receive a copy of this instances object data.
+     *
+     * @throws Exception if an error occurs while copying the contents to the target.
+     */
+    void copyInto(AmqpObjectTypeDelegate copy) throws Exception;
+
     boolean isAmqpTypeEncoded();
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
index 546060b..618d123 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
@@ -26,7 +26,9 @@ import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.apache.qpid.jms.policy.JmsDeserializationPolicy;
 import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream;
+import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream.TrustedClassFilter;
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.messaging.Data;
 import org.apache.qpid.proton.amqp.messaging.Section;
@@ -38,7 +40,7 @@ import io.netty.buffer.ByteBuf;
  * Wrapper around an AMQP Message instance that will be treated as a JMS ObjectMessage
  * type.
  */
-public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
+public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate, TrustedClassFilter {
 
     static final Data NULL_OBJECT_BODY;
     static
@@ -53,25 +55,32 @@ public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
         NULL_OBJECT_BODY = new Data(new Binary(bytes));
     }
 
+    private final AmqpJmsMessageFacade parent;
     private final Message message;
     private final AtomicReference<Section> cachedReceivedBody = new AtomicReference<Section>();
+    private final JmsDeserializationPolicy deserializationPolicy;
     private ByteBuf messageBytes;
+    private boolean localContent;
 
     /**
      * Create a new delegate that uses Java serialization to store the message content.
      *
-     * @param message
-     *        the AMQP message instance where the object is to be stored / read.
+     * @param parent
+     *        the AMQP message facade instance where the object is to be stored / read.
      * @param messageBytes
      *        the raw bytes that comprise the message when it was received.
+     * @param deserializationPolicy
+     *        the JmsDeserializationPolicy that is used to validate the security of message
+     *        content, may be null (e.g on new outgoing messages).
      */
-    public AmqpSerializedObjectDelegate(Message message, ByteBuf messageBytes) {
-        this.message = message;
+    public AmqpSerializedObjectDelegate(AmqpJmsMessageFacade parent, ByteBuf messageBytes, JmsDeserializationPolicy deserializationPolicy) {
+        this.parent = parent;
+        this.message = parent.getAmqpMessage();
         this.message.setContentType(SERIALIZED_JAVA_OBJECT_CONTENT_TYPE);
         this.messageBytes = messageBytes;
+        this.deserializationPolicy = deserializationPolicy;
 
-        // We will decode the body on each access, so clear the current value
-        // so we don't carry along unneeded bloat.
+        // Cache the body so the first access can grab it without extra work.
         if (messageBytes != null) {
             cachedReceivedBody.set(message.getBody());
         }
@@ -116,7 +125,7 @@ public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
             Serializable serialized = null;
 
             try (ByteArrayInputStream bais = new ByteArrayInputStream(bin.getArray(), bin.getArrayOffset(), bin.getLength());
-                 ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(bais)) {
+                 ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(bais, this)) {
 
                 serialized = (Serializable) objIn.readObject();
             }
@@ -137,6 +146,7 @@ public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
         }
 
         messageBytes = null;
+        localContent = true;
     }
 
     @Override
@@ -148,7 +158,40 @@ public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
     }
 
     @Override
+    public void copyInto(AmqpObjectTypeDelegate copy) throws Exception {
+        if (!(copy instanceof AmqpSerializedObjectDelegate)) {
+            copy.setObject(getObject());
+        } else {
+            AmqpSerializedObjectDelegate target = (AmqpSerializedObjectDelegate) copy;
+
+            // Swap our cached value to the copy, we will just decode it if we need it.
+            target.cachedReceivedBody.set(cachedReceivedBody.getAndSet(null));
+
+            // If we have the original bytes just copy those and let the next get
+            // decode them into the payload, otherwise we need to do a deep copy.
+            if (messageBytes != null) {
+                target.messageBytes = messageBytes.copy();
+            }
+
+            target.localContent = localContent;
+
+            // Copy the already encoded message body if it exists, subsequent gets
+            // will deserialize the data so no mutations can occur.
+            target.message.setBody(message.getBody());
+        }
+    }
+
+    @Override
     public boolean isAmqpTypeEncoded() {
         return false;
     }
+
+    @Override
+    public boolean isTrusted(Class<?> clazz) {
+        if (!localContent && deserializationPolicy != null) {
+            return deserializationPolicy.isTrustedType(parent.getConsumerDestination(), clazz);
+        } else {
+            return true;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
index 99ab86b..cc1038f 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
@@ -48,18 +48,17 @@ public class AmqpTypedObjectDelegate implements AmqpObjectTypeDelegate {
     /**
      * Create a new delegate that uses Java serialization to store the message content.
      *
-     * @param message
-     *        the AMQP message instance where the object is to be stored / read.
+     * @param parent
+     *        the AMQP message facade instance where the object is to be stored / read.
      * @param messageBytes
      *        the raw bytes that comprise the AMQP message that was received.
      */
-    public AmqpTypedObjectDelegate(Message message, ByteBuf messageBytes) {
-        this.message = message;
+    public AmqpTypedObjectDelegate(AmqpJmsMessageFacade parent, ByteBuf messageBytes) {
+        this.message = parent.getAmqpMessage();
         this.message.setContentType(null);
         this.messageBytes = messageBytes;
 
-        // We will decode the body on each access, so clear the current value
-        // so we don't carry along unneeded bloat.
+        // Cache the body so the first access can grab it without extra work.
         if (messageBytes != null) {
             cachedReceivedBody.set(message.getBody());
         }
@@ -108,15 +107,16 @@ public class AmqpTypedObjectDelegate implements AmqpObjectTypeDelegate {
             Message transfer = Message.Factory.create();
 
             // Exchange the incoming body value for one that is created from encoding
-            // and decoding the value.
+            // and decoding the value. Save the bytes for subsequent getObject and
+            // copyInto calls to use.
             transfer.setBody(new AmqpValue(value));
             messageBytes = encodeMessage(transfer);
             transfer = decodeMessage(messageBytes);
-            messageBytes = null;
 
             // This step requires a heavy-weight operation of both encoding and decoding the
             // incoming body value in order to create a copy such that changes to the original
-            // do not affect the stored value.  In the future it makes sense to try to enhance
+            // do not affect the stored value, and also verifies we can actually encode it at all
+            // now instead of later during send. In the future it makes sense to try to enhance
             // proton such that we can encode the body and use those bytes directly on the
             // message as it is being sent.
 
@@ -135,6 +135,41 @@ public class AmqpTypedObjectDelegate implements AmqpObjectTypeDelegate {
         }
     }
 
+    @Override
+    public void copyInto(AmqpObjectTypeDelegate copy) throws Exception {
+        if (!(copy instanceof AmqpTypedObjectDelegate)) {
+            copy.setObject(getObject());
+        } else {
+            AmqpTypedObjectDelegate target = (AmqpTypedObjectDelegate) copy;
+
+            // Swap our cached value (if any) to the copy, we will just decode it if we need it later.
+            target.cachedReceivedBody.set(cachedReceivedBody.getAndSet(null));
+
+            if (messageBytes != null) {
+                // If we have the original bytes just copy those and let the next get
+                // decode them into the payload (or for the copy, use the cached
+                // body if it was swapped above).
+                target.messageBytes = messageBytes.copy();
+
+                // Internal message body copy to satisfy sends. This is safe since the body was set
+                // from a copy (decoded from the bytes) to ensure it is a snapshot. Also safe for
+                // gets as they will use the message bytes (or cached body if set) to return the object.
+                target.message.setBody(message.getBody());
+            } else {
+                // We have to deep get/set copy here, otherwise a get might return
+                // the object value carried by the original version.
+                copy.setObject(getObject());
+            }
+        }
+    }
+
+    @Override
+    public boolean isAmqpTypeEncoded() {
+        return true;
+    }
+
+    //----- Internal implementation ------------------------------------------//
+
     private boolean isSupportedAmqpValueObjectType(Serializable serializable) {
         // TODO: augment supported types to encode as an AmqpValue?
         return serializable instanceof String ||
@@ -142,9 +177,4 @@ public class AmqpTypedObjectDelegate implements AmqpObjectTypeDelegate {
                serializable instanceof List<?> ||
                serializable.getClass().isArray();
     }
-
-    @Override
-    public boolean isAmqpTypeEncoded() {
-        return true;
-    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
index 0432bc4..21562a8 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
@@ -31,16 +31,29 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
     private static final ClassLoader FALLBACK_CLASS_LOADER = ClassLoadingAwareObjectInputStream.class.getClassLoader();
 
     private final ClassLoader inLoader;
+    private final TrustedClassFilter securityFilter;
 
-    public ClassLoadingAwareObjectInputStream(InputStream in) throws IOException {
+    /**
+     * Security Filter used to filter classes that the application deems to be insecure, this filter
+     * is not applied to the class instances for the primitive types, and array types are narrowed
+     * to the component type of the array before being passed into this filter.
+     */
+    public interface TrustedClassFilter {
+        boolean isTrusted(Class<?> clazz);
+    }
+
+    public ClassLoadingAwareObjectInputStream(InputStream in, TrustedClassFilter filter) throws IOException {
         super(in);
+
         inLoader = in.getClass().getClassLoader();
+        securityFilter = filter;
     }
 
     @Override
     protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {
         ClassLoader cl = Thread.currentThread().getContextClassLoader();
-        return load(classDesc.getName(), cl, inLoader);
+        Class<?> clazz = load(classDesc.getName(), cl, inLoader);
+        return checkSecurity(clazz);
     }
 
     @Override
@@ -51,20 +64,52 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
             cinterfaces[i] = load(interfaces[i], cl);
         }
 
+        Class<?> clazz = null;
+        Throwable failureCause = null;
+
         try {
-            return Proxy.getProxyClass(cl, cinterfaces);
+            clazz = Proxy.getProxyClass(cl, cinterfaces);
         } catch (IllegalArgumentException e) {
+            failureCause = e;
+
             try {
-                return Proxy.getProxyClass(inLoader, cinterfaces);
+                clazz = Proxy.getProxyClass(inLoader, cinterfaces);
             } catch (IllegalArgumentException e1) {
             }
             try {
-                return Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces);
+                clazz = Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces);
             } catch (IllegalArgumentException e2) {
             }
+        }
 
-            throw new ClassNotFoundException(null, e);
+        if (clazz != null) {
+            return checkSecurity(clazz);
         }
+
+        throw new ClassNotFoundException("Failed find class.", failureCause);
+    }
+
+    private Class<?> checkSecurity(Class<?> clazz) throws ClassNotFoundException {
+
+        Class<?> target = clazz;
+
+        while (target.isArray()) {
+            target = target.getComponentType();
+        }
+
+        while (target.isAnonymousClass() || target.isLocalClass()) {
+            target = target.getEnclosingClass();
+        }
+
+        if (!target.isPrimitive() && securityFilter != null) {
+            if (!securityFilter.isTrusted(target)) {
+                throw new ClassNotFoundException("Forbidden " + clazz + "! " +
+                    "This class is not trusted to be deserialized under the current configuration. " +
+                    "Please refer to the documentation for more information on how to configure trusted classes.");
+            }
+        }
+
+        return clazz;
     }
 
     private Class<?> load(String className, ClassLoader... cl) throws ClassNotFoundException {

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
index efb29f5..48c668b 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
@@ -38,6 +38,7 @@ import javax.jms.Connection;
 import javax.jms.ExceptionListener;
 import javax.jms.JMSException;
 
+import org.apache.qpid.jms.policy.JmsDefaultDeserializationPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultPrefetchPolicy;
 import org.apache.qpid.jms.policy.JmsDefaultPresettlePolicy;
 import org.apache.qpid.jms.policy.JmsDefaultRedeliveryPolicy;
@@ -111,12 +112,16 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
     public void testConnectionFactoryPrefetchPolicyIsAppliedToConnection() throws JMSException {
         JmsConnectionFactory factory = new JmsConnectionFactory(USER, PASSWORD, "mock://localhost");
 
+        JmsDefaultPrefetchPolicy prefetchPolicy = (JmsDefaultPrefetchPolicy) factory.getPrefetchPolicy();
+
+        assertFalse(prefetchPolicy.getQueuePrefetch() == 1);
+
         ((JmsDefaultPrefetchPolicy) factory.getPrefetchPolicy()).setAll(1);
 
         JmsConnection connection = (JmsConnection) factory.createConnection();
         assertNotNull(connection);
 
-        JmsDefaultPrefetchPolicy prefetchPolicy = (JmsDefaultPrefetchPolicy) connection.getPrefetchPolicy();
+        prefetchPolicy = (JmsDefaultPrefetchPolicy) connection.getPrefetchPolicy();
         assertNotNull(prefetchPolicy);
         assertNotSame(factory.getPrefetchPolicy(), prefetchPolicy);
 
@@ -132,6 +137,8 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
 
         JmsDefaultPresettlePolicy presettlePolicy = (JmsDefaultPresettlePolicy) factory.getPresettlePolicy();
 
+        assertFalse(presettlePolicy.isPresettleAll());
+
         presettlePolicy.setPresettleAll(true);
 
         JmsConnection connection = (JmsConnection) factory.createConnection();
@@ -150,6 +157,8 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
 
         JmsDefaultRedeliveryPolicy redeliveryPolicy = (JmsDefaultRedeliveryPolicy) factory.getRedeliveryPolicy();
 
+        assertFalse(redeliveryPolicy.getMaxRedeliveries() == 100);
+
         redeliveryPolicy.setMaxRedeliveries(100);
 
         JmsConnection connection = (JmsConnection) factory.createConnection();
@@ -163,6 +172,29 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
     }
 
     @Test
+    public void testConnectionFactoryDeserializationPolicyIsAppliedToConnection() throws JMSException {
+        JmsConnectionFactory factory = new JmsConnectionFactory(USER, PASSWORD, "mock://localhost");
+
+        final String TRUSTED_PACKAGES = "java.lang,java.util";
+
+        JmsDefaultDeserializationPolicy deserializationPolicy =
+            (JmsDefaultDeserializationPolicy) factory.getDeserializationPolicy();
+
+        assertFalse(deserializationPolicy.getWhiteList().equals(TRUSTED_PACKAGES));
+
+        deserializationPolicy.setWhiteList(TRUSTED_PACKAGES);
+
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        assertNotNull(connection);
+
+        deserializationPolicy = (JmsDefaultDeserializationPolicy) connection.getDeserializationPolicy();
+        assertNotNull(deserializationPolicy);
+        assertNotSame(factory.getDeserializationPolicy(), deserializationPolicy);
+
+        assertEquals(TRUSTED_PACKAGES, deserializationPolicy.getWhiteList());
+    }
+
+    @Test
     public void testConnectionGetConfiguredURIApplied() throws Exception {
         URI mock = new URI("mock://localhost");
 
@@ -529,6 +561,47 @@ public class JmsConnectionFactoryTest extends QpidJmsTestCase {
         assertEquals("Properties were not equal", props, props2);
     }
 
+    /**
+     * The deserialization policy is maintained in a child-object, which we extract the properties from
+     * when serializing the factory. Ensure this functions by doing a round trip on a factory
+     * configured with some new deserialization configuration via the URI.
+     *
+     * @throws Exception if an error occurs during the test.
+     */
+    @Test
+    public void testSerializeThenDeserializeMaintainsDeserializationPolicy() throws Exception {
+        String whiteListValue = "java.lang";
+        String whitelistKey = "deserializationPolicy.whiteList";
+
+        String blackListValue = "java.lang.foo";
+        String blacklistKey = "deserializationPolicy.blackList";
+
+        String uri = "amqp://localhost:1234?jms." + whitelistKey + "=" + whiteListValue + "&jms." + blacklistKey + "=" + blackListValue;
+
+        JmsConnectionFactory cf = new JmsConnectionFactory(uri);
+        Map<String, String> props = cf.getProperties();
+
+        assertTrue("Props dont contain expected deserialization policy change", props.containsKey(whitelistKey));
+        assertEquals("Unexpected value", whiteListValue, props.get(whitelistKey));
+
+        assertTrue("Props dont contain expected deserialization policy change", props.containsKey(blacklistKey));
+        assertEquals("Unexpected value", blackListValue, props.get(blacklistKey));
+
+        Object roundTripped = roundTripSerialize(cf);
+
+        assertNotNull("Null object returned", roundTripped);
+        assertEquals("Unexpected type", JmsConnectionFactory.class, roundTripped.getClass());
+
+        Map<String, String> props2 = ((JmsConnectionFactory)roundTripped).getProperties();
+        assertTrue("Props dont contain expected deserialization policy change", props2.containsKey(whitelistKey));
+        assertEquals("Unexpected value", whiteListValue, props2.get(whitelistKey));
+
+        assertTrue("Props dont contain expected deserialization policy change", props2.containsKey(blacklistKey));
+        assertEquals("Unexpected value", blackListValue, props2.get(blacklistKey));
+
+        assertEquals("Properties were not equal", props, props2);
+    }
+
     @Test
     public void testSetRemoteURIThrowsOnNullURI() throws Exception {
         JmsConnectionFactory cf = new JmsConnectionFactory();

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
index bae22c1..a9bc0c5 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ObjectMessageIntegrationTest.java
@@ -23,11 +23,13 @@ import static org.hamcrest.Matchers.nullValue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.util.HashMap;
+import java.util.UUID;
 
 import javax.jms.Connection;
 import javax.jms.JMSException;
@@ -51,13 +53,18 @@ import org.apache.qpid.jms.test.testpeer.matchers.sections.MessagePropertiesSect
 import org.apache.qpid.jms.test.testpeer.matchers.sections.TransferPayloadCompositeMatcher;
 import org.apache.qpid.jms.test.testpeer.matchers.types.EncodedAmqpValueMatcher;
 import org.apache.qpid.jms.test.testpeer.matchers.types.EncodedDataMatcher;
+import org.apache.qpid.jms.util.SimplePojo;
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.DescribedType;
 import org.apache.qpid.proton.amqp.Symbol;
 import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ObjectMessageIntegrationTest extends QpidJmsTestCase {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ObjectMessageIntegrationTest.class);
 
-public class ObjectMessageIntegrationTest extends QpidJmsTestCase
-{
     private final IntegrationTestFixture testFixture = new IntegrationTestFixture();
 
     //==== Java serialization encoding ====
@@ -224,6 +231,120 @@ public class ObjectMessageIntegrationTest extends QpidJmsTestCase
         }
     }
 
+    @Test(timeout = 20000)
+    public void testReceiveBlockedSerializedContentFailsOnGetObject() throws Exception {
+        // We arent allowing the test class
+        doTestReceiveSerializedContentPolicyTest("java.lang,java.util", null, false);
+    }
+
+    @Test(timeout = 20000)
+    public void testReceiveBlockAllSerializedContentFailsOnGetObject() throws Exception {
+        // We are blocking everything
+        doTestReceiveSerializedContentPolicyTest(null, "*", false);
+    }
+
+    @Test(timeout = 20000)
+    public void testReceiveBlockSomeSerializedContentFailsOnGetObject() throws Exception {
+        // We arent allowing the UUID
+        doTestReceiveSerializedContentPolicyTest("org.apache.qpid.jms", null, false);
+    }
+
+    @Test(timeout = 20000)
+    public void testReceiveWithWrongUnblockedSerializedContentFailsOnGetObject() throws Exception {
+        // We arent allowing the UUID a different way
+        doTestReceiveSerializedContentPolicyTest("java.lang,org.apache.qpid.jms", null, false);
+    }
+
+    @Test(timeout = 20000)
+    public void testReceiveWithFullyWhitelistedSerializedContentSucceeds() throws Exception {
+        // We are allowing everything needed
+        doTestReceiveSerializedContentPolicyTest("java.lang,java.util,org.apache.qpid.jms", null, true);
+    }
+
+    @Test(timeout = 20000)
+    public void testReceiveWithFullyWhitelistedSerializedContentFailsDueToBlackList() throws Exception {
+        // We are whitelisting everything needed, but then the blacklist is overriding to block some
+        doTestReceiveSerializedContentPolicyTest("java.lang,java.util,org.apache.qpid.jms", "java.util", false);
+    }
+
+    private void doTestReceiveSerializedContentPolicyTest(String whiteList, String blackList, boolean succeed) throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
+            String options = null;
+            if(whiteList != null) {
+                options = "?jms.deserializationPolicy.whiteList=" + whiteList;
+            }
+
+            if(blackList != null) {
+                if(options == null) {
+                    options = "?";
+                } else {
+                    options += "&";
+                }
+
+                options +="jms.deserializationPolicy.blackList=" + blackList;
+            }
+
+            Connection connection = testFixture.establishConnecton(testPeer, options);
+
+            connection.start();
+
+            testPeer.expectBegin();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            MessageAnnotationsDescribedType msgAnnotations = new MessageAnnotationsDescribedType();
+            msgAnnotations.setSymbolKeyedAnnotation(AmqpMessageSupport.JMS_MSG_TYPE, AmqpMessageSupport.JMS_OBJECT_MESSAGE);
+            PropertiesDescribedType properties = new PropertiesDescribedType();
+            properties.setContentType(Symbol.valueOf(AmqpMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE));
+
+            SimplePojo expectedContent = new SimplePojo(UUID.randomUUID());
+
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(expectedContent);
+            oos.flush();
+            oos.close();
+            byte[] bytes = baos.toByteArray();
+
+            DescribedType dataContent = new DataDescribedType(new Binary(bytes));
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, msgAnnotations, properties, null, dataContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(3000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+            assertTrue(receivedMessage instanceof ObjectMessage);
+
+            ObjectMessage objectMessage = (ObjectMessage) receivedMessage;
+            Object received = null;
+            try {
+                received = objectMessage.getObject();
+                if(!succeed) {
+                    fail("Should not be able to read blocked content");
+                }
+            } catch (JMSException jmsEx) {
+                LOG.debug("Caught: ", jmsEx);
+                if(succeed) {
+                    fail("Should have been able to read blocked content");
+                }
+            }
+
+            if(succeed) {
+                assertEquals("Content not as expected", expectedContent, received);
+            }
+
+            testPeer.expectClose();
+            connection.close();
+
+            testPeer.waitForAllHandlersToComplete(3000);
+        }
+    }
+
     //==== AMQP type system encoding ====
 
     @Test(timeout = 20000)

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java
index 6b44f3c..44bab21 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/facade/test/JmsTestObjectMessageFacade.java
@@ -71,7 +71,7 @@ public class JmsTestObjectMessageFacade extends JmsTestMessageFacade implements
         Serializable serialized = null;
 
         try (ByteArrayInputStream dataIn = new ByteArrayInputStream(object);
-             ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn)) {
+             ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn, null)) {
 
             serialized = (Serializable) objIn.readObject();
         }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicyTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicyTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicyTest.java
new file mode 100644
index 0000000..93ff466
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/policy/JmsDefaultDeserializationPolicyTest.java
@@ -0,0 +1,328 @@
+/*
+ * 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.qpid.jms.policy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.UUID;
+import java.util.Vector;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.JmsQueue;
+import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream;
+import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream.TrustedClassFilter;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JmsDefaultDeserializationPolicyTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JmsDefaultDeserializationPolicyTest.class);
+
+    @Test
+    public void testIsTrustedType() {
+        JmsDestination destination = new JmsQueue("test-queue");
+        JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+
+        assertTrue(policy.isTrustedType(destination, null));
+        assertTrue(policy.isTrustedType(destination, UUID.class));
+        assertTrue(policy.isTrustedType(destination, String.class));
+        assertTrue(policy.isTrustedType(destination, Boolean.class));
+        assertTrue(policy.isTrustedType(destination, Double.class));
+        assertTrue(policy.isTrustedType(destination, Object.class));
+
+        // Only types in lang
+        policy.setWhiteList("java.lang");
+
+        assertTrue(policy.isTrustedType(destination, null));
+        assertFalse(policy.isTrustedType(destination, UUID.class));
+        assertTrue(policy.isTrustedType(destination, String.class));
+        assertTrue(policy.isTrustedType(destination, Boolean.class));
+        assertFalse(policy.isTrustedType(destination, getClass()));
+
+        // Entry must be complete package name prefix to match
+        // i.e while "java.n" is a prefix of "java.net", this
+        // wont match the socket class below.
+        policy.setWhiteList("java.n");
+        assertFalse(policy.isTrustedType(destination, UUID.class));
+        assertFalse(policy.isTrustedType(destination, String.class));
+        assertFalse(policy.isTrustedType(destination, java.net.Socket.class));
+
+        // add a non-core package
+        policy.setWhiteList("java.lang,org.apache.qpid.jms");
+
+        assertFalse(policy.isTrustedType(destination, UUID.class));
+        assertTrue(policy.isTrustedType(destination, String.class));
+        assertTrue(policy.isTrustedType(destination, getClass()));
+
+        // Try with a class-specific entry
+        policy.setWhiteList("java.lang.Integer");
+
+        assertTrue(policy.isTrustedType(destination, Integer.class));
+        assertFalse(policy.isTrustedType(destination, Boolean.class));
+
+        // Verify blacklist overrides whitelist
+        policy.setWhiteList("java.lang.Integer");
+        policy.setBlackList("java.lang.Integer");
+
+        assertFalse(policy.isTrustedType(destination, Integer.class));
+
+        // Verify blacklist entry prefix overrides whitelist
+        policy.setWhiteList("java.lang.Integer");
+        policy.setBlackList("java.lang");
+
+        assertFalse(policy.isTrustedType(destination, Integer.class));
+
+        // Verify blacklist catch-all overrides whitelist
+        policy.setWhiteList("java.lang.Integer");
+        policy.setBlackList("*");
+
+        assertFalse(policy.isTrustedType(destination, Integer.class));
+    }
+
+    @Test
+    public void testHashCode() {
+        JmsDeserializationPolicy policy1 = new JmsDefaultDeserializationPolicy();
+        JmsDeserializationPolicy policy2 = new JmsDefaultDeserializationPolicy();
+
+        assertTrue(policy1.hashCode() != 0);
+        assertEquals(policy1.hashCode(), policy2.hashCode());
+        assertEquals(policy2.hashCode(), policy1.hashCode());
+
+        ((JmsDefaultDeserializationPolicy) policy1).setWhiteList("java.util");
+
+        assertFalse(policy1.hashCode() == policy2.hashCode());
+        assertFalse(policy2.hashCode() == policy1.hashCode());
+
+        ((JmsDefaultDeserializationPolicy) policy2).setWhiteList("java.util");
+
+        assertTrue(policy1.hashCode() == policy2.hashCode());
+        assertTrue(policy2.hashCode() == policy1.hashCode());
+
+        ((JmsDefaultDeserializationPolicy) policy1).setBlackList("java.util");
+
+        assertFalse(policy1.hashCode() == policy2.hashCode());
+        assertFalse(policy2.hashCode() == policy1.hashCode());
+
+        ((JmsDefaultDeserializationPolicy) policy2).setBlackList("java.util");
+
+        assertTrue(policy1.hashCode() == policy2.hashCode());
+        assertTrue(policy2.hashCode() == policy1.hashCode());
+    }
+
+    @Test
+    public void testEqualsObject() {
+        JmsDefaultDeserializationPolicy policy1 = new JmsDefaultDeserializationPolicy();
+        JmsDefaultDeserializationPolicy policy2 = new JmsDefaultDeserializationPolicy();
+
+        assertTrue(policy1.equals(policy1));
+        assertTrue(policy1.equals(policy2));
+        assertTrue(policy2.equals(policy1));
+
+        policy1.setWhiteList("java.util");
+
+        assertFalse(policy1.equals(policy2));
+        assertFalse(policy2.equals(policy1));
+
+        assertFalse(policy1.equals(null));
+        assertFalse(policy1.equals(""));
+        assertFalse(policy1.equals(this));
+
+        policy2.setWhiteList("java.util");
+        assertTrue(policy1.equals(policy2));
+
+        policy1.setBlackList("java.util");
+
+        assertFalse(policy1.equals(policy2));
+        assertFalse(policy2.equals(policy1));
+
+        policy2.setBlackList("java.util");
+        assertTrue(policy1.equals(policy2));
+        assertTrue(policy2.equals(policy1));
+    }
+
+    @Test
+    public void testJmsDefaultDeserializationPolicy() {
+        JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+
+        assertFalse(policy.getWhiteList().isEmpty());
+        assertTrue(policy.getBlackList().isEmpty());
+    }
+
+    @Test
+    public void testJmsDefaultDeserializationPolicyCopyCtor() {
+        JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+
+        policy.setWhiteList("a.b.c");
+        policy.setBlackList("d.e.f");
+
+        JmsDefaultDeserializationPolicy copy = new JmsDefaultDeserializationPolicy(policy);
+
+        assertEquals("a.b.c", copy.getWhiteList());
+        assertEquals("d.e.f", copy.getBlackList());
+    }
+
+    @Test
+    public void testJmsDefaultDeserializationPolicyCopy() {
+        JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+
+        policy.setWhiteList("a.b.c");
+        policy.setBlackList("d.e.f");
+
+        JmsDefaultDeserializationPolicy copy = (JmsDefaultDeserializationPolicy) policy.copy();
+
+        assertEquals("a.b.c", copy.getWhiteList());
+        assertEquals("d.e.f", copy.getBlackList());
+    }
+
+    @Test
+    public void testSetWhiteList() {
+        JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+        assertNotNull(policy.getWhiteList());
+
+        policy.setWhiteList(null);
+        assertNotNull(policy.getWhiteList());
+        assertTrue(policy.getWhiteList().isEmpty());
+
+        policy.setWhiteList("*");
+        assertNotNull(policy.getWhiteList());
+        assertFalse(policy.getWhiteList().isEmpty());
+    }
+
+    @Test
+    public void testSetBlackList() {
+        JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+        assertNotNull(policy.getBlackList());
+
+        policy.setBlackList(null);
+        assertNotNull(policy.getBlackList());
+        assertTrue(policy.getBlackList().isEmpty());
+
+        policy.setBlackList("*");
+        assertNotNull(policy.getBlackList());
+        assertFalse(policy.getBlackList().isEmpty());
+    }
+
+    @Test
+    public void testDeserializeVectorUsingPolicy() throws Exception {
+        Vector<Object> vector = new Vector<Object>();
+        vector.add("pi");
+        vector.add(new Integer(314159));
+        vector.add(new Vector<String>());
+        vector.add(Boolean.FALSE);
+
+        final JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+        ByteArrayInputStream input = new ByteArrayInputStream(serializeObject(vector));
+        TrustedClassFilter filter = new TrustedClassFilter() {
+
+            @Override
+            public boolean isTrusted(Class<?> clazz) {
+                LOG.trace("Check for trust status of class: {}", clazz.getName());
+                return policy.isTrustedType(new JmsQueue(), clazz);
+            }
+        };
+
+        ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, filter);
+
+        Object result = null;
+        try {
+            result = reader.readObject();
+        } catch (Exception ex) {
+            fail("Should no throw any errors");
+        } finally {
+            reader.close();
+        }
+
+        assertNotNull(result);
+        assertTrue(result instanceof Vector);
+        assertEquals(4, ((Vector<?>) result).size());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testDeserializeHashMapUsingPolicy() throws Exception {
+        HashMap<Object, Object> map = new HashMap<Object, Object>();
+
+        map.put("a", "Value");
+        map.put("b", new Integer(1));
+        map.put("c", new Vector<Object>());
+        map.put("d", Boolean.FALSE);
+
+        final JmsDefaultDeserializationPolicy policy = new JmsDefaultDeserializationPolicy();
+        ByteArrayInputStream input = new ByteArrayInputStream(serializeObject(map));
+        TrustedClassFilter filter = new TrustedClassFilter() {
+
+            @Override
+            public boolean isTrusted(Class<?> clazz) {
+                LOG.trace("Check for trust status of class: {}", clazz.getName());
+                return policy.isTrustedType(new JmsQueue(), clazz);
+            }
+        };
+
+        ClassLoadingAwareObjectInputStream reader = new ClassLoadingAwareObjectInputStream(input, filter);
+
+        Object result = null;
+        try {
+            result = reader.readObject();
+        } catch (Exception ex) {
+            fail("Should no throw any errors");
+        } finally {
+            reader.close();
+        }
+
+        assertNotNull(result);
+        assertTrue(result instanceof HashMap);
+
+        map = (HashMap<Object, Object>) result;
+
+        assertEquals(4, map.size());
+
+        assertEquals("Value", map.get("a"));
+        assertEquals(new Integer(1), map.get("b"));
+        assertEquals(new Vector<Object>(), map.get("c"));
+        assertEquals(Boolean.FALSE, map.get("d"));
+    }
+
+    //----- Internal methods -------------------------------------------------//
+
+    private byte[] serializeObject(Object value) throws IOException {
+        byte[] result = new byte[0];
+
+        if (value != null) {
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                 ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+
+                oos.writeObject(value);
+                oos.flush();
+                oos.close();
+
+                result = baos.toByteArray();
+            }
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java
index a534de0..eee5f8e 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilderTest.java
@@ -41,6 +41,8 @@ import org.apache.qpid.jms.message.JmsObjectMessage;
 import org.apache.qpid.jms.message.JmsStreamMessage;
 import org.apache.qpid.jms.message.JmsTextMessage;
 import org.apache.qpid.jms.message.facade.JmsMessageFacade;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsConsumerInfo;
 import org.apache.qpid.jms.provider.amqp.AmqpConsumer;
 import org.apache.qpid.jms.test.QpidJmsTestCase;
 import org.apache.qpid.proton.Proton;
@@ -62,7 +64,10 @@ public class AmqpJmsMessageBuilderTest extends QpidJmsTestCase {
     @Override
     public void setUp() throws Exception {
         super.setUp();
+
+        JmsConsumerId consumerId = new JmsConsumerId("ID:MOCK:1", 1, 1);
         mockConsumer = Mockito.mock(AmqpConsumer.class);
+        Mockito.when(mockConsumer.getResourceInfo()).thenReturn(new JmsConsumerInfo(consumerId));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java
index 28530d9..4d28ec1 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactoryTest.java
@@ -48,6 +48,8 @@ import org.apache.qpid.jms.message.facade.JmsMessageFacade;
 import org.apache.qpid.jms.message.facade.JmsObjectMessageFacade;
 import org.apache.qpid.jms.message.facade.JmsStreamMessageFacade;
 import org.apache.qpid.jms.message.facade.JmsTextMessageFacade;
+import org.apache.qpid.jms.meta.JmsConnectionId;
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
 import org.apache.qpid.jms.provider.amqp.AmqpConnection;
 import org.apache.qpid.jms.test.QpidJmsTestCase;
 import org.junit.Test;
@@ -194,12 +196,19 @@ public class AmqpJmsMessageFactoryTest extends QpidJmsTestCase {
     }
 
     private AmqpConnection createMockAmqpConnectionAmqpTypes() {
+        JmsConnectionId connectionId = new JmsConnectionId("ID:MOCK:1");
         AmqpConnection connection = Mockito.mock(AmqpConnection.class);
         Mockito.when(connection.isObjectMessageUsesAmqpTypes()).thenReturn(true);
+        Mockito.when(connection.getResourceInfo()).thenReturn(new JmsConnectionInfo(connectionId));
+
         return connection;
     }
 
     private AmqpConnection createMockAmqpConnection() {
-        return Mockito.mock(AmqpConnection.class);
+        JmsConnectionId connectionId = new JmsConnectionId("ID:MOCK:1");
+        AmqpConnection connection = Mockito.mock(AmqpConnection.class);
+        Mockito.when(connection.getResourceInfo()).thenReturn(new JmsConnectionInfo(connectionId));
+
+        return connection;
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
index 3775269..48a78f6 100644
--- a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageTypesTestCase.java
@@ -22,6 +22,10 @@ import java.nio.charset.StandardCharsets;
 
 import org.apache.qpid.jms.JmsDestination;
 import org.apache.qpid.jms.JmsTopic;
+import org.apache.qpid.jms.meta.JmsConnectionId;
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsConsumerInfo;
 import org.apache.qpid.jms.provider.amqp.AmqpConnection;
 import org.apache.qpid.jms.provider.amqp.AmqpConsumer;
 import org.apache.qpid.jms.test.QpidJmsTestCase;
@@ -91,13 +95,20 @@ public class AmqpJmsMessageTypesTestCase extends QpidJmsTestCase {
     }
 
     protected AmqpConsumer createMockAmqpConsumer() {
+        JmsConsumerId consumerId = new JmsConsumerId("ID:MOCK:1:1:1");
+        AmqpConnection connection = createMockAmqpConnection();
         AmqpConsumer consumer = Mockito.mock(AmqpConsumer.class);
-        Mockito.when(consumer.getConnection()).thenReturn(createMockAmqpConnection());
+        Mockito.when(consumer.getConnection()).thenReturn(connection);
         Mockito.when(consumer.getDestination()).thenReturn(consumerDestination);
+        Mockito.when(consumer.getResourceInfo()).thenReturn(new JmsConsumerInfo(consumerId));
         return consumer;
     }
 
     protected AmqpConnection createMockAmqpConnection() {
-        return Mockito.mock(AmqpConnection.class);
+        JmsConnectionId connectionId = new JmsConnectionId("ID:MOCK:1");
+        AmqpConnection connection = Mockito.mock(AmqpConnection.class);
+        Mockito.when(connection.getResourceInfo()).thenReturn(new JmsConnectionInfo(connectionId));
+
+        return connection;
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/669cfff8/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/AnonymousSimplePojoParent.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/AnonymousSimplePojoParent.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/AnonymousSimplePojoParent.java
new file mode 100644
index 0000000..32eb3f9
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/AnonymousSimplePojoParent.java
@@ -0,0 +1,39 @@
+/*
+ * 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.qpid.jms.util;
+
+import java.io.Serializable;
+
+public class AnonymousSimplePojoParent implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private SimplePojo payload;
+
+    public AnonymousSimplePojoParent(Object simplePojoPayload) {
+        // Create an ANONYMOUS simple payload, itself serializable, like we
+        // have to be since the object references us and is used
+        // during the serialization.
+        payload = new SimplePojo(simplePojoPayload) {
+            private static final long serialVersionUID = 1L;
+        };
+    }
+
+    public SimplePojo getPayload() {
+        return payload;
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org