jms - MappingJackson2MessageConverter setTypeIdPropertyName with runtime class

jms - MappingJackson2MessageConverter setTypeIdPropertyName with runtime class

我正在尝试创建通用服务,该服务将使用 java 11、spring boot 2.2.6 和 MappingJackson2MessageConverter 处理向 MQ 发送消息。我想在我的其他服务中将它用作 bean。

但是当我发送消息时它有接口的类型而不是我正在发送的对象的 class。

我有接口 Entity 用于我要发送的所有对象和 class SomeEntity implements Entity。所以消息有 "type" of (for array) [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);
    }
}

在其他spring引导服务中我将服务配置为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;
}

有没有办法强制转换器使用运行时 class 而不是接口的?

更新: 有 2 个问题:在 DefaultMessageSender 和数组中用 Entity class 替换所有 T 的类型擦除。 SomeEntity[] 不是 Entity[] 的子class,你不能转换它。

为了解决这个问题,我用列表替换了数组,并将方法抽象化,这样我就可以用具体的 classes 重新定义它。

@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);
        }
    };
}

因为你发送的是数组

您可以设置从 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);
        }
    }