【问题标题】:ClassCastException in Spring IntegrationFlow ImplementationSpring IntegrationFlow 实现中的 ClassCastException
【发布时间】:2020-01-22 17:24:31
【问题描述】:

我目前有一个 IntegrationFlow 实现,它利用 Service 类来实现要由流执行的所有所需功能。像这样的...

@Service
public class FlowService {

    public Message<String> removeLineFeeds(Message<String> message) {
        return MessageBuilder
                .withPayload(StringUtils.remove(message.getPayload(), StringUtils.LF))
                .copyHeadersIfAbsent(message.getHeaders())
                .build();
    }

}

@Configuration
@EnableIntegration
public class FlowConfiguration {

    @Autowired
    private FlowService flowService;

    @Bean
    public IntegrationFlow flow() {
        return IntegrationFlows
                .from("inputChannel")
                .transform(flowService, "removeLineFeeds")
                .get();
    }
}

上述实现完全按照预期工作,但我希望改进/修改实现以利用 Java 8/Lambdas 的强大功能,使其看起来像这样......

@Bean
public IntegrationFlow flow() {
    return IntegrationFlows
            .from("inputChannel")
            .transform(flowService::removeLineFeeds)
            .get();
}

不幸的是,当以这种方式实现时,流程将在处理消息时抛出ClassCastException。我已经尝试了一些目前在线存在的不同提议的解决方案,但它们似乎都没有奏效。无论使用何种 IntegrationFlow 方法(转换、过滤器等),我都会遇到类似的问题。

需要对当前实现进行哪些更改以允许在 IntegrationFlow 方法中使用flowService::removeLineFeeds

编辑:PER ARTEM 的回应

似乎 IntegrationFlow 中的一个简单转换器可以解决问题。我当前的实现似乎将消息作为Message&lt;byte[]&gt; 传递,而不是我期待的Message&lt;String&gt;。有关详细信息,请参阅下面 Artem 的完整回复。

@Bean
public IntegrationFlow flow() {
    return IntegrationFlows
            .from("inputChannel")
            .convert(String.class)
            .transform(flowService::removeLineFeeds)
            .get();
}

【问题讨论】:

    标签: java spring spring-integration spring-integration-dsl


    【解决方案1】:

    重点是 lambda 必须对应一些函数式接口。 对于transform(),它是GenericTransformer&lt;S, T&gt;。事实上,您的Message&lt;String&gt; removeLineFeeds(Message&lt;String&gt; message) 满足这样的合同。如果你只处理有效载荷,它会很好用:

    public String removeLineFeeds(String message) {
        return StringUtils.remove(message.getPayload(), StringUtils.LF);
    }
    

    仅仅因为当目标实现中的所有通用信息在运行时被删除时,我们无法猜测您想要处理整个Message&lt;?&gt;,因此框架仅将有效负载传播到您的 lambda。你的String 不能转换为Message,因此是ClassCastException

    为了解决问题并模拟 Java 泛型系统,我们建议使用具有显式预期类型的​​重载方法:

    /**
     * Populate the {@link MessageTransformingHandler} instance for the provided
     * {@link GenericTransformer} for the specific {@code payloadType} to convert at
     * runtime.
     * @param payloadType the {@link Class} for expected payload type. It can also be
     * {@code Message.class} if you wish to access the entire message in the transformer.
     * Conversion to this type will be attempted, if necessary.
     * @param genericTransformer the {@link GenericTransformer} to populate.
     * @param <P> the payload type - 'transform from' or {@code Message.class}.
     * @param <T> the target type - 'transform to'.
     * @return the current {@link BaseIntegrationFlowDefinition}.
     * @see MethodInvokingTransformer
     * @see LambdaMessageProcessor
     */
    public <P, T> B transform(Class<P> payloadType, GenericTransformer<P, T> genericTransformer) {
    

    所以,你的配置应该是这样的:

    .transform(Message.class, flowService::removeLineFeeds)
    

    这样我们就可以说我们想要获得完整消息以供我们的函数处理的框架。

    无论如何,我更喜欢仅带有payload 的第一个变体:框架会照顾您将请求标头处理为回复消息。

    在文档中查看更多信息:https://docs.spring.io/spring-integration/reference/html/dsl.html#java-dsl-class-cast

    【讨论】:

    • 感谢 Artem 的回复。我尝试了您上面建议的两种解决方案,但仍然遇到 ClassCastException。更具体地说,异常现在读取java.lang.ClassCastException: [B cannot be cast to java.lang.String
    • 嗯,这已经是一个不同的,与业务相关的。您期望String,但您的消息包含byte[] 作为有效负载。您可以在您的转换器方法中从 byte[] 创建一个字符串,或者使用 convert(String.class) 并注册一个 Converter&lt;byte[], String&gt; @IntegrationConverter bean。
    • 看起来添加 .convert(String.class) 就可以了。我是否正确假设当我有.transform(flowService, "removeLineFeeds") Spring Integration 正在为我处理转换?试图了解我在最初的实现中是如何没有遇到这个问题的。
    • 没错。因为通过方法名调用会发生在我们真正可以尝试将传入数据转换为预期类型的​​反射中。对于 lambda,我们只有一个直接调用,没有人可以猜测转换的目标类型,除非您使用带有 Class...的重载方法...
    猜你喜欢
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 2016-08-12
    • 1970-01-01
    相关资源
    最近更新 更多