Skip to content

Asynchronous deserialization performed by Hazelcast may fail due to the wrong ClassLoader being used #24836

Closed
@dsyer

Description

@dsyer

I discovered this in a long yak-shaving session migrating an app to Boot 2.4.1 and Hazelcast 4.0.3.

This fails when you run it from the jar:

@SpringBootApplication
public class IssueApplication {
	public static void main(String[] args) {
		SpringApplication.run(IssueApplication.class, args);
	}
	@Bean
	CommandLineRunner runner(HazelcastInstance hazelcast) {
		IMap<String, Foo> sessions = hazelcast.getMap("foos");
		return args -> {
			sessions.set("foo", new Foo("foo"));
			System.err.println(sessions.get("foo"));
			sessions.getAsync("foo").whenComplete((u, t) -> System.err.println(u)).toCompletableFuture().get();
		};
	}
}
class Foo implements Serializable {
	private String value;
	public Foo() {
	}
	public Foo(String value) {
		this.value = value;
	}
	public String getValue() {
		return this.value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	@Override
	public String toString() {
		return "Foo [value=" + this.value + "]";
	}
}

It's fine when you run in an IDE, or with java -classpath .... The problem is that Hazelcast uses the Thread.crrentThread().getContextClassLoader() by default, and in the async background thread this is the JarLauncher not the AppClassLoader.

I worked around it with this

		@Bean
		Config hazelcastConfig() {
			Config config = new Config();
			config.setClassLoader(SpringApplication.class.getClassLoader());
			...
			return config;
		}

but the issue is more generic really - probably any library that uses JDK fork-join utilities will end up with the same class loader.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions