jms - MappingJackson2MessageConverter setTypeIdPropertyName с классом времени выполнения - PullRequest
1 голос
/ 28 апреля 2020

Я пытаюсь создать универсальный c сервис, который будет обрабатывать отправку сообщений в MQ, используя java 11, весеннюю загрузку 2.2.6 и MappingJackson2MessageConverter. Я хочу использовать его в качестве bean-компонента в других своих службах.

Но когда я отправляю сообщение, оно имеет тип интерфейса вместо класса отправляемого объекта.

У меня есть интерфейс Entity для всех объектов, которые я собираюсь отправить и класс SomeEntity implements Entity. Таким образом, сообщение имеет «тип» (для массива) [Lcom.company.Entity; вместо [Lcom.company.SomeEntity;.

Интерфейс для службы:

public interface MessageSender<T> {
    void send(T[] entities);
}

Реализация по умолчанию:

public class DefaultMessageSender<T extends Entity> implements MessageSender<T> {
    private final JmsTemplate jmsTemplate;

    public DefaultMessageSender(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    @Override
    public void send(T[] entities) {
        jmsTemplate.convertAndSend(entities);
    }
}

В другой службе весенней загрузки я настраиваю службу как bean:

@Bean
public MessageSender<SomeEntity> customerMessageSender(JmsTemplate jmsTemplate) {
    return new DefaultMessageSender<>(jmsTemplate);
}

@Bean
public MessageConverter jacksonJmsMessageConverter() {
    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
    converter.setTargetType(MessageType.TEXT);
    converter.setTypeIdPropertyName("type");
    return converter;
}

Есть ли способ заставить преобразователь использовать класс среды выполнения, а не интерфейс?

Upd.: Было две проблемы: удаление типа, которое заменяет все T с классом Entity в DefaultMessageSender и массивами. SomeEntity [] не является подклассом Entity [], и вы не можете его приводить.

Чтобы решить эту проблему, я заменил массив списком и сделал метод абстрактным, чтобы переопределить его конкретными классами.

@Bean
public MessageSender<SomeEntity> someEntityMessageSender(JmsTemplate jmsTemplate) {
    return new AbstractDefaultMessageSender<>(jmsTemplate) {
        @Override
        protected void send(List<SomeEntity> items) {
            var arr = items.toArray(new SomeEntity[0]);
            jmsTemplate.convertAndSend(arr);
        }
    };
}

1 Ответ

1 голос
/ 28 апреля 2020

Это потому, что вы отправляете массив.

Вы можете настроить отображение от Entity[] на конкретный тип (если есть только один), или создать подкласс и переопределить этот метод, чтобы просмотреть элемент тип.

    /**
     * Set a type id for the given payload object on the given JMS Message.
     * <p>The default implementation consults the configured type id mapping and
     * sets the resulting value (either a mapped id or the raw Java class name)
     * into the configured type id message property.
     * @param object the payload object to set a type id for
     * @param message the JMS Message on which to set the type id property
     * @throws JMSException if thrown by JMS methods
     * @see #getJavaTypeForMessage(javax.jms.Message)
     * @see #setTypeIdPropertyName(String)
     * @see #setTypeIdMappings(java.util.Map)
     */
    protected void setTypeIdOnMessage(Object object, Message message) throws JMSException {
        if (this.typeIdPropertyName != null) {
            String typeId = this.classIdMappings.get(object.getClass());
            if (typeId == null) {
                typeId = object.getClass().getName();
            }
            message.setStringProperty(this.typeIdPropertyName, typeId);
        }
    }
...