I am currently using Hazelcast based session manager in my spring(not spring boot) application. I currently hit this problem:
com.hazelcast.nio.serialization.HazelcastSerializationException: java.lang.ClassNotFoundException: com.thg.role.dto.CustomerDTO at com.hazelcast.internal.serialization.impl.defaultserializers.JavaDefaultSerializers$JavaSerializer.read(JavaDefaultSerializers.java:96) at com.hazelcast.internal.serialization.impl.defaultserializers.JavaDefaultSerializers$JavaSerializer.read(JavaDefaultSerializers.java:85) at com.hazelcast.internal.serialization.impl.StreamSerializerAdapter.read(StreamSerializerAdapter.java:44)
I do not want to add a custom jar to the Hazelcast server classpath(My set up is a server-client one). Instead I need a way that Hazelcast can still serialize and deserialize the object. After reading up on Hazelcast documentation, I realized I had to implement a custom Portable serializer. Below is my implementation:
import static org.springframework.session.hazelcast.HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME;
import static org.springframework.session.hazelcast.HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE;
@Configuration
@EnableHazelcastHttpSession
public class HazelCastSessionConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(HazelCastSessionConfig.class);
@Bean
public SessionRepositoryCustomizer<Hazelcast4IndexedSessionRepository> sessionRepositoryCustomizer() {
return sessionRepository -> {
sessionRepository.setFlushMode(FlushMode.IMMEDIATE);
sessionRepository.setSaveMode(SaveMode.ON_SET_ATTRIBUTE);
sessionRepository.setSessionMapName(DEFAULT_SESSION_MAP_NAME);
sessionRepository.setDefaultMaxInactiveInterval(1200);
};
}
@Bean
@SpringSessionHazelcastInstance
public HazelcastInstance hazelcastInstance() {
ClientConfig clientConfig = new ClientConfig();
clientConfig.setClusterName("dev");
clientConfig.setProperty("hazelcast.session.replication.enabled", "true");
clientConfig.setProperty("hazelcast.logging.type", "slf4j");
clientConfig.getNetworkConfig().addAddress("12.30.140.28");
clientConfig.getSerializationConfig().addPortableFactory(PortableAddressDTOFactory.FACTORY_ID, new PortableAddressDTOFactory());
clientConfig.getSerializationConfig().addPortableFactory(PortableCustomerDTOFactory.FACTORY_ID, new PortableCustomerDTOFactory());
var hazelcastClient = HazelcastClient.newHazelcastClient(clientConfig);
configureSessionMap(hazelcastClient);
return hazelcastClient;
}
private void configureSessionMap(HazelcastInstance hazelcastClient) {
var mapCfg = new MapConfig(DEFAULT_SESSION_MAP_NAME);
var attributeConfig = new AttributeConfig()
.setName(PRINCIPAL_NAME_ATTRIBUTE)
.setExtractorClassName(Hazelcast4PrincipalNameExtractor.class.getName());
var indexConfig = new IndexConfig(IndexType.HASH, PRINCIPAL_NAME_ATTRIBUTE);
mapCfg.addAttributeConfig(attributeConfig).addIndexConfig(indexConfig);
hazelcastClient.getConfig().addMapConfig(mapCfg);
}
}
public class CustomerDTOPortableSerializer implements PortableSerializer<CustomerDTO> {
@Override
public int getTypeId() {
// A unique ID for this Portable serializer
return 1;
}
@Override
public void write(PortableWriter writer, CustomerDTO customerDTO) throws IOException {
// Write the fields of the CustomerDTO object to the PortableWriter
writer.writeLong("id", customerDTO.getId());
writer.writeBoolean("authenticated", customerDTO.isAuthenticated());
writer.writeInt("numberOfOrders", customerDTO.getNumberOfOrders());
writer.writeLongArray("ownedProductIds", customerDTO.getOwnedProductIds().toArray(new Long[0]));
}
@Override
public CustomerDTO read(PortableReader reader) throws IOException {
// Read the fields from the PortableReader and create a new //CustomerDTO object
CustomerDTO customerDTO = new CustomerDTO();
customerDTO.setId(reader.readLong("id"));
customerDTO.setAuthenticated(reader.readBoolean("authenticated"));
customerDTO.setNumberOfOrders(reader.readInt("numberOfOrders"));
customerDTO.setOwnedProductIds(Arrays.asList(reader.readLongArray("ownedProductIds")));
return customerDTO;
}
}
CustomerDTO implements Serializable {
//fields, getters and setters..
}
However, when I ran the application, it is still throwing the same error. It looks like my custom Portable class was not registered. Anyone willing to point me to what the problem might be? Hazelcast version: 5.3.2 Management centre version: 5.3.1 Hazelcast client version: 5.2.2
I have tried implementing my own custom Portable serializers but not do not think they are being picked up by the Hazelcast server as the error persists.
That is probably happening because of the misuse of Portable. I see that your class does not implement the Portable interface. It should implement it, not the Serializable.
public class CustomerDTO implements Portable {
}
See this full example in the reference manual to see how the class and its factory should look like:
If you don't want your class to implement a Hazelcast-specific interface, then check out the Compact serialization: