即使在 @Converter 注释中将 allowNull 设置为 true,Camel TypeConverter 仍会抛出 NoTypeConversionAvailableException

Camel TypeConverter still throws NoTypeConversionAvailableException even if allowNull set to true in @Converter annotation

我正在使用 Apache Camel 3.4.3 并尝试为我的骆驼路线转换空值

     from(endpointURI)
        .convertBodyTo(DataContainer.class)
        .to(DIRECT_ROUTE)

像这样使用自定义 TypeConverter:

@Converter(allowNull = true)
public DataContainer toDataContainer(String xml) {
    LOGGER.info("Received body as string [{}] try to convert to DataContainer", xml);
    if (StringUtils.isBlank(xml)) {
        return null;
    }
    if (!XmlUtils.isXml(xml)) {
        throw new SwiftCorpException(ErrorCode.ERROR_99999,
            String.format(
                "value [%s] is not a xml, so it cannot be converted to DataContainer",
                xml
            )
        );
    }
    return DataContainer.fromXml(xml);
}

但这种方式会引发异常:

org.apache.camel.InvalidPayloadException: No body available of type: ru.swiftcorp.common.utils.DataContainer but has value: of type: java.lang.String on: Message. Caused by: No type converter available to convert from type: java.lang.String to the required type: ru.vtb.swiftcorp.common.utils.DataContainer with value . Exchange[]. Caused by: [org.apache.camel.NoTypeConversionAvailableException - No type converter available to convert from type: java.lang.String to the required type: ru.swiftcorp.common.utils.DataContainer with value ]

开始调试,发现当@Converter注解中的allowNull设置为true, 这导致在方法 public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) throws NoTypeConversionAvailableException:

中执行以下代码到 CoreTypeConverterRegistry class
public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) throws NoTypeConversionAvailableException {

    ...
    Object answer = doConvertTo(type, exchange, value, true, false);
    if (answer == null) {
        // Could not find suitable conversion
        throw new NoTypeConversionAvailableException(value, type);
    }
    return (T) answer;
}

此处的 answer 为空,下一步抛出 NoTypeConversionAvailableException。

但是 Apache Camel 接下来说 (here's a link) :

If null should be allowed as a valid response, then from Camel 2.11.2/2.12 onwards you can specify this in the annotation as shown

所以我的问题是我如何 return null (我可以这样做)类型转换器中的值,这样我的路线就不会在转换发生了吗?

我 运行 遇到了同样的问题,最后做了 doTry() 并且特别优雅地捕捉到了 NoTypeConversionAvailableException.

示例转换器:

@Converter(generateLoader = true)
public final class TestConverter {

    @Converter(allowNull = true)
    public static MyObject parse(String message) { 
       if (!StringUtils.hasText(message)) {
         return null;
       }
       MyObject obj = new MyObject();
       obj.setMyFirstProperty(message.substring(10, 11));
       // Set other fields, etc.
       return obj;
    }
}

示例路线(使用 generateLoader = true 参数时自动使用 Camel TypeConverterRegistry 中的 @Converter

from("direct:test")
    .log(LoggingLevel.DEBUG, logger, "${body}")
    .doTry()
        .bean(myService, "processTheMessage")
    .doCatch(NoTypeConversionAvailableException.class)
    .end();

这不是我最喜欢的解决方案,因为 allowNull 是 Camel 文档中记录的功能,但它允许我优雅地丢弃

这是因为convertBodyTo使用了强制转换,这意味着如果不能转换就会抛出异常。

您可以争辩说 allowNull 即使对于强制转换也应该有效。然而,这不是它的原始设计,因为它是用于常规转换(不是强制性的)。作为强制性的是保证始终存在该给定类型的响应对象(它永远不会为空)的合同。

还引入了 allowNull,当您有后备转换器时,这些转换器可能会或可能无法转换,具体取决于输入数据的内容。

需要多考虑一下,我们是应该放宽 convertBodyTo 为非强制性,还是添加一个标志以便您可以打开|关闭强制性