From 2cd79d71282095dbca86878ef23e3a75a733fa67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Galder=20Zamarren=CC=83o?= <galder@zamarreno.com>
Date: Wed, 3 May 2017 15:41:18 +0200
Subject: [PATCH] ISPN-7781 Add java deserial white list for client

* Added new option to Hot Rod client that enables a list of regular
  expressions to be plugged that define classes that can be deserialized
  using standard Java serialization.

---
 .../client/hotrod/RemoteCacheManager.java     |  4 +-
 .../AbstractConfigurationChildBuilder.java    |  5 ++
 .../hotrod/configuration/Configuration.java   | 13 ++-
 .../configuration/ConfigurationBuilder.java   | 22 ++++-
 .../ConfigurationChildBuilder.java            |  7 ++
 .../hotrod/event/ClientListenerNotifier.java  | 11 ++-
 .../hotrod/impl/ConfigurationProperties.java  |  1 +
 .../hotrod/impl/iteration/KeyTracker.java     |  3 +-
 .../impl/iteration/NoOpSegmentKeyTracker.java |  3 +-
 .../hotrod/impl/iteration/ReplKeyTracker.java |  3 +-
 .../impl/iteration/SegmentKeyTracker.java     |  5 +-
 .../impl/operations/AbstractKeyOperation.java |  7 +-
 .../operations/AbstractKeyValueOperation.java |  6 +-
 .../AddClientListenerOperation.java           |  7 +-
 .../operations/AuthMechListOperation.java     |  5 +-
 .../hotrod/impl/operations/AuthOperation.java |  6 +-
 .../impl/operations/BulkGetKeysOperation.java |  8 +-
 .../impl/operations/BulkGetOperation.java     | 10 ++-
 .../impl/operations/ClearOperation.java       |  5 +-
 .../impl/operations/ContainsKeyOperation.java |  7 +-
 .../impl/operations/ExecuteOperation.java     | 60 +++++++-------
 .../FaultTolerantPingOperation.java           |  8 +-
 .../impl/operations/GetAllOperation.java      |  9 ++-
 .../operations/GetAllParallelOperation.java   |  7 +-
 .../hotrod/impl/operations/GetOperation.java  |  8 +-
 .../operations/GetWithMetadataOperation.java  | 10 ++-
 .../operations/GetWithVersionOperation.java   | 10 ++-
 .../impl/operations/HotRodOperation.java      |  6 +-
 .../operations/IterationEndOperation.java     |  8 +-
 .../operations/IterationNextOperation.java    | 14 ++--
 .../operations/IterationStartOperation.java   |  5 +-
 .../impl/operations/OperationsFactory.java    | 80 +++++++++++--------
 .../operations/ParallelHotRodOperation.java   |  5 +-
 .../hotrod/impl/operations/PingOperation.java |  9 ++-
 .../impl/operations/PutAllOperation.java      |  6 +-
 .../operations/PutAllParallelOperation.java   |  8 +-
 .../impl/operations/PutIfAbsentOperation.java |  7 +-
 .../hotrod/impl/operations/PutOperation.java  |  6 +-
 .../impl/operations/QueryOperation.java       |  5 +-
 .../RemoveClientListenerOperation.java        |  4 +-
 .../RemoveIfUnmodifiedOperation.java          |  7 +-
 .../impl/operations/RemoveOperation.java      |  5 +-
 .../ReplaceIfUnmodifiedOperation.java         |  5 +-
 .../impl/operations/ReplaceOperation.java     |  9 ++-
 .../operations/RetryOnFailureOperation.java   |  5 +-
 .../hotrod/impl/operations/SizeOperation.java |  5 +-
 .../impl/operations/StatsOperation.java       |  6 +-
 .../client/hotrod/impl/protocol/Codec.java    |  9 ++-
 .../client/hotrod/impl/protocol/Codec10.java  | 13 +--
 .../client/hotrod/impl/protocol/Codec20.java  | 26 +++---
 .../client/hotrod/impl/protocol/Codec21.java  | 13 +--
 .../hotrod/impl/protocol/CodecUtils.java      |  5 +-
 .../tcp/SaslTransportObjectFactory.java       | 40 +++++-----
 .../transport/tcp/TcpTransportFactory.java    |  4 +-
 .../transport/tcp/TransportObjectFactory.java |  7 +-
 .../infinispan/client/hotrod/logging/Log.java |  4 +
 .../hotrod/marshall/MarshallerUtil.java       | 62 ++++++++++++--
 .../hotrod/TransportObjectFactoryTest.java    |  5 +-
 .../configuration/ConfigurationTest.java      | 12 ++-
 .../MultiServerDistRemoteIteratorTest.java    |  2 +-
 .../hotrod/retry/RetryOnFailureUnitTest.java  |  3 +-
 .../CompatibilityCacheFactory.java            |  1 +
 62 files changed, 423 insertions(+), 238 deletions(-)

diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/RemoteCacheManager.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/RemoteCacheManager.java
index 4f354c1..f266c7e 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/RemoteCacheManager.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/RemoteCacheManager.java
@@ -576,7 +576,7 @@ public void start() {
          asyncExecutorService = executorFactory.getExecutor(configuration.asyncExecutorFactory().properties());
       }
 
-      listenerNotifier = ClientListenerNotifier.create(codec, marshaller);
+      listenerNotifier = ClientListenerNotifier.create(codec, marshaller, configuration.serialWhitelist());
       transportFactory.start(codec, configuration, defaultCacheTopologyId, listenerNotifier);
 
       synchronized (cacheName2RemoteCache) {
@@ -704,7 +704,7 @@ private void startRemoteCache(RemoteCacheHolder remoteCacheHolder) {
       RemoteCacheImpl<?, ?> remoteCache = remoteCacheHolder.remoteCache;
       OperationsFactory operationsFactory = new OperationsFactory(
               transportFactory, remoteCache.getName(), remoteCacheHolder.forceReturnValue, codec, listenerNotifier,
-            asyncExecutorService);
+            asyncExecutorService, configuration);
       remoteCache.init(marshaller, asyncExecutorService, operationsFactory, configuration.keySizeEstimate(), configuration.valueSizeEstimate());
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/AbstractConfigurationChildBuilder.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/AbstractConfigurationChildBuilder.java
index c2628c6..7df00ac 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/AbstractConfigurationChildBuilder.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/AbstractConfigurationChildBuilder.java
@@ -156,6 +156,11 @@ public ConfigurationBuilder maxRetries(int retriesPerServer) {
       return builder.maxRetries(retriesPerServer);
    }
 
+   @Override
+   public ConfigurationBuilder addJavaSerialWhiteList(String... regExs) {
+      return builder.addJavaSerialWhiteList(regExs);
+   }
+
    @Override
    public ConfigurationBuilder withProperties(Properties properties) {
       return builder.withProperties(properties);
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/Configuration.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/Configuration.java
index 5f76362..28a5ed1 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/Configuration.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/Configuration.java
@@ -45,12 +45,13 @@
    private final int maxRetries;
    private final NearCacheConfiguration nearCache;
    private final List<ClusterConfiguration> clusters;
+   private final List<String> serialWhitelist;
 
    Configuration(ExecutorFactoryConfiguration asyncExecutorFactory, Class<? extends RequestBalancingStrategy> balancingStrategyClass, FailoverRequestBalancingStrategy balancingStrategy, ClassLoader classLoader,
          ConnectionPoolConfiguration connectionPool, int connectionTimeout, Class<? extends ConsistentHash>[] consistentHashImpl, boolean forceReturnValues, int keySizeEstimate, Class<? extends Marshaller> marshallerClass,
          boolean pingOnStartup, String protocolVersion, List<ServerConfiguration> servers, int socketTimeout, SecurityConfiguration security, boolean tcpNoDelay, boolean tcpKeepAlive,
          Class<? extends TransportFactory> transportFactory, int valueSizeEstimate, int maxRetries, NearCacheConfiguration nearCache,
-         List<ClusterConfiguration> clusters) {
+         List<ClusterConfiguration> clusters, List<String> serialWhitelist) {
       this.asyncExecutorFactory = asyncExecutorFactory;
       this.balancingStrategyClass = balancingStrategyClass;
       this.balancingStrategy = balancingStrategy;
@@ -74,13 +75,14 @@
       this.valueSizeEstimate = valueSizeEstimate;
       this.nearCache = nearCache;
       this.clusters = clusters;
+      this.serialWhitelist = serialWhitelist;
    }
 
    Configuration(ExecutorFactoryConfiguration asyncExecutorFactory, Class<? extends RequestBalancingStrategy> balancingStrategyClass, FailoverRequestBalancingStrategy balancingStrategy, ClassLoader classLoader,
          ConnectionPoolConfiguration connectionPool, int connectionTimeout, Class<? extends ConsistentHash>[] consistentHashImpl, boolean forceReturnValues, int keySizeEstimate, Marshaller marshaller,
          boolean pingOnStartup, String protocolVersion, List<ServerConfiguration> servers, int socketTimeout, SecurityConfiguration security, boolean tcpNoDelay, boolean tcpKeepAlive,
          Class<? extends TransportFactory> transportFactory, int valueSizeEstimate, int maxRetries, NearCacheConfiguration nearCache,
-         List<ClusterConfiguration> clusters) {
+         List<ClusterConfiguration> clusters, List<String> serialWhitelist) {
       this.asyncExecutorFactory = asyncExecutorFactory;
       this.balancingStrategyClass = balancingStrategyClass;
       this.balancingStrategy = balancingStrategy;
@@ -104,6 +106,7 @@
       this.valueSizeEstimate = valueSizeEstimate;
       this.nearCache = nearCache;
       this.clusters = clusters;
+      this.serialWhitelist = serialWhitelist;
    }
 
    public ExecutorFactoryConfiguration asyncExecutorFactory() {
@@ -206,6 +209,10 @@ public int maxRetries() {
       return maxRetries;
    }
 
+   public List<String> serialWhitelist() {
+      return serialWhitelist;
+   }
+
    @Override
    public String toString() {
       return "Configuration [asyncExecutorFactory=" + asyncExecutorFactory + ", balancingStrategyClass=" + balancingStrategyClass + ", balancingStrategy=" + balancingStrategy + ",classLoader=" + classLoader + ", connectionPool="
@@ -213,6 +220,8 @@ public String toString() {
             + forceReturnValues + ", keySizeEstimate=" + keySizeEstimate + ", marshallerClass=" + marshallerClass + ", marshaller=" + marshaller + ", pingOnStartup="
             + pingOnStartup + ", protocolVersion=" + protocolVersion + ", servers=" + servers + ", socketTimeout=" + socketTimeout + ", security=" + security + ", tcpNoDelay=" + tcpNoDelay + ", tcpKeepAlive=" + tcpKeepAlive
             + ", transportFactory=" + transportFactory + ", valueSizeEstimate=" + valueSizeEstimate + ", maxRetries=" + maxRetries
+            + ", serialWhiteList=" + serialWhitelist
             + "nearCache=" + nearCache + "]";
    }
+
 }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/ConfigurationBuilder.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/ConfigurationBuilder.java
index 05f25c7..59fdd48 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/ConfigurationBuilder.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/ConfigurationBuilder.java
@@ -2,6 +2,8 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Properties;
@@ -70,6 +72,7 @@
    private int valueSizeEstimate = ConfigurationProperties.DEFAULT_VALUE_SIZE;
    private int maxRetries = ConfigurationProperties.DEFAULT_MAX_RETRIES;
    private final NearCacheConfigurationBuilder nearCache;
+   private final List<String> whiteListRegExs = new ArrayList<>();
 
    private final List<ClusterConfigurationBuilder> clusters = new ArrayList<ClusterConfigurationBuilder>();
 
@@ -276,6 +279,12 @@ public ConfigurationBuilder maxRetries(int maxRetries) {
       return this;
    }
 
+   @Override
+   public ConfigurationBuilder addJavaSerialWhiteList(String... regEx) {
+      this.whiteListRegExs.addAll(Arrays.asList(regEx));
+      return this;
+   }
+
    @Override
    public ConfigurationBuilder withProperties(Properties properties) {
       TypedProperties typed = TypedProperties.toTypedProperties(properties);
@@ -306,6 +315,13 @@ public ConfigurationBuilder withProperties(Properties properties) {
       }
       this.valueSizeEstimate(typed.getIntProperty(ConfigurationProperties.VALUE_SIZE_ESTIMATE, valueSizeEstimate));
       this.maxRetries(typed.getIntProperty(ConfigurationProperties.MAX_RETRIES, maxRetries));
+
+      String serialWhitelist = typed.getProperty(ConfigurationProperties.JAVA_SERIAL_WHITELIST);
+      if (serialWhitelist != null) {
+         String[] classes = serialWhitelist.split(",");
+         Collections.addAll(this.whiteListRegExs, classes);
+      }
+
       return this;
    }
 
@@ -343,11 +359,11 @@ public Configuration create() {
       if (marshaller == null) {
          return new Configuration(asyncExecutorFactory.create(), balancingStrategyClass, balancingStrategy, classLoader == null ? null : classLoader.get(), connectionPool.create(), connectionTimeout,
                consistentHashImpl, forceReturnValues, keySizeEstimate, marshallerClass, pingOnStartup, protocolVersion, servers, socketTimeout, security.create(), tcpNoDelay, tcpKeepAlive, transportFactory,
-               valueSizeEstimate, maxRetries, nearCache.create(), serverClusterConfigs);
+               valueSizeEstimate, maxRetries, nearCache.create(), serverClusterConfigs, whiteListRegExs);
       } else {
          return new Configuration(asyncExecutorFactory.create(), balancingStrategyClass, balancingStrategy, classLoader == null ? null : classLoader.get(), connectionPool.create(), connectionTimeout,
                consistentHashImpl, forceReturnValues, keySizeEstimate, marshaller, pingOnStartup, protocolVersion, servers, socketTimeout, security.create(), tcpNoDelay, tcpKeepAlive, transportFactory,
-               valueSizeEstimate, maxRetries, nearCache.create(), serverClusterConfigs);
+               valueSizeEstimate, maxRetries, nearCache.create(), serverClusterConfigs, whiteListRegExs);
       }
    }
 
@@ -391,6 +407,8 @@ public ConfigurationBuilder read(Configuration template) {
       this.valueSizeEstimate = template.valueSizeEstimate();
       this.maxRetries = template.maxRetries();
       this.nearCache.read(template.nearCache());
+      this.whiteListRegExs.addAll(template.serialWhitelist());
+
       return this;
    }
 }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/ConfigurationChildBuilder.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/ConfigurationChildBuilder.java
