I’m using Apache Camel 3.4.3 and trying to convert empty value for my camel route
from(endpointURI) .convertBodyTo(DataContainer.class) .to(DIRECT_ROUTE)
with custom TypeConverter like this:
@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); }
but this way fires exception:
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 ]
I started debugging, and found out when allowNull in @Converter annotation setted to true, this leads to the execution of the following code into CoreTypeConverterRegistry
class inside method public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) throws NoTypeConversionAvailableException
:
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; }
here’s answer is null and next step NoTypeConversionAvailableException throws.
But Apache Camel says next (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
So my question is how i can return null (and can I do this) value in type converter so that my route does not break in the place where the conversion takes place?
Advertisement
Answer
This is because convertBodyTo
is using mandatory conversion, which means that an exception will be thrown if it was not possible to converter.
You can argue that allowNull
even for mandatory conversion should be valid. However that was not its original design, as it was for regular conversion (not mandatory). As mandatory is a contract that guarantees that there is always a response object of that given type (its never null).
Also allowNull
was introduced when you have fallback converters that may or may not be able to convert depending on the content of the input data.
Need to think a bit more about this, whether we should either relax convertBodyTo
to be non mandatory, or add a flag so you can turn mandatory on|off