0

I am trying to migrate from Spring Boot 2.7 application with Hazelcast 4.2 to Spring Boot 3.2 and Hazelcast 5.3, which also includes JCache Hazelcast provider.

In previous version I was using WebFilter from Hazelcast (https://github.com/hazelcast/hazelcast-wm/blob/master/src/main/java/com/hazelcast/web/WebFilter.java) registered with FilterRegistrationBean, but it is not prepared for Spring Boot 3 bacause of the lack of jakarta imports.

Because of that I wanted to use Spring Session Hazelcast 3 configuration, but after making request to application I am getting this stacktrace:

com.hazelcast.nio.serialization.HazelcastSerializationException: java.lang.ClassNotFoundException: org.springframework.session.hazelcast.SessionUpdateEntryProcessor
    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 (...)
Caused by: java.lang.ClassNotFoundException: org.springframework.session.hazelcast.SessionUpdateEntryProcessor
    at jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
(...)

So then I added configuration for the hazelcast server and client to use "User Code Deployment" as stated in the documentation (along with Spring one): https://docs.hazelcast.com/hazelcast/5.3/clusters/deploying-code-on-member but then I get error on missing class with @SessionScope - do I have to add jar of classes?

com.hazelcast.core.HazelcastException: java.lang.NoClassDefFoundError: com/g4iner/ExampleCache$Companion
    at com.hazelcast.internal.util.ExceptionUtil.lambda$static$0(ExceptionUtil.java:48)

I get this error after following this documentantion, but I'm not sure if I adjusted this in a right way: https://docs.spring.io/spring-session/reference/3.2/http-session.html#httpsession-hazelcast

There is also some information on Hazelcast but it lacks changes for new versions: https://docs.hazelcast.com/tutorials/spring-session-hazelcast

My configuration and code (using Spring Boot 3.2.6, Hazelcast 5.3.7 client, hazelcast 5.3.7 server running in docker-compose):

docker-compose.yml

version: "3"
services:
  hazelcast:
    image: hazelcast/hazelcast:5.3.7-slim-jdk17
    environment:
      - HZ_USERCODEDEPLOYMENT_ENABLED=true
    ports:
      - "5701:5701"

pom.xml

org.springframework.boot:spring-boot-starter-web-3.2.6
org.springframework.boot:spring-boot-starter-cache-3.2.6
org.springframework.session:spring-session-core-3.2.3
org.springframework.session:spring-session-hazelcast-3.2.3
javax.cache:cache-api-1.1.1
com.hazelcast:hazelcast-spring-5.3.7
com.hazelcast:hazelcast-5.3.7

application.yml

spring:
  cache:
    type: jcache
    jcache:
      provider: com.hazelcast.client.cache.HazelcastClientCachingProvider
  hazelcast:
    config: classpath:hazelcast-client.xml

hazelcast-client.xml

<hazelcast-client xmlns="http://www.hazelcast.com/schema/client-config"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://www.hazelcast.com/schema/client-config
                  http://www.hazelcast.com/schema/client-config/hazelcast-client-config-5.3.xsd">

    <cluster-name>dev</cluster-name>

    <instance-name>hazelcast-client</instance-name>

    <user-code-deployment enabled="true">
        <classNames>
           <className>org.springframework.session.hazelcast.SessionUpdateEntryProcessor</className>
            <className>org.springframework.session.Session</className>
            <className>org.springframework.session.MapSession</className>
        </classNames>
    </user-code-deployment>

    <network>
        <cluster-members>
            <address>localhost:5701</address>
        </cluster-members>
    </network>

</hazelcast-client>

HazelcastSessionConfiguration.kt

@EnableHazelcastHttpSession
@Configuration
open class HazelcastSessionConfiguration {

@EnableHazelcastHttpSession
@Configuration
open class HazelcastSessionConfiguration {

    @Bean
    @SpringSessionHazelcastInstance
    open fun hazelcastInstance(): HazelcastInstance {
        val clientConfig = ClientConfig()
        clientConfig.networkConfig.addAddress("localhost:5701")
        clientConfig.userCodeDeploymentConfig.setEnabled(true).addClass(Session::class.java)
            .addClass(MapSession::class.java).addClass(SessionUpdateEntryProcessor::class.java)
        return HazelcastClient.newHazelcastClient(clientConfig)
    }


// example config from Spring docs for Server - what and how do I need for docker instance?
    @Bean
    open fun hazelcastConfig(): Config {
        val config = Config()
        val attributeConfig = AttributeConfig()
            .setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
            .setExtractorClassName(PrincipalNameExtractor::class.java.name)
        config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
            .addAttributeConfig(attributeConfig)
            .addIndexConfig(
                IndexConfig(IndexType.HASH, HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
            )
        config.setClusterName("dev")
        config.networkConfig.setPublicAddress("localhost:5701")
        val serializerConfig = SerializerConfig()
        serializerConfig.setImplementation(HazelcastSessionSerializer()).setTypeClass(MapSession::class.java)
        config.serializationConfig.addSerializerConfig(serializerConfig)
        return config
    }

}

I tried different configurations,with and without "hazelcastConfig" bean, changing hazelcast to 5.4 and 4.2, or creating "hazelcastInstance" but nothing changes.

What am I missing here, what is the proper way of configuring client and server? Any help will be appreciated

1 Answer 1

1

If you are using Hazelcast as a client, then the "user code deployment" feature needs to be enabled. Because spring session is using Hazelcast's entry processor to update the session data.

On the cluster side you need to change the docker-compose.yaml file something like this. Here I am using hazelcast:5.4.0 image because Spring 3 requires Java 17. As far as I know Hazelcast 5.3.x uses Java 8 and it does not allow a class compiled with a newer Java version to be deployed.

version: "3"
services:
  hazelcast:
    image: hazelcast/hazelcast:5.4.0-slim-jdk21
    ports:
      - "5701:5701"
    environment:
      - HZ_USERCODEDEPLOYMENT_ENABLED=true

On the client side you need to deploy some spring classes to cluster, because Hazelcast cluster does not have them. Something like this.

import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.SessionIdGenerator;
import org.springframework.session.hazelcast.SessionUpdateEntryProcessor;


@Configuration
public class HazelcastHttpSessionConfig {

    @Bean
    public HazelcastInstance hazelcastInstance() {
        ClientConfig clientConfig = new ClientConfig();
        clientConfig.getNetworkConfig()
                .addAddress("0.0.0.0:5701"); // connect to local server

        clientConfig.getUserCodeDeploymentConfig()
                .setEnabled(true)
                .addClass(Session.class)
                .addClass(MapSession.class)
                .addClass(SessionUpdateEntryProcessor.class)
                .addClass(SessionIdGenerator.class)
        ;
        return HazelcastClient.newHazelcastClient(clientConfig);
    }
}

application.properties is like this

spring.cache.type=jcache
spring.cache.jcache.provider: com.hazelcast.client.cache.HazelcastClientCachingProvider

That's all. You don't need to do anything else.

Note : This answer only works if you are using spring-session only. If you are using spring-session + spring-security you also need to deploy spring-security related classes to Hazelcast cluster

1
  • Thanks for advice, I tried above configuration, but then I get errors from com.hazelcast.nio.serialization.HazelcastSerializationException: java.lang.ClassNotFoundException: Failed to load class com.g4iner.ExampleCache from other members - so I need to add every class with session scope and serialization to this configuration (and from other libraries)? Instead of that I resolved the problem by forking hazelcast-wm project and replacing all javax imports with jakarta - then I'm able to use this modified WebFilter in FilterRegistrationBean
    – G4iner
    Commented Jun 6 at 14:08

Not the answer you're looking for? Browse other questions tagged or ask your own question.