question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Spring kafka 2.2 type mappings class loader mismatch

See original GitHub issue

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

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:12 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
artembilancommented, Dec 6, 2018

About your concern, Gary, during deserialization. The AbstractJavaTypeMapper uses a ClassUtils.getDefaultClassLoader() which is supplied with the Thread.currentThread().getContextClassLoader(). So, that one should work as well.

0reactions
artembilancommented, Dec 6, 2018

OK. I found the problem. The JsonSerializer has this code:

	mappingsMap.put(split[0].trim(),
						ClassUtils.forName(split[1].trim(), JsonSerializer.class.getClassLoader()));

Meanwhile Spring Boot Dev tool recommends to use a Thread.currentThread().getContextClassLoader() first.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Spring kafka 2.2 type mappings class loader mismatch
It seems your application is multi-classloader, e.g. it is Web one. And Apache Kafka Client loads that senderProps.put(ProducerConfig.
Read more >
Spring Boot Reference Documentation
Documentation Overview. This section provides a brief overview of Spring Boot reference documentation. It serves as a map for the rest of the...
Read more >
Documentation - Apache Kafka
In Kafka the communication between the clients and the servers is done with a simple, high-performance, language agnostic TCP protocol.
Read more >
Kafka Broker Configurations for Confluent Platform
imbalance.per.broker.percentage , leader rebalance to the preferred leader for partitions is triggered. Type: boolean.
Read more >
Using the Kafka Handler - GoldenGate - Oracle Help Center
Fully qualified class name of a custom class that implements Oracle GoldenGate for Big Data Kafka Handler's CreateProducerRecord Java Interface. Provided this ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found