Skip to content

Spring kafka 2.2 type mappings class loader mismatch #894

@idkw

Description

@idkw

Hi,

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 :

https://github.com/spring-projects/spring-kafka/blob/master/spring-kafka/src/main/java/org/springframework/kafka/support/converter/AbstractJavaTypeMapper.java#L142

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions