Hazelcast deserializes value on server on get from Binary IMap

Viewed 83

We have an application connecting as client to cluster of Hazelcast servers. Hazelcast version used is 5.1 on both client and servers. We have a IMap<Long, Product> that has been populated previously without problem to the cluster. But when we try to retrieve a value from the IMap, it results in an exception

ERROR o.s.boot.SpringApplication - Application run failed     org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'application': Invocation of init method failed; nested exception is com.hazelcast.nio.serialization.HazelcastSerializationException: No DataSerializerFactory registered for namespace: 1
...
Caused by: com.hazelcast.nio.serialization.HazelcastSerializationException: No DataSerializerFactory registered for namespace: 1
    at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.readInternal(DataSerializableSerializer.java:139)
    at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.read(DataSerializableSerializer.java:106)
    at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.read(DataSerializableSerializer.java:51)
    at com.hazelcast.internal.serialization.impl.StreamSerializerAdapter.read(StreamSerializerAdapter.java:44)

(the get on IMap is during @PostConstruct, that's why "Error creating bean with name 'application'").

The Product class representing the value is implementing the IdentifiedDataSerializable and has on client associated and correctly registered ProductDataSerializableFactory (implements DataSerializableFactory).

The thing is that this exception is NOT originating on the client - it comes from the Hazelcast grid. And that is the issue - because the IMap is defined as BINARY - hence the server should NOT care about DataSerializerFactory, it should simply pass the bytes to the client and let it do the deserialization. So why it is not working as we expect? What might be wrong? And speaking about, how can we register the the above mentioned factory on server as well?

I'm attaching the relevant part of HazelcastConfiguration Java file used on client and hazelcast.xml used on servers below (omitted the unimportant parts like join etc.). It is mostly a default one with some additions, e.g. user-code-deployment. HazelcastConfiguration on client

public HazelcastInstance hazelcastInstance() {
    ClientConfig config = new ClientConfig();
    config.getSerializationConfig().addDataSerializableFactoryClass(ProductDataSerializableFactory.FACTORY_ID, ProductDataSerializableFactory.class);
    ClientUserCodeDeploymentConfig clientUserCodeDeploymentConfig = new ClientUserCodeDeploymentConfig();
    clientUserCodeDeploymentConfig.addClass("com.finmason.product.Product");
    clientUserCodeDeploymentConfig.addClass("com.finmason.product.ProductDataSerializableFactory");
    clientUserCodeDeploymentConfig.setEnabled(true);    
    config.setUserCodeDeploymentConfig(clientUserCodeDeploymentConfig);    
    return HazelcastClient.newHazelcastClient(config);
}

hazelcast.yml on server

hazelcast:
  user-code-deployment:
    enabled: true
    class-cache-mode: ETERNAL
    provider-mode: LOCAL_AND_CACHED_CLASSES
    whitelist-prefixes: com.finmason
    provider-filter: HAS_ATTRIBUTE:lite
  security:
    client-block-unmapped-actions: true
  map:
    default:
      in-memory-format: BINARY
      metadata-policy: CREATE_ON_UPDATE          
  serialization:
    portable-version: 0
  jet:
    enabled: true
    resource-upload-enabled: true

And the source of ProductDataSerializableFactory

public class ProductDataSerializableFactory implements DataSerializableFactory {
    public static final int FACTORY_ID = 1;
    public static final int PRODUCT_TYPE = 1;

    @Override
    public IdentifiedDataSerializable create(int typeId) {
        return (typeId == PRODUCT_TYPE) ? new Product() : null;
    }
}
0 Answers
Related