如何将LinkedHashMap转换为自定义对象?

3
我在我的Kafka Consumer端有两个主题:主题A和主题B。两者都将传递给同一个方法。该方法的详细信息如下:
@Slf4j
@Service
public class KafkaConsumerService {

    @KafkaListener(topics = { "topic-a", "topic-b" }, groupId = "X-consumer")
    public <T> void listenX(Response<T> msg) {
        log.info("MSG arrived to consumer");
        KafkaMessageDTO<TokenMobieDTO> test = msg.getData();

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class KafkaMessageDTO<T> {

    @JsonProperty("object")
    private T object;

    @JsonProperty("header")
    private HttpHeaders headers;

}

我总是发送那个msg变量类型为>到那个方法。尝试从KafkaMessageDTO中提取对象(kafkaMessageDTO.getObject()),但不幸的是,我无法做到。
在调试中,我能够看到值,并且看起来数据完全匹配,如下所示 enter image description here 我该如何将msg对象转换为KafkaMessageDTO对象?当我尝试转换时,我收到了这个错误。
threw exception; nested exception is java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class com.token.dto.TokenMobieDTO (java.util.LinkedHashMap is in module java.base of loader 'bootstrap';

我尝试过进行映射,但是数据中似乎没有列表,所以我无法进行迭代。问题仍然存在。

你是否在任何地方定义了消息对象应该转换为你的自定义类型?Jackson无法知道你的@JsonProperty("object")字段是什么类型 - 你需要告诉它。 - undefined
@knittl 是的,在这里我定义了 KafkaMessageDTO<TokenMobieDTO> test = msg.getData(); 在这个例子中,T 应该是 KafkaMessageDTO<TokenMobieDTO> - undefined
T与对象从JSON反序列化的方式无关。反序列化发生在对象构建和初始化之前,而不是在访问字段时。如果不告诉Jackson类型,它将始终将JSON对象(即{...})回退到LinkedHashMap - undefined
那么我该如何处理呢?你能给我一些例子吗? - undefined
快速搜索找到了这些帖子;我对Kafka监听器的了解不够,无法判断哪个适用:https://stackoverflow.com/q/51096351/112968,https://stackoverflow.com/q/61430128/112968,https://stackoverflow.com/q/70216775/112968,https://stackoverflow.com/q/55825642/112968 - 你可以搜索“多态JSON反序列化”或类似的内容。请注意,Jackson也可以将Map转换为自定义对象(这可能是一个简单可行的解决方法)。 - undefined
@knittl 非常感谢你的帮助,但不幸的是,它们都不适用于我的情况。我有多个主题,并且我需要使用JsonSerializer/JsonDeserializer作为配置。如果有其他方法可以仅配置KafkaConsumerService,那可能会有所帮助。如果你有其他意见,请告诉我。 - undefined
2个回答

1
作为一种解决方法,您可以使用Jackson将地图转换为您的自定义类型。这样做效率可能不高(JSON首先被解析为链式哈希地图,然后再进行转换),但应该能够正常工作。
@Slf4j
@RequiredArgsConstructor
@Service
public class KafkaConsumerService {
    private final ObjectMapper objectMapper;

    @KafkaListener(topics = { "topic-a", "topic-b" }, groupId = "X-consumer")
    public <T> void listenX(Response<T> msg) {
        log.info("MSG arrived to consumer");
        final KafkaMessageDTO<LinkedHashMap> test = msg.getData();
        final TokenMobieDTO dto = objectMapper.convertValue(
                test.getObject(),
                TokenMobieDTO.class);

        // ..

(有更好的方法)
资源:

-2
你代码中的问题与Java中的泛型类型擦除有关。当你尝试从KafkaMessageDTO中提取对象时,由于类型擦除,泛型类型信息丢失,因此无法直接访问TokenMobieDTO。
为了解决这个问题,你可以修改KafkaConsumerService类,将实际的类类型传递给listenX方法。以下是你可以做的方式:
@Slf4j
@Service
public class KafkaConsumerService {

    @KafkaListener(topics = { "topic-a", "topic-b" }, groupId = "X-consumer")
    public <T> void listenX(KafkaMessageDTO<T> msg) {
        log.info("MSG arrived to consumer");
        T object = msg.getObject();
        // Use 'object' (e.g., cast it to TokenMobieDTO if needed)
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class KafkaMessageDTO<T> {

    @JsonProperty("object")
    private T object;

    @JsonProperty("header")
    private HttpHeaders headers;

    // Getter for 'object'
    public T getObject() {
        return object;
    }
}


我遇到了同样的问题。当我尝试使用 T object = msg.getObject(); 时,对象变量包含了 LinkedHasMap。我无法提取数据。 - undefined
JSON对象已经反序列化。将其强制转换为不同类型不能将实例的类型从LinkedHashMap更改为TokenMobieDTO - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接