Spring kafka 2.2 type mappings class loader mismatch
See original GitHub issueHi,
Following my question on StackOverflow which revealed to be actually a bug :
https://stackoverflow.com/questions/53559944/spring-kafka-2-2-type-mappings-class-loader-mismatch
Here it is again below for reference :
I’m trying to use the new type mappings feature introduced in Spring Kafka 2.2 :
Scroll down to “Mapping Types” :
https://docs.spring.io/spring-kafka/reference/htmlsingle/#serdes
On the producer side, I registered a mapping as follow :
senderProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
senderProps.put(JsonSerializer.TYPE_MAPPINGS, "foo:com.myfoo.Foo");
And on the consumer as follow :
consumerProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
consumerProps.put(JsonDeSerializer.TYPE_MAPPINGS, "foo:com.yourfoo.Foo");
However, when sending an event to Kafka on the producer side of the com.myfoo.Foo
class, the classId header that is added to the record is com.myfoo.Foo
instead of foo
. Thus on the consumer side, it fails to deserialize because com.myfoo.Foo
is unknown.
I have narrowed the issue down to this method in spring-kafka :
protected void addHeader(Headers headers, String headerName, Class<?> clazz) {
if (this.classIdMapping.containsKey(clazz)) {
headers.add(new RecordHeader(headerName, this.classIdMapping.get(clazz)));
}
else {
headers.add(new RecordHeader(headerName, clazz.getName().getBytes(StandardCharsets.UTF_8)));
}
}
When debugging through the execution of the serialization of a kafka record, the execution actually goes to the else branch, whereas in my understanding it should actually go to the if branch and add foo
as a header. Instead it adds com.myfoo.Foo
to the header.
The culprit seems to be related to a class loader mismatch but I’m not sure if it’s actually a bug or something stupid I did on my end.
Basically, the classIdMapping
map is correctly filled with com.myfoo.Foo
as a key and the UTF-8 byte[] representation of foo
as the corresponding value.
However during the if chec, the clazz
parameter is a Class loaded by a different class loader as what was stored in the classIdMapping
map, thus the hashcodes are different and it goes to the else branch.
Thanks
Issue Analytics
- State:
- Created 5 years ago
- Comments:12 (9 by maintainers)
About your concern, Gary, during deserialization. The
AbstractJavaTypeMapper
uses aClassUtils.getDefaultClassLoader()
which is supplied with theThread.currentThread().getContextClassLoader()
. So, that one should work as well.OK. I found the problem. The
JsonSerializer
has this code:Meanwhile Spring Boot Dev tool recommends to use a
Thread.currentThread().getContextClassLoader()
first.