index eae60d9..13a21ca 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/ConfigurationChildBuilder.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/configuration/ConfigurationChildBuilder.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.configuration;
 
+import java.util.List;
 import java.util.Properties;
 
 import org.infinispan.client.hotrod.impl.consistenthash.ConsistentHash;
@@ -168,6 +169,12 @@
     */
    ConfigurationBuilder maxRetries(int maxRetries);
 
+   /**
+    * List of regular expressions for classes that can be deserialized using standard Java deserialization
+    * when reading data that might have been stored with a different endpoint, e.g. REST.
+    */
+   ConfigurationBuilder addJavaSerialWhiteList(String... regEx);
+
    /**
     * Configures this builder using the specified properties
     */
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/event/ClientListenerNotifier.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/event/ClientListenerNotifier.java
index 7f24878..00a1e2e 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/event/ClientListenerNotifier.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/event/ClientListenerNotifier.java
@@ -60,16 +60,19 @@
    private final ExecutorService executor;
    private final Codec codec;
    private final Marshaller marshaller;
+   private final List<String> whitelist;
 
-   protected ClientListenerNotifier(ExecutorService executor, Codec codec, Marshaller marshaller) {
+   protected ClientListenerNotifier(ExecutorService executor, Codec codec, Marshaller marshaller,
+      List<String> whitelist) {
       this.executor = executor;
       this.codec = codec;
       this.marshaller = marshaller;
+      this.whitelist = whitelist;
    }
 
-   public static ClientListenerNotifier create(Codec codec, Marshaller marshaller) {
+   public static ClientListenerNotifier create(Codec codec, Marshaller marshaller, List<String> whitelist) {
       ExecutorService executor = Executors.newCachedThreadPool(getRestoreThreadNameThreadFactory());
-      return new ClientListenerNotifier(executor, codec, marshaller);
+      return new ClientListenerNotifier(executor, codec, marshaller, whitelist);
    }
 
    private static ThreadFactory getRestoreThreadNameThreadFactory() {
@@ -261,7 +264,7 @@ public void run() {
          while (!Thread.currentThread().isInterrupted()) {
             ClientEvent clientEvent = null;
             try {
-               clientEvent = codec.readEvent(transport, op.listenerId, marshaller);
+               clientEvent = codec.readEvent(transport, op.listenerId, marshaller, whitelist);
                invokeClientEvent(clientEvent);
                // Nullify event, makes it easier to identify network vs invocation error messages
                clientEvent = null;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/ConfigurationProperties.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/ConfigurationProperties.java
index 291ea40..8399d74 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/ConfigurationProperties.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/ConfigurationProperties.java
@@ -43,6 +43,7 @@
    public static final String TRUST_STORE_FILE_NAME = "infinispan.client.hotrod.trust_store_file_name";
    public static final String TRUST_STORE_PASSWORD = "infinispan.client.hotrod.trust_store_password";
    public static final String MAX_RETRIES = "infinispan.client.hotrod.max_retries";
+   public static final String JAVA_SERIAL_WHITELIST = "infinispan.client.hotrod.java_serial_whitelist";
 
    // defaults
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/KeyTracker.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/KeyTracker.java
index 0e869c3..455a62d 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/KeyTracker.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/KeyTracker.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.iteration;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -8,7 +9,7 @@
  */
 public interface KeyTracker {
 
-   boolean track(byte[] key, short status);
+   boolean track(byte[] key, short status, List<String> whitelist);
 
    void segmentsFinished(byte[] finishedSegments);
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/NoOpSegmentKeyTracker.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/NoOpSegmentKeyTracker.java
index 1d6bd73..3dc4f5b 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/NoOpSegmentKeyTracker.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/NoOpSegmentKeyTracker.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.iteration;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -9,7 +10,7 @@
 class NoOpSegmentKeyTracker implements KeyTracker {
 
    @Override
-   public boolean track(byte[] key, short status) {
+   public boolean track(byte[] key, short status, List<String> whitelist) {
       return true;
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/ReplKeyTracker.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/ReplKeyTracker.java
index ec0449d..5e2d2a2 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/ReplKeyTracker.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/ReplKeyTracker.java
@@ -3,6 +3,7 @@
 import org.infinispan.commons.equivalence.ByteArrayEquivalence;
 import org.infinispan.commons.util.CollectionFactory;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -17,7 +18,7 @@
    private Set<byte[]> keys = CollectionFactory.makeSet(ByteArrayEquivalence.INSTANCE);
 
    @Override
-   public boolean track(byte[] key, short status) {
+   public boolean track(byte[] key, short status, List<String> whitelist) {
       return keys.add(key);
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/SegmentKeyTracker.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/SegmentKeyTracker.java
index 21d4f56..775e475 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/SegmentKeyTracker.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/iteration/SegmentKeyTracker.java
@@ -12,6 +12,7 @@
 
 import java.util.BitSet;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReferenceArray;
 import java.util.stream.IntStream;
@@ -39,9 +40,9 @@ public SegmentKeyTracker(Marshaller marshaller, SegmentConsistentHash segmentCon
       segmentStream.forEach(i -> keysPerSegment.set(i, CollectionFactory.makeSet(ByteArrayEquivalence.INSTANCE)));
    }
 
-   public boolean track(byte[] key, short status) {
+   public boolean track(byte[] key, short status, List<String> whitelist) {
       int segment = HotRodConstants.hasCompatibility(status) ?
-              segmentConsistentHash.getSegment(MarshallerUtil.bytes2obj(marshaller, key, status)) :
+              segmentConsistentHash.getSegment(MarshallerUtil.bytes2obj(marshaller, key, status, whitelist)) :
               segmentConsistentHash.getSegment(key);
       boolean result = keysPerSegment.get(segment).add(key);
       if (log.isTraceEnabled())
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AbstractKeyOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AbstractKeyOperation.java
index 82cd30f..a9127fa 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AbstractKeyOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AbstractKeyOperation.java
@@ -5,6 +5,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import net.jcip.annotations.Immutable;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.VersionedOperationResponse;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
@@ -29,8 +30,8 @@
    protected final byte[] keyBytes;
 
    protected AbstractKeyOperation(Codec codec, TransportFactory transportFactory,
-         Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+         Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags, Configuration cfg) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
       this.key = key;
       this.keyBytes = keyBytes;
    }
@@ -55,7 +56,7 @@ protected short sendKeyOperation(byte[] key, Transport transport, byte opCode, b
    }
 
    protected T returnPossiblePrevValue(Transport transport, short status) {
-      return (T) codec.returnPossiblePrevValue(transport, status, flags);
+      return (T) codec.returnPossiblePrevValue(transport, status, flags, cfg.serialWhitelist());
    }
 
    protected VersionedOperationResponse returnVersionedOperationResponse(Transport transport, HeaderParams params) {
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AbstractKeyValueOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AbstractKeyValueOperation.java
index 039b7a4..597b990 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AbstractKeyValueOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AbstractKeyValueOperation.java
@@ -1,6 +1,8 @@
 package org.infinispan.client.hotrod.impl.operations;
 
 import net.jcip.annotations.Immutable;
+
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -29,9 +31,9 @@
    protected final TimeUnit maxIdleTimeUnit;
 
    protected AbstractKeyValueOperation(Codec codec, TransportFactory transportFactory, Object key, byte[] keyBytes, byte[] cacheName,
-                                       AtomicInteger topologyId, int flags, byte[] value,
+                                       AtomicInteger topologyId, int flags, Configuration cfg, byte[] value,
                                        long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) {
-      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags);
+      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, cfg);
       this.value = value;
       this.lifespan = lifespan;
       this.maxIdle = maxIdle;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AddClientListenerOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AddClientListenerOperation.java
index 2872a9c..c401224 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AddClientListenerOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AddClientListenerOperation.java
@@ -2,6 +2,7 @@
 
 import org.infinispan.client.hotrod.RemoteCacheManager;
 import org.infinispan.client.hotrod.annotation.ClientListener;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.event.ClientEvent;
 import org.infinispan.client.hotrod.event.ClientListenerNotifier;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
@@ -43,10 +44,10 @@
    public final byte[][] converterFactoryParams;
 
    protected AddClientListenerOperation(Codec codec, TransportFactory transportFactory,
-         String cacheName, AtomicInteger topologyId, int flags,
+         String cacheName, AtomicInteger topologyId, int flags, Configuration cfg,
          ClientListenerNotifier listenerNotifier, Object listener,
          byte[][] filterFactoryParams, byte[][] converterFactoryParams) {
-      super(codec, transportFactory, RemoteCacheManager.cacheNameBytes(cacheName), topologyId, flags);
+      super(codec, transportFactory, RemoteCacheManager.cacheNameBytes(cacheName), topologyId, flags, cfg);
       this.listenerId = generateListenerId();
       this.listenerNotifier = listenerNotifier;
       this.listener = listener;
@@ -92,7 +93,7 @@ protected Short executeOperation(Transport transport) {
       Either<Short, ClientEvent> either;
       do {
          // Process state transfer related events or add listener response
-         either = codec.readHeaderOrEvent(dedicatedTransport, params, listenerId, listenerNotifier.getMarshaller());
+         either = codec.readHeaderOrEvent(dedicatedTransport, params, listenerId, listenerNotifier.getMarshaller(), cfg.serialWhitelist());
          switch(either.type()) {
             case LEFT:
                if (HotRodConstants.isSuccess(either.left()))
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AuthMechListOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AuthMechListOperation.java
index 76c14c1..ab143ef 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AuthMechListOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AuthMechListOperation.java
@@ -6,6 +6,7 @@
 
 import net.jcip.annotations.Immutable;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -21,8 +22,8 @@
 
    private final Transport transport;
 
-   public AuthMechListOperation(Codec codec, AtomicInteger topologyId, Transport transport) {
-      super(codec, 0, DEFAULT_CACHE_NAME_BYTES, topologyId);
+   public AuthMechListOperation(Codec codec, AtomicInteger topologyId, Configuration cfg, Transport transport) {
+      super(codec, 0, cfg, DEFAULT_CACHE_NAME_BYTES, topologyId);
       this.transport = transport;
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AuthOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AuthOperation.java
index 24c8a3e..4e2a78f 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AuthOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/AuthOperation.java
@@ -4,6 +4,7 @@
 
 import net.jcip.annotations.Immutable;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -21,8 +22,9 @@
    private final String saslMechanism;
    private final byte[] response;
 
-   public AuthOperation(Codec codec, AtomicInteger topologyId, Transport transport, String saslMechanism, byte response[]) {
-      super(codec, 0, DEFAULT_CACHE_NAME_BYTES, topologyId);
+   public AuthOperation(Codec codec, AtomicInteger topologyId, Configuration cfg, Transport transport,
+                        String saslMechanism, byte response[]) {
+      super(codec, 0,  cfg, DEFAULT_CACHE_NAME_BYTES, topologyId);
       this.transport = transport;
       this.saslMechanism = saslMechanism;
       this.response = response;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/BulkGetKeysOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/BulkGetKeysOperation.java
index 93bc08a..14b810f 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/BulkGetKeysOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/BulkGetKeysOperation.java
@@ -5,6 +5,7 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -19,8 +20,9 @@
 public class BulkGetKeysOperation<K> extends RetryOnFailureOperation<Set<K>> {
    private final int scope;
 
-   public BulkGetKeysOperation(Codec codec, TransportFactory transportFactory, byte[] cacheName, AtomicInteger topologyId, int flags, int scope) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+   public BulkGetKeysOperation(Codec codec, TransportFactory transportFactory, byte[] cacheName,
+                               AtomicInteger topologyId, int flags, Configuration cfg, int scope) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
       this.scope = scope;
    }
    
@@ -37,7 +39,7 @@ protected Transport getTransport(int retryCount, Set<SocketAddress> failedServer
       short status = readHeaderAndValidate(transport, params);
       Set<K> result = new HashSet<K>();
       while ( transport.readByte() == 1) { //there's more!
-         result.add(codec.readUnmarshallByteArray(transport, status));
+         result.add(codec.readUnmarshallByteArray(transport, status, cfg.serialWhitelist()));
       }
       return result;
    }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/BulkGetOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/BulkGetOperation.java
index ee361fd..5908091 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/BulkGetOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/BulkGetOperation.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.operations;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -21,8 +22,9 @@
 
    private final int entryCount;
 
-   public BulkGetOperation(Codec codec, TransportFactory transportFactory, byte[] cacheName, AtomicInteger topologyId, int flags, int entryCount) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+   public BulkGetOperation(Codec codec, TransportFactory transportFactory, byte[] cacheName, AtomicInteger topologyId,
+                           int flags, Configuration cfg, int entryCount) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
       this.entryCount = entryCount;
    }
    
@@ -39,8 +41,8 @@ protected Transport getTransport(int retryCount, Set<SocketAddress> failedServer
       short status = readHeaderAndValidate(transport, params);
       Map<K, V> result = new HashMap<K, V>();
       while ( transport.readByte() == 1) { //there's more!
-         K key = codec.readUnmarshallByteArray(transport, status);
-         V value = codec.readUnmarshallByteArray(transport, status);
+         K key = codec.readUnmarshallByteArray(transport, status, cfg.serialWhitelist());
+         V value = codec.readUnmarshallByteArray(transport, status, cfg.serialWhitelist());
          result.put(key, value);
       }
       return result;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ClearOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ClearOperation.java
index 01b4c6c..0523897 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ClearOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ClearOperation.java
@@ -1,6 +1,7 @@
 package org.infinispan.client.hotrod.impl.operations;
 
 import net.jcip.annotations.Immutable;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -20,8 +21,8 @@
 public class ClearOperation extends RetryOnFailureOperation<Void> {
 
    public ClearOperation(Codec codec, TransportFactory transportFactory,
-                         byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+                         byte[] cacheName, AtomicInteger topologyId, int flags, Configuration cfg) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ContainsKeyOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ContainsKeyOperation.java
index 32c1c72..221863d 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ContainsKeyOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ContainsKeyOperation.java
@@ -1,6 +1,7 @@
 package org.infinispan.client.hotrod.impl.operations;
 
 import net.jcip.annotations.Immutable;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -17,9 +18,9 @@
 @Immutable
 public class ContainsKeyOperation extends AbstractKeyOperation<Boolean> {
 
-   public ContainsKeyOperation(Codec codec, TransportFactory transportFactory,
-         Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, key, keyBytes,cacheName, topologyId, flags);
+   public ContainsKeyOperation(Codec codec, TransportFactory transportFactory, Object key, byte[] keyBytes,
+                               byte[] cacheName, AtomicInteger topologyId, int flags, Configuration cfg) {
+      super(codec, transportFactory, key, keyBytes,cacheName, topologyId, flags, cfg);
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ExecuteOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ExecuteOperation.java
index 995ed0e..8136ad1 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ExecuteOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ExecuteOperation.java
@@ -6,6 +6,7 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -19,34 +20,35 @@
  */
 public class ExecuteOperation<T> extends RetryOnFailureOperation<T> {
 
-	private final String taskName;
-	private final Map<String, byte[]> marshalledParams;
-
-	protected ExecuteOperation(Codec codec, TransportFactory transportFactory,
-			byte[] cacheName, AtomicInteger topologyId, int flags, String taskName, Map<String, byte[]> marshalledParams) {
-		super(codec, transportFactory, cacheName, topologyId, flags);
-		this.taskName = taskName;
-		this.marshalledParams = marshalledParams;
-	}
-
-	@Override
-	protected Transport getTransport(int retryCount,
-			Set<SocketAddress> failedServers) {
-		return transportFactory.getTransport(failedServers, cacheName);
-	}
-
-	@Override
-	protected T executeOperation(Transport transport) {
-		HeaderParams params = writeHeader(transport, EXEC_REQUEST);
-		transport.writeString(taskName);
-		transport.writeVInt(marshalledParams.size());
-		for(Entry<String, byte[]> entry : marshalledParams.entrySet()) {
-			transport.writeString(entry.getKey());
-			transport.writeArray(entry.getValue());
-		}
-		transport.flush();
-		short status = readHeaderAndValidate(transport, params);
-		return codec.readUnmarshallByteArray(transport, status);
-	}
+   private final String taskName;
+   private final Map<String, byte[]> marshalledParams;
+
+   protected ExecuteOperation(Codec codec, TransportFactory transportFactory, byte[] cacheName,
+                              AtomicInteger topologyId, int flags, Configuration cfg,
+                              String taskName, Map<String, byte[]> marshalledParams) {
+      super(codec, transportFactory, cacheName == null ? DEFAULT_CACHE_NAME_BYTES : cacheName, topologyId, flags, cfg);
+      this.taskName = taskName;
+      this.marshalledParams = marshalledParams;
+   }
+
+   @Override
+   protected Transport getTransport(int retryCount,
+         Set<SocketAddress> failedServers) {
+      return transportFactory.getTransport(failedServers, cacheName);
+   }
+
+   @Override
+   protected T executeOperation(Transport transport) {
+      HeaderParams params = writeHeader(transport, EXEC_REQUEST);
+      transport.writeString(taskName);
+      transport.writeVInt(marshalledParams.size());
+      for(Entry<String, byte[]> entry : marshalledParams.entrySet()) {
+         transport.writeString(entry.getKey());
+         transport.writeArray(entry.getValue());
+      }
+      transport.flush();
+      short status = readHeaderAndValidate(transport, params);
+      return codec.readUnmarshallByteArray(transport, status, cfg.serialWhitelist());
+   }
 
 }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/FaultTolerantPingOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/FaultTolerantPingOperation.java
index 4200eaa..ae59bbe 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/FaultTolerantPingOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/FaultTolerantPingOperation.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.operations;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.transport.Transport;
 import org.infinispan.client.hotrod.impl.transport.TransportFactory;
@@ -17,8 +18,9 @@
 public class FaultTolerantPingOperation extends RetryOnFailureOperation<PingOperation.PingResult> {
 
    protected FaultTolerantPingOperation(Codec codec, TransportFactory transportFactory,
-                                        byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+                                        byte[] cacheName, AtomicInteger topologyId, int flags,
+                                        Configuration cfg) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
    }
 
    @Override
@@ -28,7 +30,7 @@ protected Transport getTransport(int retryCount, Set<SocketAddress> failedServer
 
    @Override
    protected PingOperation.PingResult executeOperation(Transport transport) {
-      return new PingOperation(codec, topologyId, transport, cacheName).execute();
+      return new PingOperation(codec, topologyId, cfg, transport, cacheName).execute();
    }
 
 }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetAllOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetAllOperation.java
index 2227f05..4172296 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetAllOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetAllOperation.java
@@ -8,6 +8,7 @@
 
 import net.jcip.annotations.Immutable;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -24,8 +25,8 @@
 
    public GetAllOperation(Codec codec, TransportFactory transportFactory,
                           Set<byte[]> keys, byte[] cacheName, AtomicInteger topologyId,
-                          int flags) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+                          int flags, Configuration cfg) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
       this.keys = keys;
    }
 
@@ -44,8 +45,8 @@ public GetAllOperation(Codec codec, TransportFactory transportFactory,
       int size = transport.readVInt();
       Map<K, V> result = new HashMap<K, V>(size);
       for (int i = 0; i < size; ++i) {
-         K key = codec.readUnmarshallByteArray(transport, status);
-         V value = codec.readUnmarshallByteArray(transport, status);
+         K key = codec.readUnmarshallByteArray(transport, status, cfg.serialWhitelist());
+         V value = codec.readUnmarshallByteArray(transport, status, cfg.serialWhitelist());
          result.put(key, value);
       }
       return result;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetAllParallelOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetAllParallelOperation.java
index 52fe940..12d6a5e 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetAllParallelOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetAllParallelOperation.java
@@ -10,6 +10,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.transport.TransportFactory;
 
@@ -21,8 +22,8 @@
    private final Set<byte[]> keys;
 
    protected GetAllParallelOperation(Codec codec, TransportFactory transportFactory, Set<byte[]> keys, byte[]
-         cacheName, AtomicInteger topologyId, int flags, ExecutorService executorService) {
-      super(codec, transportFactory, cacheName, topologyId, flags, executorService);
+         cacheName, AtomicInteger topologyId, int flags, Configuration cfg, ExecutorService executorService) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg, executorService);
       this.keys = keys;
    }
 
@@ -42,7 +43,7 @@ protected GetAllParallelOperation(Codec codec, TransportFactory transportFactory
 
       return splittedKeys.values().stream().map(
             keysSubset -> new GetAllOperation<K, V>(codec, transportFactory, keysSubset, cacheName, topologyId,
-                  flags)).collect(Collectors.toList());
+                  flags, cfg)).collect(Collectors.toList());
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetOperation.java
index d4048a6..9b63a1c 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetOperation.java
@@ -1,6 +1,7 @@
 package org.infinispan.client.hotrod.impl.operations;
 
 import net.jcip.annotations.Immutable;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -18,8 +19,9 @@
 public class GetOperation<V> extends AbstractKeyOperation<V> {
 
    public GetOperation(Codec codec, TransportFactory transportFactory,
-         Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags);
+                       Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags,
+                       Configuration cfg) {
+      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, cfg);
    }
 
    @Override
@@ -30,7 +32,7 @@ public V executeOperation(Transport transport) {
          result = null;
       } else {
          if (HotRodConstants.isSuccess(status)) {
-            result = codec.readUnmarshallByteArray(transport, status);
+            result = codec.readUnmarshallByteArray(transport, status, cfg.serialWhitelist());
          }
       }
       return result;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetWithMetadataOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetWithMetadataOperation.java
index fb86207..51c0b63 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetWithMetadataOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetWithMetadataOperation.java
@@ -5,6 +5,7 @@
 import net.jcip.annotations.Immutable;
 
 import org.infinispan.client.hotrod.MetadataValue;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.MetadataValueImpl;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
@@ -26,9 +27,10 @@
    private static final Log log = LogFactory.getLog(GetWithMetadataOperation.class);
    private static final boolean trace = log.isTraceEnabled();
 
-   public GetWithMetadataOperation(Codec codec, TransportFactory transportFactory,
-         Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags);
+   public GetWithMetadataOperation(Codec codec, TransportFactory transportFactory, Object key, byte[] keyBytes,
+                                   byte[] cacheName, AtomicInteger topologyId, int flags,
+                                   Configuration cfg) {
+      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, cfg);
    }
 
    @Override
@@ -55,7 +57,7 @@ public GetWithMetadataOperation(Codec codec, TransportFactory transportFactory,
          if (trace) {
             log.tracef("Received version: %d", version);
          }
-         V value = codec.readUnmarshallByteArray(transport, status);
+         V value = codec.readUnmarshallByteArray(transport, status, cfg.serialWhitelist());
          result = new MetadataValueImpl<V>(creation, lifespan, lastUsed, maxIdle, version, value);
       }
       return result;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetWithVersionOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetWithVersionOperation.java
index 57f3d29..6b51b84 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetWithVersionOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/GetWithVersionOperation.java
@@ -5,6 +5,7 @@
 import net.jcip.annotations.Immutable;
 
 import org.infinispan.client.hotrod.VersionedValue;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.VersionedValueImpl;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
@@ -27,9 +28,10 @@
    private static final Log log = LogFactory.getLog(GetWithVersionOperation.class);
    private static final boolean trace = log.isTraceEnabled();
 
-   public GetWithVersionOperation(Codec codec, TransportFactory transportFactory,
-         Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags);
+   public GetWithVersionOperation(Codec codec, TransportFactory transportFactory, Object key, byte[] keyBytes,
+                                  byte[] cacheName, AtomicInteger topologyId, int flags,
+                                  Configuration cfg) {
+      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, cfg);
    }
 
    @Override
@@ -43,7 +45,7 @@ public GetWithVersionOperation(Codec codec, TransportFactory transportFactory,
          if (trace) {
             log.tracef("Received version: %d", version);
          }
-         V value = codec.readUnmarshallByteArray(transport, status);
+         V value = codec.readUnmarshallByteArray(transport, status, cfg.serialWhitelist());
          result = new VersionedValueImpl<V>(version, value);
       }
       return result;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/HotRodOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/HotRodOperation.java
index 4183ec4..474d073 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/HotRodOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/HotRodOperation.java
@@ -4,6 +4,7 @@
 
 import net.jcip.annotations.Immutable;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
@@ -28,14 +29,17 @@
 
    protected final Codec codec;
 
+   protected final Configuration cfg;
+
    private static final byte NO_TX = 0;
    private static final byte XA_TX = 1;
 
-   protected HotRodOperation(Codec codec, int flags, byte[] cacheName, AtomicInteger topologyId) {
+   protected HotRodOperation(Codec codec, int flags, Configuration cfg, byte[] cacheName, AtomicInteger topologyId) {
       this.flags = flags;
       this.cacheName = cacheName;
       this.topologyId = topologyId;
       this.codec = codec;
+      this.cfg = cfg;
    }
 
    public abstract Object execute();
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationEndOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationEndOperation.java
index f94e7cd..764ddcf 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationEndOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationEndOperation.java
@@ -2,6 +2,7 @@
 
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -17,9 +18,10 @@
    private final TransportFactory transportFactory;
    private final Transport transport;
 
-   protected IterationEndOperation(Codec codec, int flags, byte[] cacheName, AtomicInteger topologyId,
-                                   String iterationId, TransportFactory transportFactory, Transport transport) {
-      super(codec, flags, cacheName, topologyId);
+   protected IterationEndOperation(Codec codec, int flags, Configuration cfg,  byte[] cacheName,
+                                   AtomicInteger topologyId, String iterationId, TransportFactory transportFactory,
+                                   Transport transport) {
+      super(codec, flags, cfg, cacheName, topologyId);
       this.iterationId = iterationId;
       this.transportFactory = transportFactory;
       this.transport = transport;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationNextOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationNextOperation.java
index 2b33c12..b185519 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationNextOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationNextOperation.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.operations;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.MetadataValueImpl;
 import org.infinispan.client.hotrod.impl.iteration.KeyTracker;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
@@ -27,14 +28,15 @@
 
    private final String iterationId;
    private final Transport transport;
+   private final List<String> whitelist;
    private final KeyTracker segmentKeyTracker;
 
-   protected IterationNextOperation(Codec codec, int flags, byte[] cacheName, AtomicInteger topologyId,
-                                    String iterationId, Transport transport, KeyTracker segmentKeyTracker) {
-      super(codec, flags, cacheName, topologyId);
+   protected IterationNextOperation(Codec codec, int flags, Configuration cfg, byte[] cacheName, AtomicInteger topologyId,
+                                    String iterationId, Transport transport, KeyTracker segmentKeyTracker, List<String> whitelist) {
+      super(codec, flags, cfg, cacheName, topologyId);
       this.iterationId = iterationId;
       this.transport = transport;
-
+      this.whitelist = whitelist;
       this.segmentKeyTracker = segmentKeyTracker;
    }
 
@@ -86,7 +88,7 @@ protected IterationNextOperation(Codec codec, int flags, byte[] cacheName, Atomi
                value = new MetadataValueImpl<>(creation, lifespan, lastUsed, maxIdle, version, value);
             }
 
-            if (segmentKeyTracker.track(key, status)) {
+            if (segmentKeyTracker.track(key, status, whitelist)) {
                entries.add(new SimpleEntry<>(unmarshall(key, status), (E) value));
             }
          }
@@ -100,7 +102,7 @@ protected IterationNextOperation(Codec codec, int flags, byte[] cacheName, Atomi
 
    private Object unmarshall(byte[] bytes, short status) {
       Marshaller marshaller = transport.getTransportFactory().getMarshaller();
-      return MarshallerUtil.bytes2obj(marshaller, bytes, status);
+      return MarshallerUtil.bytes2obj(marshaller, bytes, status, whitelist);
    }
 
 }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationStartOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationStartOperation.java
index c8e4f8e..703b39a 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationStartOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/IterationStartOperation.java
@@ -5,6 +5,7 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.consistenthash.SegmentConsistentHash;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
@@ -32,10 +33,10 @@
    private final TransportFactory transportFactory;
    private final boolean metadata;
 
-   IterationStartOperation(Codec codec, int flags, byte[] cacheName, AtomicInteger topologyId,
+   IterationStartOperation(Codec codec, int flags, Configuration cfg, byte[] cacheName, AtomicInteger topologyId,
                            String filterConverterFactory, byte[][] filterParameters, Set<Integer> segments,
                            int batchSize, TransportFactory transportFactory, boolean metadata) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
       this.filterConverterFactory = filterConverterFactory;
       this.filterParameters = filterParameters;
       this.segments = segments;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/OperationsFactory.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/OperationsFactory.java
index 7b6fa11..6e36c02 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/OperationsFactory.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/OperationsFactory.java
@@ -5,6 +5,7 @@
 import org.infinispan.client.hotrod.CacheTopologyInfo;
 import org.infinispan.client.hotrod.Flag;
 import org.infinispan.client.hotrod.RemoteCacheManager;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.event.ClientListenerNotifier;
 import org.infinispan.client.hotrod.impl.iteration.KeyTracker;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
@@ -46,8 +47,10 @@
 
    private final ExecutorService executorService;
 
+   private final Configuration cfg;
+
    public OperationsFactory(TransportFactory transportFactory, String cacheName, boolean forceReturnValue, Codec
-           codec, ClientListenerNotifier listenerNotifier, ExecutorService executorService) {
+           codec, ClientListenerNotifier listenerNotifier, ExecutorService executorService, Configuration cfg) {
       this.transportFactory = transportFactory;
       this.executorService = executorService;
       this.cacheNameBytes = RemoteCacheManager.cacheNameBytes(cacheName);
@@ -58,6 +61,11 @@ public OperationsFactory(TransportFactory transportFactory, String cacheName, bo
       this.forceReturnValue = forceReturnValue;
       this.codec = codec;
       this.listenerNotifier = listenerNotifier;
+      this.cfg = cfg;
+   }
+
+   public OperationsFactory(TransportFactory transportFactory, Codec codec, ExecutorService executorService, Configuration cfg) {
+      this(transportFactory, null, false, codec, null, executorService, cfg);
    }
 
    public ClientListenerNotifier getListenerNotifier() {
@@ -69,58 +77,58 @@ public ClientListenerNotifier getListenerNotifier() {
    }
 
    public <V> GetOperation<V> newGetKeyOperation(Object key, byte[] keyBytes) {
-      return new GetOperation<V>(
-            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags());
+      return new GetOperation<>(
+            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), cfg);
    }
 
    public <K, V> GetAllParallelOperation<K, V> newGetAllOperation(Set<byte[]> keys) {
       return new GetAllParallelOperation<>(codec, transportFactory, keys, cacheNameBytes, topologyId, flags(),
-            executorService);
+            cfg, executorService);
    }
 
    public <V> RemoveOperation<V> newRemoveOperation(Object key, byte[] keyBytes) {
-      return new RemoveOperation<V>(
-            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags());
+      return new RemoveOperation<>(
+            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), cfg);
    }
 
    public <V> RemoveIfUnmodifiedOperation<V> newRemoveIfUnmodifiedOperation(Object key, byte[] keyBytes, long version) {
-      return new RemoveIfUnmodifiedOperation<V>(
-            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), version);
+      return new RemoveIfUnmodifiedOperation<>(
+            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), cfg, version);
    }
 
    public ReplaceIfUnmodifiedOperation newReplaceIfUnmodifiedOperation(Object key, byte[] keyBytes,
             byte[] value, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit, long version) {
       return new ReplaceIfUnmodifiedOperation(
             codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(lifespan, maxIdle),
-            value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit, version);
+            cfg, value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit, version);
    }
 
    public <V> GetWithVersionOperation<V> newGetWithVersionOperation(Object key, byte[] keyBytes) {
-      return new GetWithVersionOperation<V>(
-            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags());
+      return new GetWithVersionOperation<>(
+            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), cfg);
    }
 
    public <V> GetWithMetadataOperation<V> newGetWithMetadataOperation(Object key, byte[] keyBytes) {
-      return new GetWithMetadataOperation<V>(
-            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags());
+      return new GetWithMetadataOperation<>(
+            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), cfg);
    }
 
    public StatsOperation newStatsOperation() {
       return new StatsOperation(
-            codec, transportFactory, cacheNameBytes, topologyId, flags());
+            codec, transportFactory, cacheNameBytes, topologyId, flags(), cfg);
    }
 
    public <V> PutOperation<V> newPutKeyValueOperation(Object key, byte[] keyBytes, byte[] value,
           long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) {
       return new PutOperation<V>(
             codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(lifespan, maxIdle),
-            value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
+            cfg, value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
    }
 
    public PutAllParallelOperation newPutAllOperation(Map<byte[], byte[]> map,
                                                      long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) {
       return new PutAllParallelOperation(
-            codec, transportFactory, map, cacheNameBytes, topologyId, flags(lifespan, maxIdle),
+            codec, transportFactory, map, cacheNameBytes, topologyId, flags(lifespan, maxIdle), cfg,
               lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit, executorService);
    }
 
@@ -128,52 +136,52 @@ public PutAllParallelOperation newPutAllOperation(Map<byte[], byte[]> map,
              long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
       return new PutIfAbsentOperation<V>(
             codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(lifespan, maxIdleTime),
-            value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
+            cfg, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
    }
 
    public <V> ReplaceOperation<V> newReplaceOperation(Object key, byte[] keyBytes, byte[] values,
            long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) {
       return new ReplaceOperation<V>(
             codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(lifespan, maxIdle),
-            values, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
+            cfg, values, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
    }
 
    public ContainsKeyOperation newContainsKeyOperation(Object key, byte[] keyBytes) {
       return new ContainsKeyOperation(
-            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags());
+            codec, transportFactory, key, keyBytes, cacheNameBytes, topologyId, flags(), cfg);
    }
 
    public ClearOperation newClearOperation() {
       return new ClearOperation(
-            codec, transportFactory, cacheNameBytes, topologyId, flags());
+            codec, transportFactory, cacheNameBytes, topologyId, flags(), cfg);
    }
 
    public <K, V> BulkGetOperation<K, V> newBulkGetOperation(int size) {
       return new BulkGetOperation(
-            codec, transportFactory, cacheNameBytes, topologyId, flags(), size);
+            codec, transportFactory, cacheNameBytes, topologyId, flags(), cfg, size);
    }
 
    public <K> BulkGetKeysOperation<K> newBulkGetKeysOperation(int scope) {
-      return new BulkGetKeysOperation<K>(
-         codec, transportFactory, cacheNameBytes, topologyId, flags(), scope);
+      return new BulkGetKeysOperation<>(
+         codec, transportFactory, cacheNameBytes, topologyId, flags(), cfg, scope);
    }
 
    public AddClientListenerOperation newAddClientListenerOperation(Object listener) {
       return new AddClientListenerOperation(codec, transportFactory,
-            cacheName, topologyId, flags(), listenerNotifier,
+            cacheName, topologyId, flags(), cfg, listenerNotifier,
             listener, null, null);
    }
 
    public AddClientListenerOperation newAddClientListenerOperation(
          Object listener, byte[][] filterFactoryParams, byte[][] converterFactoryParams) {
       return new AddClientListenerOperation(codec, transportFactory,
-            cacheName, topologyId, flags(), listenerNotifier,
+            cacheName, topologyId, flags(), cfg, listenerNotifier,
             listener, filterFactoryParams, converterFactoryParams);
    }
 
    public RemoveClientListenerOperation newRemoveClientListenerOperation(Object listener) {
       return new RemoveClientListenerOperation(codec, transportFactory,
-            cacheNameBytes, topologyId, flags(), listenerNotifier, listener);
+            cacheNameBytes, topologyId, flags(), cfg, listenerNotifier, listener);
    }
 
    /**
@@ -183,7 +191,7 @@ public RemoveClientListenerOperation newRemoveClientListenerOperation(Object lis
     * @return a ping operation for a particular node
     */
    public PingOperation newPingOperation(Transport transport) {
-      return new PingOperation(codec, topologyId, transport, cacheNameBytes);
+      return new PingOperation(codec, topologyId, cfg, transport, cacheNameBytes);
    }
 
    /**
@@ -195,21 +203,22 @@ public PingOperation newPingOperation(Transport transport) {
     */
    public FaultTolerantPingOperation newFaultTolerantPingOperation() {
       return new FaultTolerantPingOperation(
-            codec, transportFactory, cacheNameBytes, topologyId, flags());
+            codec, transportFactory, cacheNameBytes, topologyId, flags(), cfg);
    }
 
    public QueryOperation newQueryOperation(RemoteQuery remoteQuery) {
       return new QueryOperation(
-            codec, transportFactory, cacheNameBytes, topologyId, flags(), remoteQuery);
+            codec, transportFactory, cacheNameBytes, topologyId, flags(), cfg, remoteQuery);
    }
 
    public SizeOperation newSizeOperation() {
-      return new SizeOperation(codec, transportFactory, cacheNameBytes, topologyId, flags());
+      return new SizeOperation(codec, transportFactory, cacheNameBytes, topologyId, flags(), cfg);
    }
 
    public <T> ExecuteOperation<T> newExecuteOperation(String taskName, Map<String, byte[]> marshalledParams) {
-		return new ExecuteOperation<T>(codec, transportFactory, cacheNameBytes, topologyId, flags(), taskName, marshalledParams);
-	}
+      return new ExecuteOperation<>(codec, transportFactory, cacheNameBytes,
+            topologyId, flags(), cfg, taskName, marshalledParams);
+   }
 
    private int flags(long lifespan, long maxIdle) {
       int intFlags = flags();
@@ -265,14 +274,15 @@ public CacheTopologyInfo getCacheTopologyInfo() {
    }
 
    public IterationStartOperation newIterationStartOperation(String filterConverterFactory, byte[][] filterParameters, Set<Integer> segments, int batchSize, boolean metadata) {
-      return new IterationStartOperation(codec, flags(), cacheNameBytes, topologyId, filterConverterFactory, filterParameters, segments, batchSize, transportFactory, metadata);
+      return new IterationStartOperation(codec, flags(), cfg, cacheNameBytes, topologyId, filterConverterFactory, filterParameters, segments, batchSize, transportFactory, metadata);
    }
 
    public IterationEndOperation newIterationEndOperation(String iterationId, Transport transport) {
-      return new IterationEndOperation(codec, flags(), cacheNameBytes, topologyId, iterationId, transportFactory, transport);
+      return new IterationEndOperation(codec, flags(), cfg, cacheNameBytes, topologyId, iterationId, transportFactory, transport);
    }
 
    public <K, V> IterationNextOperation newIterationNextOperation(String iterationId, Transport transport, KeyTracker segmentKeyTracker) {
-      return new IterationNextOperation(codec, flags(), cacheNameBytes, topologyId, iterationId, transport, segmentKeyTracker);
+      return new IterationNextOperation(codec, flags(), cfg, cacheNameBytes, topologyId, iterationId, transport, segmentKeyTracker, cfg.serialWhitelist());
    }
+
 }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ParallelHotRodOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ParallelHotRodOperation.java
index 8805f84..bdbac82 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ParallelHotRodOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ParallelHotRodOperation.java
@@ -10,6 +10,7 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.exceptions.ParallelOperationException;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.transport.TransportFactory;
@@ -30,8 +31,8 @@
    protected final CompletionService<T> completionService;
 
    protected ParallelHotRodOperation(Codec codec, TransportFactory transportFactory, byte[] cacheName, AtomicInteger
-         topologyId, int flags, ExecutorService executorService) {
-      super(codec, flags, cacheName, topologyId);
+         topologyId, int flags, Configuration cfg, ExecutorService executorService) {
+      super(codec, flags, cfg, cacheName, topologyId);
       this.transportFactory = transportFactory;
       this.completionService = new ExecutorCompletionService<>(executorService);
    }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PingOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PingOperation.java
index 7376407..8670cec 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PingOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PingOperation.java
@@ -4,6 +4,7 @@
 
 import net.jcip.annotations.Immutable;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.exceptions.HotRodClientException;
 import org.infinispan.client.hotrod.exceptions.InvalidResponseException;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
@@ -27,12 +28,12 @@
 
    private final Transport transport;
 
-   public PingOperation(Codec codec, AtomicInteger topologyId, Transport transport) {
-      this(codec, topologyId, transport, DEFAULT_CACHE_NAME_BYTES);
+   public PingOperation(Codec codec, AtomicInteger topologyId, Configuration cfg, Transport transport) {
+      this(codec, topologyId, cfg, transport, DEFAULT_CACHE_NAME_BYTES);
    }
 
-   public PingOperation(Codec codec, AtomicInteger topologyId, Transport transport, byte[] cacheName) {
-      super(codec, 0, cacheName, topologyId);
+   public PingOperation(Codec codec, AtomicInteger topologyId, Configuration cfg, Transport transport, byte[] cacheName) {
+      super(codec, 0, cfg, cacheName, topologyId);
       this.transport = transport;
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutAllOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutAllOperation.java
index 4dfec2a..5debc01 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutAllOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutAllOperation.java
@@ -9,6 +9,7 @@
 
 import net.jcip.annotations.Immutable;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.exceptions.InvalidResponseException;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
@@ -27,8 +28,9 @@
 
    public PutAllOperation(Codec codec, TransportFactory transportFactory,
                           Map<byte[], byte[]> map, byte[] cacheName, AtomicInteger topologyId,
-                          int flags, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+                          int flags, Configuration cfg,
+                          long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
       this.map = map;
       this.lifespan = lifespan;
       this.lifespanTimeUnit = lifespanTimeUnit;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutAllParallelOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutAllParallelOperation.java
index 4c866d1..48f6fe6 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutAllParallelOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutAllParallelOperation.java
@@ -9,6 +9,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.transport.TransportFactory;
 
@@ -24,9 +25,10 @@
    private final TimeUnit maxIdleTimeUnit;
 
    public PutAllParallelOperation(Codec codec, TransportFactory transportFactory, Map<byte[], byte[]> map, byte[]
-         cacheName, AtomicInteger topologyId, int flags, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle,
+         cacheName, AtomicInteger topologyId, int flags, Configuration cfg, long lifespan,
+                                  TimeUnit lifespanTimeUnit, long maxIdle,
                                   TimeUnit maxIdleTimeUnit, ExecutorService executorService) {
-      super(codec, transportFactory, cacheName, topologyId, flags, executorService);
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg, executorService);
       this.map = map;
       this.lifespan = lifespan;
       this.lifespanTimeUnit = lifespanTimeUnit;
@@ -50,7 +52,7 @@ public PutAllParallelOperation(Codec codec, TransportFactory transportFactory, M
 
       return splittedMaps.values().stream().map(
             mapSubset -> new PutAllOperation(codec, transportFactory, mapSubset, cacheName, topologyId, flags,
-                  lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit)).collect(Collectors.toList());
+                  cfg, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit)).collect(Collectors.toList());
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutIfAbsentOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutIfAbsentOperation.java
index 11b3186..ef5d589 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutIfAbsentOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutIfAbsentOperation.java
@@ -5,6 +5,7 @@
 
 import net.jcip.annotations.Immutable;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -27,8 +28,10 @@
 
    public PutIfAbsentOperation(Codec codec, TransportFactory transportFactory,
                                Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId,
-                               int flags, byte[] value, long lifespan,TimeUnit lifespanTimeUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
-      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, value, lifespan, lifespanTimeUnit, maxIdleTime, maxIdleTimeUnit);
+                               int flags, Configuration cfg, byte[] value, long lifespan,
+                               TimeUnit lifespanTimeUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
+      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, cfg, value,
+            lifespan, lifespanTimeUnit, maxIdleTime, maxIdleTimeUnit);
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutOperation.java
index 4723795..25c6ef1 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/PutOperation.java
@@ -5,6 +5,7 @@
 
 import net.jcip.annotations.Immutable;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.exceptions.InvalidResponseException;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
@@ -22,9 +23,10 @@
 
    public PutOperation(Codec codec, TransportFactory transportFactory,
                        Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId,
-                       int flags, byte[] value, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) {
+                       int flags, Configuration cfg, byte[] value, long lifespan, TimeUnit lifespanTimeUnit,
+                       long maxIdle, TimeUnit maxIdleTimeUnit) {
       super(codec, transportFactory, key, keyBytes, cacheName, topologyId,
-         flags, value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
+         flags, cfg, value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/QueryOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/QueryOperation.java
index 1c556cd..b829d31 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/QueryOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/QueryOperation.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.operations;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.query.RemoteQuery;
@@ -30,8 +31,8 @@
    private final RemoteQuery remoteQuery;
 
    public QueryOperation(Codec codec, TransportFactory transportFactory, byte[] cacheName, AtomicInteger topologyId,
-                         int flags, RemoteQuery remoteQuery) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+                         int flags, Configuration cfg, RemoteQuery remoteQuery) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
       this.remoteQuery = remoteQuery;
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveClientListenerOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveClientListenerOperation.java
index c3c9ee9..33f5828 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveClientListenerOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveClientListenerOperation.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.operations;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.event.ClientListenerNotifier;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
@@ -28,8 +29,9 @@
 
    protected RemoveClientListenerOperation(Codec codec, TransportFactory transportFactory,
                                            byte[] cacheName, AtomicInteger topologyId, int flags,
+                                           Configuration cfg,
                                            ClientListenerNotifier listenerNotifier, Object listener) {
-      super(codec, flags, cacheName, topologyId);
+      super(codec, flags, cfg, cacheName, topologyId);
       this.transportFactory = transportFactory;
       this.listenerNotifier = listenerNotifier;
       this.listener = listener;
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveIfUnmodifiedOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveIfUnmodifiedOperation.java
index b052d61..8f86c1b 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveIfUnmodifiedOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveIfUnmodifiedOperation.java
@@ -1,6 +1,7 @@
 package org.infinispan.client.hotrod.impl.operations;
 
 import net.jcip.annotations.Immutable;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.VersionedOperationResponse;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
@@ -22,8 +23,10 @@
    private final long version;
 
    public RemoveIfUnmodifiedOperation(Codec codec, TransportFactory transportFactory,
-         Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags, long version) {
-      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags);
+                                      Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId,
+                                      int flags, Configuration cfg,
+                                      long version) {
+      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, cfg);
       this.version = version;
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveOperation.java
index 8f48e61..715c253 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RemoveOperation.java
@@ -1,6 +1,7 @@
 package org.infinispan.client.hotrod.impl.operations;
 
 import net.jcip.annotations.Immutable;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -19,8 +20,8 @@
 public class RemoveOperation<V> extends AbstractKeyOperation<V> {
 
    public RemoveOperation(Codec codec, TransportFactory transportFactory,
-         Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags);
+         Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId, int flags, Configuration cfg) {
+      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, cfg);
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ReplaceIfUnmodifiedOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ReplaceIfUnmodifiedOperation.java
index 96f675e..be3a31a 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ReplaceIfUnmodifiedOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ReplaceIfUnmodifiedOperation.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.operations;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.VersionedOperationResponse;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
@@ -20,9 +21,9 @@
    private final long version;
 
    public ReplaceIfUnmodifiedOperation(Codec codec, TransportFactory transportFactory, Object key, byte[] keyBytes, byte[] cacheName,
-                                       AtomicInteger topologyId, int flags, byte[] value,
+                                       AtomicInteger topologyId, int flags, Configuration cfg, byte[] value,
                                        long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit, long version) {
-      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
+      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, cfg, value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
       this.version = version;
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ReplaceOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ReplaceOperation.java
index 20d30dc..e88460d 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ReplaceOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/ReplaceOperation.java
@@ -2,6 +2,7 @@
 
 import net.jcip.annotations.Immutable;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.transport.Transport;
 import org.infinispan.client.hotrod.impl.transport.TransportFactory;
@@ -20,9 +21,11 @@
 public class ReplaceOperation<V> extends AbstractKeyValueOperation<V> {
 
    public ReplaceOperation(Codec codec, TransportFactory transportFactory,
-            Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId,
-            int flags, byte[] value, long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) {
-      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, value, lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
+                           Object key, byte[] keyBytes, byte[] cacheName, AtomicInteger topologyId,
+                           int flags, Configuration cfg, byte[] value,
+                           long lifespan, TimeUnit lifespanTimeUnit, long maxIdle, TimeUnit maxIdleTimeUnit) {
+      super(codec, transportFactory, key, keyBytes, cacheName, topologyId, flags, cfg, value,
+            lifespan, lifespanTimeUnit, maxIdle, maxIdleTimeUnit);
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RetryOnFailureOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RetryOnFailureOperation.java
index 6740aef..8fa7922 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RetryOnFailureOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/RetryOnFailureOperation.java
@@ -1,6 +1,7 @@
 package org.infinispan.client.hotrod.impl.operations;
 
 import net.jcip.annotations.Immutable;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.exceptions.HotRodClientException;
 import org.infinispan.client.hotrod.exceptions.RemoteIllegalLifecycleStateException;
 import org.infinispan.client.hotrod.exceptions.RemoteNodeSuspectException;
@@ -36,8 +37,8 @@
    private boolean triedCompleteRestart = false;
 
    protected RetryOnFailureOperation(Codec codec, TransportFactory transportFactory,
-                                     byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, flags, cacheName, topologyId);
+                                     byte[] cacheName, AtomicInteger topologyId, int flags, Configuration cfg) {
+      super(codec, flags, cfg, cacheName, topologyId);
       this.transportFactory = transportFactory;
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/SizeOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/SizeOperation.java
index 262f6ce..e944748 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/SizeOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/SizeOperation.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.operations;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -12,8 +13,8 @@
 public class SizeOperation extends RetryOnFailureOperation<Integer> {
 
    protected SizeOperation(Codec codec, TransportFactory transportFactory,
-                           byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+                           byte[] cacheName, AtomicInteger topologyId, int flags, Configuration cfg) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/StatsOperation.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/StatsOperation.java
index 0fd940e..a503f25 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/StatsOperation.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/operations/StatsOperation.java
@@ -1,6 +1,8 @@
 package org.infinispan.client.hotrod.impl.operations;
 
 import net.jcip.annotations.Immutable;
+
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
 import org.infinispan.client.hotrod.impl.transport.Transport;
@@ -22,8 +24,8 @@
 public class StatsOperation extends RetryOnFailureOperation<Map<String, String>> {
 
    public StatsOperation(Codec codec, TransportFactory transportFactory,
-                         byte[] cacheName, AtomicInteger topologyId, int flags) {
-      super(codec, transportFactory, cacheName, topologyId, flags);
+                         byte[] cacheName, AtomicInteger topologyId, int flags, Configuration cfg) {
+      super(codec, transportFactory, cacheName, topologyId, flags, cfg);
    }
 
    @Override
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec.java
index 5793516..73f5cc8 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.impl.protocol;
 
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import org.infinispan.client.hotrod.annotation.ClientListener;
@@ -40,11 +41,11 @@ void writeClientListenerParams(Transport transport, ClientListener clientListene
     */
    short readHeader(Transport transport, HeaderParams params);
 
-   ClientEvent readEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller);
+   ClientEvent readEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller, List<String> whitelist);
 
-   Either<Short, ClientEvent> readHeaderOrEvent(Transport transport, HeaderParams params, byte[] expectedListenerId, Marshaller marshaller);
+   Either<Short, ClientEvent> readHeaderOrEvent(Transport transport, HeaderParams params, byte[] expectedListenerId, Marshaller marshaller, List<String> whitelist);
 
-   Object returnPossiblePrevValue(Transport transport, short status, int flags);
+   Object returnPossiblePrevValue(Transport transport, short status, int flags, List<String> whitelist);
 
    /**
     * Logger for Hot Rod client codec
@@ -54,5 +55,5 @@ void writeClientListenerParams(Transport transport, ClientListener clientListene
    /**
     * Read and unmarshall byte array.
     */
-   <T> T readUnmarshallByteArray(Transport transport, short status);
+   <T> T readUnmarshallByteArray(Transport transport, short status, List<String> whitelist);
 }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec10.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec10.java
index c89aa27..e0119a6 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec10.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec10.java
@@ -6,6 +6,7 @@
 import java.net.SocketAddress;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -130,23 +131,23 @@ public short readHeader(Transport transport, HeaderParams params) {
    }
 
    @Override
-   public ClientEvent readEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller) {
+   public ClientEvent readEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller, List<String> whitelist) {
       return null;  // No events sent in Hot Rod 1.x protocol
    }
 
    @Override
-   public Either<Short, ClientEvent> readHeaderOrEvent(Transport transport, HeaderParams params, byte[] expectedListenerId, Marshaller marshaller) {
+   public Either<Short, ClientEvent> readHeaderOrEvent(Transport transport, HeaderParams params, byte[] expectedListenerId, Marshaller marshaller, List<String> whitelist) {
       return null;  // No events sent in Hot Rod 1.x protocol
    }
 
    @Override
-   public Object returnPossiblePrevValue(Transport transport, short status, int flags) {
+   public Object returnPossiblePrevValue(Transport transport, short status, int flags, List<String> whitelist) {
       Marshaller marshaller = transport.getTransportFactory().getMarshaller();
       if (hasForceReturn(flags)) {
          byte[] bytes = transport.readArray();
          if (trace) getLog().tracef("Previous value bytes is: %s", Util.printArray(bytes, false));
          //0-length response means null
-         return bytes.length == 0 ? null : MarshallerUtil.bytes2obj(marshaller, bytes, status);
+         return bytes.length == 0 ? null : MarshallerUtil.bytes2obj(marshaller, bytes, status, whitelist);
       } else {
          return null;
       }
@@ -162,8 +163,8 @@ public Log getLog() {
    }
 
    @Override
-   public <T> T readUnmarshallByteArray(Transport transport, short status) {
-      return CodecUtils.readUnmarshallByteArray(transport, status);
+   public <T> T readUnmarshallByteArray(Transport transport, short status, List<String> whitelist) {
+      return CodecUtils.readUnmarshallByteArray(transport, status, whitelist);
    }
 
    protected void checkForErrorsInResponseStatus(Transport transport, HeaderParams params, short status) {
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec20.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec20.java
index 97ee675..c502742 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec20.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec20.java
@@ -44,8 +44,8 @@
    final boolean trace = getLog().isTraceEnabled();
 
    @Override
-   public <T> T readUnmarshallByteArray(Transport transport, short status) {
-      return CodecUtils.readUnmarshallByteArray(transport, status);
+   public <T> T readUnmarshallByteArray(Transport transport, short status, List<String> whitelist) {
+      return CodecUtils.readUnmarshallByteArray(transport, status, whitelist);
    }
 
    @Override
@@ -143,14 +143,14 @@ private short readPartialHeader(Transport transport, HeaderParams params, short
    }
 
    @Override
-   public ClientEvent readEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller) {
+   public ClientEvent readEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller, List<String> whitelist) {
       readMagic(transport);
       readMessageId(transport, null);
       short eventTypeId = transport.readByte();
-      return readPartialEvent(transport, expectedListenerId, marshaller, eventTypeId);
+      return readPartialEvent(transport, expectedListenerId, marshaller, eventTypeId, whitelist);
    }
 
-   protected ClientEvent readPartialEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller, short eventTypeId) {
+   protected ClientEvent readPartialEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller, short eventTypeId, List<String> whitelist) {
       short status = transport.readByte();
       transport.readByte(); // ignore, no topology expected
       ClientEvent.Type eventType;
@@ -179,20 +179,20 @@ protected ClientEvent readPartialEvent(Transport transport, byte[] expectedListe
       boolean isRetried = transport.readByte() == 1 ? true : false;
 
       if (isCustom == 1) {
-         final Object eventData = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status);
+         final Object eventData = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status, whitelist);
          return createCustomEvent(eventData, eventType, isRetried);
       } else {
          switch (eventType) {
             case CLIENT_CACHE_ENTRY_CREATED:
-               Object createdKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status);
+               Object createdKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status, whitelist);
                long createdDataVersion = transport.readLong();
                return createCreatedEvent(createdKey, createdDataVersion, isRetried);
             case CLIENT_CACHE_ENTRY_MODIFIED:
-               Object modifiedKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status);
+               Object modifiedKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status, whitelist);
                long modifiedDataVersion = transport.readLong();
                return createModifiedEvent(modifiedKey, modifiedDataVersion, isRetried);
             case CLIENT_CACHE_ENTRY_REMOVED:
-               Object removedKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status);
+               Object removedKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status, whitelist);
                return createRemovedEvent(removedKey, isRetried);
             default:
                throw log.unknownEvent(eventTypeId);
@@ -201,7 +201,7 @@ protected ClientEvent readPartialEvent(Transport transport, byte[] expectedListe
    }
 
    @Override
-   public Either<Short, ClientEvent> readHeaderOrEvent(Transport transport, HeaderParams params, byte[] expectedListenerId, Marshaller marshaller) {
+   public Either<Short, ClientEvent> readHeaderOrEvent(Transport transport, HeaderParams params, byte[] expectedListenerId, Marshaller marshaller, List<String> whitelist) {
       readMagic(transport);
       readMessageId(transport, null);
       short opCode = transport.readByte();
@@ -209,7 +209,7 @@ protected ClientEvent readPartialEvent(Transport transport, byte[] expectedListe
          case CACHE_ENTRY_CREATED_EVENT_RESPONSE:
          case CACHE_ENTRY_MODIFIED_EVENT_RESPONSE:
          case CACHE_ENTRY_REMOVED_EVENT_RESPONSE:
-            ClientEvent clientEvent = readPartialEvent(transport, expectedListenerId, marshaller, opCode);
+            ClientEvent clientEvent = readPartialEvent(transport, expectedListenerId, marshaller, opCode, whitelist);
             return Either.newRight(clientEvent);
          default:
             return Either.newLeft(readPartialHeader(transport, params, opCode));
@@ -217,13 +217,13 @@ protected ClientEvent readPartialEvent(Transport transport, byte[] expectedListe
    }
 
    @Override
-   public Object returnPossiblePrevValue(Transport transport, short status, int flags) {
+   public Object returnPossiblePrevValue(Transport transport, short status, int flags, List<String> whitelist) {
       Marshaller marshaller = transport.getTransportFactory().getMarshaller();
       if (HotRodConstants.hasPrevious(status)) {
          byte[] bytes = transport.readArray();
          if (trace) getLog().tracef("Previous value bytes is: %s", printArray(bytes, false));
          //0-length response means null
-         return bytes.length == 0 ? null : MarshallerUtil.bytes2obj(marshaller, bytes, status);
+         return bytes.length == 0 ? null : MarshallerUtil.bytes2obj(marshaller, bytes, status, whitelist);
       } else {
          return null;
       }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec21.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec21.java
index 62bb2df..80a15aa 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec21.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/Codec21.java
@@ -10,6 +10,7 @@
 import org.infinispan.commons.marshall.Marshaller;
 
 import java.util.Arrays;
+import java.util.List;
 
 import static org.infinispan.commons.util.Util.printArray;
 
@@ -34,7 +35,7 @@ public void writeClientListenerParams(Transport transport, ClientListener client
    }
 
    @Override
-   protected ClientEvent readPartialEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller, short eventTypeId) {
+   protected ClientEvent readPartialEvent(Transport transport, byte[] expectedListenerId, Marshaller marshaller, short eventTypeId, List<String> whitelist) {
       short status = transport.readByte();
       transport.readByte(); // ignore, no topology expected
       ClientEvent.Type eventType;
@@ -65,25 +66,25 @@ protected ClientEvent readPartialEvent(Transport transport, byte[] expectedListe
       boolean isRetried = transport.readByte() == 1 ? true : false;
 
       if (isCustom == 1) {
-         final Object eventData = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status);
+         final Object eventData = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status, whitelist);
          return createCustomEvent(eventData, eventType, isRetried);
       } else if (isCustom == 2) { // New in 2.1, dealing with raw custom events
          return createCustomEvent(transport.readArray(), eventType, isRetried); // Raw data
       } else {
          switch (eventType) {
             case CLIENT_CACHE_ENTRY_CREATED:
-               Object createdKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status);
+               Object createdKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status, whitelist);
                long createdDataVersion = transport.readLong();
                return createCreatedEvent(createdKey, createdDataVersion, isRetried);
             case CLIENT_CACHE_ENTRY_MODIFIED:
-               Object modifiedKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status);
+               Object modifiedKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status, whitelist);
                long modifiedDataVersion = transport.readLong();
                return createModifiedEvent(modifiedKey, modifiedDataVersion, isRetried);
             case CLIENT_CACHE_ENTRY_REMOVED:
-               Object removedKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status);
+               Object removedKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status, whitelist);
                return createRemovedEvent(removedKey, isRetried);
             case CLIENT_CACHE_ENTRY_EXPIRED:
-               Object expiredKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status);
+               Object expiredKey = MarshallerUtil.bytes2obj(marshaller, transport.readArray(), status, whitelist);
                return createExpiredEvent(expiredKey);
             default:
                throw getLog().unknownEvent(eventTypeId);
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/CodecUtils.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/CodecUtils.java
index 8315490..d8cd36a 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/CodecUtils.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/protocol/CodecUtils.java
@@ -4,6 +4,7 @@
 import org.infinispan.client.hotrod.marshall.MarshallerUtil;
 import org.infinispan.commons.marshall.Marshaller;
 
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -31,10 +32,10 @@ public static int toSeconds(long duration, TimeUnit timeUnit) {
       return seconds;
    }
 
-   static <T> T readUnmarshallByteArray(Transport transport, short status) {
+   static <T> T readUnmarshallByteArray(Transport transport, short status, List<String> whitelist) {
       byte[] bytes = transport.readArray();
       Marshaller marshaller = transport.getTransportFactory().getMarshaller();
-      return MarshallerUtil.bytes2obj(marshaller, bytes, status);
+      return MarshallerUtil.bytes2obj(marshaller, bytes, status, whitelist);
    }
 
 }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/SaslTransportObjectFactory.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/SaslTransportObjectFactory.java
index 0fe2cec..b022d1e 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/SaslTransportObjectFactory.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/SaslTransportObjectFactory.java
@@ -16,6 +16,7 @@
 import javax.security.sasl.SaslException;
 
 import org.infinispan.client.hotrod.configuration.AuthenticationConfiguration;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.operations.AuthMechListOperation;
 import org.infinispan.client.hotrod.impl.operations.AuthOperation;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
@@ -34,12 +35,13 @@
    private static final byte[] EMPTY_BYTES = new byte[0];
    private static final String AUTH_INT = "auth-int";
    private static final String AUTH_CONF = "auth-conf";
-   private final AuthenticationConfiguration configuration;
+   private final AuthenticationConfiguration authConfiguration;
 
    public SaslTransportObjectFactory(Codec codec, TcpTransportFactory tcpTransportFactory,
-         AtomicInteger defaultCacheTopologyId, boolean pingOnStartup, AuthenticationConfiguration configuration) {
-      super(codec, tcpTransportFactory, defaultCacheTopologyId, pingOnStartup);
-      this.configuration = configuration;
+         AtomicInteger defaultCacheTopologyId, boolean pingOnStartup,
+         AuthenticationConfiguration authConfiguration, Configuration configuration) {
+      super(codec, tcpTransportFactory, defaultCacheTopologyId, pingOnStartup, configuration);
+      this.authConfiguration = authConfiguration;
    }
 
    @Override
@@ -50,34 +52,34 @@ public TcpTransport makeObject(SocketAddress address) throws Exception {
       }
 
       List<String> serverMechs = mechList(tcpTransport, defaultCacheTopologyId);
-      if (!serverMechs.contains(configuration.saslMechanism())) {
-         throw log.unsupportedMech(configuration.saslMechanism(), serverMechs);
+      if (!serverMechs.contains(authConfiguration.saslMechanism())) {
+         throw log.unsupportedMech(authConfiguration.saslMechanism(), serverMechs);
       }
 
       SaslClient saslClient;
-      if (configuration.clientSubject() != null) {
-         saslClient = Subject.doAs(configuration.clientSubject(), new PrivilegedExceptionAction<SaslClient>() {
+      if (authConfiguration.clientSubject() != null) {
+         saslClient = Subject.doAs(authConfiguration.clientSubject(), new PrivilegedExceptionAction<SaslClient>() {
             @Override
             public SaslClient run() throws Exception {
-               CallbackHandler callbackHandler = configuration.callbackHandler();
+               CallbackHandler callbackHandler = authConfiguration.callbackHandler();
                if (callbackHandler == null) {
                   callbackHandler = NoOpCallbackHandler.INSTANCE;
                }
-            return Sasl.createSaslClient(new String[] { configuration.saslMechanism() }, null, "hotrod",
-                     configuration.serverName(), configuration.saslProperties(), callbackHandler);
+            return Sasl.createSaslClient(new String[] { authConfiguration.saslMechanism() }, null, "hotrod",
+               authConfiguration.serverName(), authConfiguration.saslProperties(), callbackHandler);
             }
          });
       } else {
-         saslClient = Sasl.createSaslClient(new String[] { configuration.saslMechanism() }, null, "hotrod",
-               configuration.serverName(), configuration.saslProperties(), configuration.callbackHandler());
+         saslClient = Sasl.createSaslClient(new String[] { authConfiguration.saslMechanism() }, null, "hotrod",
+            authConfiguration.serverName(), authConfiguration.saslProperties(), authConfiguration.callbackHandler());
       }
 
       if (trace) {
-         log.tracef("Authenticating using mech: %s", configuration.saslMechanism());
+         log.tracef("Authenticating using mech: %s", authConfiguration.saslMechanism());
       }
       byte response[] = saslClient.hasInitialResponse() ? evaluateChallenge(saslClient, EMPTY_BYTES) : EMPTY_BYTES;
 
-      byte challenge[] = auth(tcpTransport, defaultCacheTopologyId, configuration.saslMechanism(), response);
+      byte challenge[] = auth(tcpTransport, defaultCacheTopologyId, authConfiguration.saslMechanism(), response);
       while (!saslClient.isComplete() && challenge != null) {
          response = evaluateChallenge(saslClient, challenge);
          if (response == null) {
@@ -105,9 +107,9 @@ public SaslClient run() throws Exception {
    }
 
    private byte[] evaluateChallenge(final SaslClient saslClient, final byte[] challenge) throws SaslException {
-      if(configuration.clientSubject()!= null) {
+      if(authConfiguration.clientSubject()!= null) {
          try {
-            return Subject.doAs(configuration.clientSubject(), new PrivilegedExceptionAction<byte[]>() {
+            return Subject.doAs(authConfiguration.clientSubject(), new PrivilegedExceptionAction<byte[]>() {
                @Override
                public byte[] run() throws Exception {
                   return saslClient.evaluateChallenge(challenge);
@@ -127,12 +129,12 @@ public SaslClient run() throws Exception {
    }
 
    private List<String> mechList(TcpTransport tcpTransport, AtomicInteger topologyId) {
-      AuthMechListOperation op = new AuthMechListOperation(codec, topologyId, tcpTransport);
+      AuthMechListOperation op = new AuthMechListOperation(codec, topologyId, configuration, tcpTransport);
       return op.execute();
    }
 
    private byte[] auth(TcpTransport tcpTransport, AtomicInteger topologyId, String mech, byte[] response) {
-      AuthOperation op = new AuthOperation(codec, topologyId, tcpTransport, mech, response);
+      AuthOperation op = new AuthOperation(codec, topologyId, configuration, tcpTransport, mech, response);
       return op.execute();
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/TcpTransportFactory.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/TcpTransportFactory.java
index 1591e79..21cce28 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/TcpTransportFactory.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/TcpTransportFactory.java
@@ -136,9 +136,9 @@ public void start(Codec codec, Configuration configuration, AtomicInteger defaul
          }
          TransportObjectFactory connectionFactory;
          if (configuration.security().authentication().enabled()) {
-            connectionFactory = new SaslTransportObjectFactory(codec, this, defaultCacheTopologyId, pingOnStartup, configuration.security().authentication());
+            connectionFactory = new SaslTransportObjectFactory(codec, this, defaultCacheTopologyId, pingOnStartup, configuration.security().authentication(), configuration);
          } else {
-            connectionFactory = new TransportObjectFactory(codec, this, defaultCacheTopologyId, pingOnStartup);
+            connectionFactory = new TransportObjectFactory(codec, this, defaultCacheTopologyId, pingOnStartup, configuration);
          }
          PropsKeyedObjectPoolFactory<SocketAddress, TcpTransport> poolFactory =
                  new PropsKeyedObjectPoolFactory<SocketAddress, TcpTransport>(
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/TransportObjectFactory.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/TransportObjectFactory.java
index 8b7309c..fe16598 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/TransportObjectFactory.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/tcp/TransportObjectFactory.java
@@ -4,6 +4,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.commons.pool.BaseKeyedPoolableObjectFactory;
+import org.infinispan.client.hotrod.configuration.Configuration;
 import org.infinispan.client.hotrod.impl.operations.PingOperation;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.logging.Log;
@@ -23,13 +24,15 @@
    protected final boolean pingOnStartup;
    protected volatile boolean firstPingExecuted = false;
    protected final Codec codec;
+   protected final Configuration configuration;
 
    public TransportObjectFactory(Codec codec, TcpTransportFactory tcpTransportFactory,
-         AtomicInteger defaultCacheTopologyId, boolean pingOnStartup) {
+         AtomicInteger defaultCacheTopologyId, boolean pingOnStartup, Configuration configuration) {
       this.tcpTransportFactory = tcpTransportFactory;
       this.defaultCacheTopologyId = defaultCacheTopologyId;
       this.pingOnStartup = pingOnStartup;
       this.codec = codec;
+      this.configuration = configuration;
    }
 
    @Override
@@ -48,7 +51,7 @@ public TcpTransport makeObject(SocketAddress address) throws Exception {
    }
 
    protected PingOperation.PingResult ping(TcpTransport tcpTransport, AtomicInteger topologyId) {
-      PingOperation po = new PingOperation(codec, topologyId, tcpTransport);
+      PingOperation po = new PingOperation(codec, topologyId, configuration, tcpTransport);
       return po.execute();
    }
 
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/logging/Log.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/logging/Log.java
index 9571d5c..22514fe 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/logging/Log.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/logging/Log.java
@@ -6,6 +6,7 @@
 import org.infinispan.client.hotrod.impl.transport.Transport;
 import org.infinispan.client.hotrod.impl.transport.tcp.TcpTransport;
 import org.infinispan.commons.CacheConfigurationException;
+import org.infinispan.commons.CacheException;
 import org.infinispan.commons.CacheListenerException;
 import org.jboss.logging.BasicLogger;
 import org.jboss.logging.annotations.Cause;
@@ -260,4 +261,7 @@
    @Message(value = "Classpath does not look correct. Make sure you are not mixing uber and jars", id = 4065)
    void warnAboutUberJarDuplicates();
 
+   @Message(value = "Class '%s' blocked by Java standard deserialization white list. Adjust the client configuration java serialization white list regular expression to include this class.", id = 4068)
+   CacheException classNotInWhitelist(String className);
+
 }
diff --git a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/marshall/MarshallerUtil.java b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/marshall/MarshallerUtil.java
index 56e4947..876fa6d 100644
--- a/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/marshall/MarshallerUtil.java
+++ b/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/marshall/MarshallerUtil.java
@@ -4,13 +4,19 @@
 import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
 import org.infinispan.client.hotrod.logging.Log;
 import org.infinispan.client.hotrod.logging.LogFactory;
+import org.infinispan.commons.CacheException;
 import org.infinispan.commons.marshall.Marshaller;
 import org.infinispan.commons.util.Util;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
 import java.io.ObjectStreamConstants;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * @author Galder Zamarreño
@@ -22,8 +28,8 @@
    private MarshallerUtil() {}
 
    @SuppressWarnings("unchecked")
-   public static <T> T bytes2obj(Marshaller marshaller, byte[] bytes, short status) {
-      if (bytes == null) return null;
+   public static <T> T bytes2obj(Marshaller marshaller, byte[] bytes, short status, List<String> whitelist) {
+         if (bytes == null) return null;
       try {
          Object ret = marshaller.objectFromByteBuffer(bytes);
          if (HotRodConstants.hasCompatibility(status)) {
@@ -33,12 +39,9 @@ private MarshallerUtil() {}
             // So, if the unmarshalled object is still a byte[], it could be a standard
             // serialized object, so check for stream magic
             if (ret instanceof byte[] && isJavaSerialized((byte[]) ret)) {
-               try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream((byte[]) ret))) {
-                  return (T) ois.readObject();
-               } catch (Exception ee) {
-                  if (log.isDebugEnabled())
-                     log.debugf("Standard deserialization not in use for %s", Util.printArray(bytes));
-               }
+               T ois = tryJavaDeserialize(bytes, (byte[]) ret, whitelist);
+               if (ois != null)
+                  return ois;
             }
          }
 
@@ -48,6 +51,18 @@ private MarshallerUtil() {}
       }
    }
 
+   public static <T> T tryJavaDeserialize(byte[] bytes, byte[] ret, List<String> whitelist) {
+      try (ObjectInputStream ois = new CheckedInputStream(new ByteArrayInputStream(ret), whitelist)) {
+         return (T) ois.readObject();
+      } catch (CacheException ce) {
+         throw ce;
+      } catch (Exception ee) {
+         if (log.isDebugEnabled())
+            log.debugf("Standard deserialization not in use for %s", Util.printArray(bytes));
+      }
+      return null;
+   }
+
    private static boolean isJavaSerialized(byte[] bytes) {
       if (bytes.length > 2) {
          short magic = (short) ((bytes[1] & 0xFF) + (bytes[0] << 8));
@@ -73,4 +88,35 @@ static short getShort(byte[] b, int off) {
       }
    }
 
+   private final static class CheckedInputStream extends ObjectInputStream {
+
+      private final List<String> whitelist;
+
+      public CheckedInputStream(InputStream in, List<String> whitelist) throws IOException {
+         super(in);
+         this.whitelist = whitelist;
+      }
+
+      @Override
+      protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
+         //Enforce SerialKiller's whitelist
+         boolean safeClass = false;
+         for (String whiteRegExp : whitelist) {
+            Pattern whitePattern = Pattern.compile(whiteRegExp);
+            Matcher whiteMatcher = whitePattern.matcher(desc.getName());
+            if (whiteMatcher.find()) {
+               safeClass = true;
+
+               if (log.isTraceEnabled())
+                  log.tracef("Whitelist match: '%s'", desc.getName());
+            }
+         }
+
+         if (!safeClass)
+            throw log.classNotInWhitelist(desc.getName());
+
+         return super.resolveClass(desc);
+      }
+   }
+
 }
diff --git a/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/TransportObjectFactoryTest.java b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/TransportObjectFactoryTest.java
index 689db9b..cc0aa69 100644
--- a/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/TransportObjectFactoryTest.java
+++ b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/TransportObjectFactoryTest.java
@@ -1,5 +1,7 @@
 package org.infinispan.client.hotrod;
 
+import org.infinispan.client.hotrod.configuration.Configuration;
+import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
 import org.infinispan.client.hotrod.exceptions.TransportException;
 import org.infinispan.client.hotrod.impl.protocol.Codec;
 import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
@@ -24,8 +26,9 @@
 
    public void testValidate() {
       Codec codec = mock(Codec.class);
+      Configuration configuration = new ConfigurationBuilder().build();
       TransportObjectFactory objectFactory = new TransportObjectFactory(codec, null,
-                                                                        new AtomicInteger(), false);
+                                                                        new AtomicInteger(), false, configuration);
       doThrow(new TransportException("induced!", null))
             .when(codec).writeHeader(any(Transport.class), any(HeaderParams.class));
 
diff --git a/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/configuration/ConfigurationTest.java b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/configuration/ConfigurationTest.java
index 5be5447..bb562bd 100644
--- a/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/configuration/ConfigurationTest.java
+++ b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/configuration/ConfigurationTest.java
@@ -15,6 +15,8 @@
 import org.infinispan.commons.CacheConfigurationException;
 import org.testng.annotations.Test;
 
+import java.util.Arrays;
+
 @Test(testName = "client.hotrod.configuration.ConfigurationTest", groups = "functional" )
 public class ConfigurationTest {
 
@@ -52,7 +54,8 @@ public void testConfiguration() {
          .valueSizeEstimate(1024)
          .maxRetries(0)
          .tcpKeepAlive(true)
-         .transportFactory(SomeTransportfactory.class);
+         .transportFactory(SomeTransportfactory.class)
+         .addJavaSerialWhiteList(".*Person.*", ".*Employee.*");
 
       Configuration configuration = builder.build();
       validateConfiguration(configuration);
@@ -81,8 +84,8 @@ public void testParseServerAddresses() {
    }
 
    @Test(expectedExceptions = CacheConfigurationException.class,
-         expectedExceptionsMessageRegExp = "ISPN(\\d)*: Invalid max_retries \\(value=-1\\). " +
-               "Value should be greater or equal than zero.")
+      expectedExceptionsMessageRegExp = "ISPN(\\d)*: Invalid max_retries \\(value=-1\\). " +
+         "Value should be greater or equal than zero.")
    public void testNegativeRetriesPerServer() {
       ConfigurationBuilder builder = new ConfigurationBuilder();
       builder.maxRetries(-1);
@@ -180,6 +183,7 @@ private void validateConfiguration(Configuration configuration) {
       assertEquals(128, configuration.keySizeEstimate());
       assertEquals(1024, configuration.valueSizeEstimate());
       assertEquals(0, configuration.maxRetries());
+      assertEquals(Arrays.asList(".*Person.*", ".*Employee.*"), configuration.serialWhitelist());
    }
 
-}
+}
\ No newline at end of file
diff --git a/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/impl/iteration/MultiServerDistRemoteIteratorTest.java b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/impl/iteration/MultiServerDistRemoteIteratorTest.java
index c0233e0..1d76fca 100644
--- a/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/impl/iteration/MultiServerDistRemoteIteratorTest.java
+++ b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/impl/iteration/MultiServerDistRemoteIteratorTest.java
@@ -45,7 +45,7 @@ private ConfigurationBuilder getCacheConfiguration() {
       List<Integer> finished = new ArrayList<>();
 
       @Override
-      public boolean track(byte[] key, short status) {
+      public boolean track(byte[] key, short status, List<String> whitelist) {
          return true;
       }
 
diff --git a/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/retry/RetryOnFailureUnitTest.java b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/retry/RetryOnFailureUnitTest.java
index 8c82f26..82d2c1b 100644
--- a/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/retry/RetryOnFailureUnitTest.java
+++ b/client/hotrod-client/src/test/java/org/infinispan/client/hotrod/retry/RetryOnFailureUnitTest.java
@@ -1,5 +1,6 @@
 package org.infinispan.client.hotrod.retry;
 
+import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
 import org.infinispan.client.hotrod.exceptions.HotRodClientException;
 import org.infinispan.client.hotrod.exceptions.RemoteNodeSuspectException;
 import org.infinispan.client.hotrod.exceptions.TransportException;
@@ -79,7 +80,7 @@ private void doRetryTest(int maxRetry, boolean failOnTransport) {
       private final boolean failOnTransport;
 
       public MockOperation(TransportFactory transportFactory, boolean failOnTransport) {
-         super(null, transportFactory, null, null, 0);
+         super(null, transportFactory, null, null, 0, new ConfigurationBuilder().build());
          this.failOnTransport = failOnTransport;
          transportInvocationCount = new AtomicInteger(0);
          executeInvocationCount = new AtomicInteger(0);
diff --git a/integrationtests/compatibility-mode-it/src/test/java/org/infinispan/it/compatibility/CompatibilityCacheFactory.java b/integrationtests/compatibility-mode-it/src/test/java/org/infinispan/it/compatibility/CompatibilityCacheFactory.java
index ee86291..a648816 100644
--- a/integrationtests/compatibility-mode-it/src/test/java/org/infinispan/it/compatibility/CompatibilityCacheFactory.java
+++ b/integrationtests/compatibility-mode-it/src/test/java/org/infinispan/it/compatibility/CompatibilityCacheFactory.java
@@ -163,6 +163,7 @@ private void createHotRodCache(HotRodServer server) {
       hotrod = server;
       hotrodClient = new RemoteCacheManager(new ConfigurationBuilder()
             .addServers("localhost:" + hotrod.getPort())
+            .addJavaSerialWhiteList(".*Person.*")
             .marshaller(marshaller)
             .build());
       hotrodCache = cacheName.isEmpty()
-- 
2.23.0

