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:54 UTC

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

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