Home > front end >  Handle Generic Type in RabbitListener
Handle Generic Type in RabbitListener

Time:05-26

In my springboot application i am creating a message that contains a generic type as follows:

public List<QMessage<T>> composeMessage(String entityName, List<T> input) {
    if (CollectionUtils.isEmpty(input)) {
        return null;
    }

    log.debug("Composing message to send");

    List<QMessage<T>> result = new ArrayList<>();
    input.forEach(el -> {
        QMessage<T> tmp = new QMessage<>();
        tmp.setSourceId(getSourceId(el));
        tmp.setEntityName(entityName);
        tmp.setData(el);
        result.add(tmp);
    });
    return result;
}

public void convertAndPublishList(List<QMessage<T>> items) {
    try {
        log.debug("Converting message to JSON and publishing to RabbitMQ");
        rabbitTemplate.convertAndSend(MQConfig.WD_COMMONS_QUEUE_EXCHANGE, MQConfig.WD_COMMONS_QUEUE_ROUTING_KEY, items);
    } catch (AmqpException e) {
        log.error("Error during message publishing to RabbitMQ. Exception: {}", e.getMessage());
        throw new BlenderProducerException(e.getMessage(), e);
    }
}


@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class QMessage<T> implements Serializable {

    private static final long serialVersionUID = 9095736695643670685L;

    private Long sourceId;

    private String entityName;

    private T data;

}

On the listener side I would like to handle the generic somehow, that's what I've tried:

@Slf4j
@Component
@RequiredArgsConstructor
@RabbitListener(queues = MQConfig.WD_COMMONS_QUEUE)
public class WDCommonsListeners {


        @RabbitHandler
        public void handleA(List<QMessage<Dog>> message) {
            System.out.println("handle 1");
        }

        @RabbitHandler
        public void handleB(List<QMessage<Cat>> message) {
            System.out.println("handle 2");
        }

}

but I got this exception message: org.springframework.amqp.AmqpException: Ambiguous methods for payload type: class java.util.ArrayList: handleA and handleB

Consider that Cat and Dog class are both extending Animal class

I've also tried with an unknown type of message as follow but I receive a LinkedList insted of an object:

@RabbitListener(queues = MQConfig.WD_COMMONS_QUEUE)
public void listener(List<QMessage<?>> message) throws IOException {

    if (!CollectionUtils.isEmpty(message)) {
            for (QMessage<?> msg : message) {
                System.out.println("msg");
            }
    }

Maybe I have to get JSON from the message and the convert it to object with an ObjectMapper?

CodePudding user response:

It just does not check a generic type of the method parameter: methodParameter.getParameterType().isAssignableFrom(payloadClass). So, that's how you got that ambiguity.

Since you logic is hard enough to deal with collection and its deep nested generic type, I'd really suggest to go with a single @RabbitListener and do respective routing manually.

The DefaultJackson2JavaTypeMapper has to be configured for the TypePrecedence.TYPE_ID to make it to convert incoming data to the List<QMessage<?>> before calling your listener method: https://docs.spring.io/spring-amqp/docs/current/reference/html/#Jackson2JsonMessageConverter-from-message

  • Related