我喜欢Kafka,但讨厌编写大量的序列化器/反序列化器,因此我尝试创建一个可以反序列化泛型类型T的GenericDeserializer<T>
。
这是我的尝试:
class GenericDeserializer< T > implements Deserializer< T > {
static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
}
@Override
public T deserialize( String topic, byte[] data) {
T result = null;
try {
result = ( T )( objectMapper.readValue( data, T.class ) );
}
catch ( Exception e ) {
e.printStackTrace();
}
return result;
}
@Override
public void close() {
}
}
但是,(Eclipse)Java编译器抱怨行
result = ( T )( objectMapper.readValue( data, T.class ) );
包含消息Illegal class literal for the type parameter T
。
问题:
答案 0 :(得分:1)
在java中,你无法实例化一个泛型类型,甚至反过来,这意味着objectMapper.readValue()
无法对T.class
进行任何操作。因此,您需要知道在给定情况下要创建的类。这样做的逻辑方法是有一些主题的映射 - &gt;类型,您的反序列化程序可以访问。这方面的一个例子是SpecificAvroSerde
,它使用汇合模式注册表(一个外部进程)来标识要反序列化的类型。您也可以将此映射构建到您的代码中,但根据您的使用情况,这不会特别健壮。
SpecificAvroSerde
的内容更深一点 - 这里有一个块正在向模式注册表询问它应该解码为什么类型:
https://github.com/confluentinc/schema-registry/blob/master/avro-serializer/src/main/java/io/confluent/kafka/serializers/AbstractKafkaAvroDeserializer.java#L109-L139
当然,这个代码都被Avro的复杂性所笼罩。如果我有时间,我会写一些关于如何使用JSON在内存中执行此操作的示例代码。
答案 1 :(得分:1)
您可以使用软件包com.fasterxml.jackson.core.type
public class KafkaGenericDeserializer<T> implements Deserializer<T> {
private final ObjectMapper mapper;
private final TypeReference<T> typeReference;
public KafkaGenericDeserializer(ObjectMapper mapper, TypeReference<T> typeReference) {
this.mapper = mapper;
this.typeReference = typeReference;
}
@Override
public T deserialize(final String topic, final byte[] data) {
if (data == null) {
return null;
}
try {
return mapper.readValue(data, typeReference);
} catch (final IOException ex) {
throw new SerializationException("Can't deserialize data [" + Arrays.toString(data) + "] from topic [" + topic + "]", ex);
}
}
@Override
public void close() {}
@Override
public void configure(final Map<String, ?> settings, final boolean isKey) {}
}
使用此类通用反序列化器,您可以创建Serge
:
public static <T> Serde<T> createSerdeWithGenericDeserializer(TypeReference<T> typeReference) {
KafkaGenericDeserializer<T> kafkaGenericDeserializer = new KafkaGenericDeserializer<>(objectMapper, typeReference);
return Serdes.serdeFrom(new JsonSerializer<>(), kafkaGenericDeserializer);
}
这里JsonSerializer
来自spring-kafka
依赖性,或者实现您自己的序列化。
之后,您可以在创建Kafka流时使用serde:
TypeReference<YourGenericClass<SpecificClass>> typeReference = new TypeReference<YourGenericClass<SpecificClass>>() {};
Serde<YourGenericClass<SpecificClass>> itemSerde = createSerdeWithGenericDeserializer(typeReference);
Consumed<String, YourGenericClass<SpecificClass>> consumed = Consumed.with(Serdes.String(), itemSerde);
streamsBuilder.stream(topicName, consumed);