Claus Ibsen created CAMEL-24579:
-----------------------------------
Summary: DataFormat.marshal graph parameter should be @Nullable
Key: CAMEL-24579
URL: https://issues.apache.org/jira/browse/CAMEL-24579
Project: Camel
Issue Type: Bug
Components: camel-core
Reporter: Claus Ibsen
org.apache.camel.spi is @NullMarked (since 4.21, CAMEL-22640) and
DataFormat.marshal has no per-parameter @Nullable on its graph parameter, so it
is treated as non-null by contract:
void marshal(Exchange exchange, Object graph, OutputStream stream) throws
Exception;
However, MarshalProcessor (camel-support) passes the message body straight
through with no null guard:
// MarshalProcessor.java
final Object originalBody = in.getBody();
Object body = originalBody;
...
dataFormat.marshal(exchange, body, osb);
and Message.getBody() is itself explicitly @Nullable. So Camel can hand a value
it declares nullable to a parameter it declares non-null. This is invisible for
Java implementations (null just arrives), but for Kotlin implementations of
DataFormat, the compiler emits a non-null assertion at the start of the
overriding method, which throws NPE before user code runs, whenever the body is
legitimately null (e.g. on an error route, or for a DataFormat that marshals
from Exchange state rather than from graph).
This was not caught by NullAway because org.apache.camel.support.processor is
not @NullMarked.
DataFormat.java was not touched by the original CAMEL-22640 sweep
(67f6a37d473c) -- it inherited non-null-by-default purely from the
package-level @NullMarked, without anyone reviewing whether graph can actually
be null at its real call site. This is the same category of gap as the
still-open CAMEL-24460 (ProducerTemplate body parameters should be nullable).
Before 4.21.0, org.apache.camel.spi was not @NullMarked, so graph was a
platform type and null was harmless.
Fix: annotate the parameter to match actual runtime behavior:
void marshal(Exchange exchange, @Nullable Object graph, OutputStream
stream) throws Exception;
This is a Javadoc/contract-only change -- MarshalProcessor's runtime behavior
is unchanged, so it does not affect existing Java implementations, and does not
risk breaking DataFormat implementations (such as Kotlin ones) that
intentionally marshal based on Exchange state rather than the graph parameter.
Reported by Petr H. on the dev list.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)