java - Spring IntegrationFlow 实现中的 ClassCastException

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

我目前有一个 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 方法(转换、过滤等),我都会遇到类似的问题。

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

编辑:每个 ARTEM 的回答

看来 IntegrationFlow 中的一个简单转换器就达到了目的。我当前的实现似乎是将消息作为 Message<byte[]> 传递。而不是 Message<String>我正在期待。有关更多详细信息,请参阅下面 Artem 的完整回复。

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

最佳答案

重点是 lambda 必须对应于某个函数式接口(interface)。 如果是transform()这是一个GenericTransformer<S, T> 。确实是你的Message<String> removeLineFeeds(Message<String> message)满足这样的契约(Contract)。如果您只处理有效负载,它会很好地工作:

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

只是因为当目标实现中的所有通用信息在运行时被删除时,我们无法猜测您想要处理整个 Message<?> ,因此框架仅向您的 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 的变体:框架会帮助您将请求 header 处理到回复消息中。

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

关于java - Spring IntegrationFlow 实现中的 ClassCastException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59865139/

相关文章:

java - OBD II 命令获取距离

spring - Spring批处理步骤的不同组合

java - jvm 崩溃.. 可用内存不足? (1.6)

java - 如何从 Button 的 onClick 监听器中删除 Firebase 数据库

Java垃圾收集困惑

spring - @Qualifier ("beanName") 和 @Component ("beanName") 之间的区别

spring - 停止tomcat时使用spring服务获取java.io.NotSerializableException

java - 基于 Spring 的 Web 应用程序的环境特定配置?

java - 从服务异常中检索 Spring Integration 中的消息

java - SFTP Spring 集成的文件轮询和过滤问题