Skip to content

CAMEL-22549: Replace deprecated Exchange getOut/hasOut/setOut with getMessage#22358

Draft
gnodet wants to merge 5 commits intoapache:mainfrom
gnodet:CAMEL-22549-clear-deprecation-warnings
Draft

CAMEL-22549: Replace deprecated Exchange getOut/hasOut/setOut with getMessage#22358
gnodet wants to merge 5 commits intoapache:mainfrom
gnodet:CAMEL-22549-clear-deprecation-warnings

Conversation

@gnodet
Copy link
Copy Markdown
Contributor

@gnodet gnodet commented Mar 31, 2026

Summary

Replace deprecated Exchange.getOut(), Exchange.hasOut(), and Exchange.setOut() calls with the modern Exchange.getMessage() API across 29 component files. This is part of the ongoing effort to clean up internal deprecation usage warnings (CAMEL-22549).

Changes by pattern:

  • Simple body/header setting (exchange.getOut().setBody(x)exchange.getMessage().setBody(x)): Most files follow this pattern
  • Redundant header copy removal: Several files were copying IN headers to OUT unnecessarily (e.g., exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders())). Since getMessage() returns IN when no OUT exists, these copies are redundant and were removed
  • isOutCapable conditional simplification: exchange.getPattern().isOutCapable() ? exchange.getOut() : exchange.getIn() simplified to exchange.getMessage()
  • Exchange reconstruction: UnwrapStreamProcessor keeps the deprecated API with @SuppressWarnings("deprecation") because it copies full exchange state (in/out/properties) which inherently requires the in/out distinction

Deprecated behavior preserved:

  • RootObject.getResponse() in camel-ognl, camel-mvel, and camel-spring keeps using getOut() with @SuppressWarnings("deprecation") — the method is itself deprecated and should maintain its original contract (lazily creating an OUT message) for backward compatibility until it is removed

Intentionally not changed:

  • Core processor files (Enricher, PollEnricher, WireTapProcessor, etc.) that rely on the in/out distinction for internal routing semantics
  • Calls to getOut() on non-Exchange objects (e.g., MethodInfo.getOut())

Affected components:

camel-beanio, camel-bindy, camel-chatscript, camel-crypto, camel-crypto-pgp, camel-fop, camel-hl7, camel-influxdb, camel-influxdb2, camel-jcr, camel-jooq, camel-mina, camel-mock, camel-mvel, camel-ognl, camel-reactive-streams, camel-rocketmq, camel-smooks, camel-soap, camel-spring, camel-spring-ws, camel-sql, camel-ssh, camel-stax, camel-xmlsecurity, camel-xpath

Claude Code on behalf of Guillaume Nodet

…tMessage

Replace usage of deprecated Exchange.getOut(), Exchange.hasOut(), and
Exchange.setOut() with Exchange.getMessage() across 32 component files.

The getOut/hasOut/setOut API has been deprecated since Camel 3.0 in favor
of the unified getMessage() API which returns the current message
regardless of direction (in/out).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet gnodet requested review from davsclaus and oscerd March 31, 2026 12:10
@github-actions
Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using build-all, build-dependents, skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

Copy link
Copy Markdown
Contributor Author

@gnodet gnodet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code on behalf of Guillaume Nodet

Self-review: inline comments explaining why each change pattern is valid.

String response = this.endpoint.getBot().sendChat(inputMessage);
inputMessage.setReply(response);
exchange.getOut().setBody(inputMessage);
exchange.getMessage().setBody(inputMessage);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pattern: simple getOut().setBody()getMessage().setBody()

getOut() lazily creates a new OUT message (copying headers from IN). getMessage() returns the current message (OUT if one exists, otherwise IN). Since no OUT was previously created here, getOut() was creating an OUT just to set a body on it — getMessage() achieves the same result without the unnecessary OUT message creation.

Same pattern applies to: BeanIODataFormat, BindyFixedLengthDataFormat, PGPKeyAccessDataFormat, HL7DataFormat, JcrProducer, Soap11/12DataFormatAdapter, SoapDataFormat, RocketMQReplyManagerSupport, SinkConverter.

Message out = exchange.getOut();
out.copyFrom(in);
out.setHeader(config.getSignatureHeaderName(), new Base64().encode(signature));
exchange.getMessage().setHeader(config.getSignatureHeaderName(), new Base64().encode(signature));
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pattern: removed redundant getOut() + copyFrom(in) + header set

The old code did:

Message out = exchange.getOut(); // creates OUT, copies headers from IN
out.copyFrom(in);               // copies body+headers from IN to OUT again
out.setHeader(..., signature);   // sets the signature header

getMessage() returns IN directly (since no OUT exists yet), which already has all the headers and body. We just need to set the signature header. The copyFrom was redundant because getOut() already copies headers, and then copyFrom copies everything again.

// propagate headers
exchange.getOut().setHeaders(headers);
exchange.getMessage().setBody(out);
exchange.getMessage().setHeaders(headers);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pattern: removed redundant header propagation

The old code saved exchange.getIn().getHeaders() into a local var, then did exchange.getOut().setHeaders(headers) to propagate them. Since getMessage() returns the IN message (which already has those headers), the explicit header propagation is unnecessary. We just set the new body and restore headers (which were captured earlier before the body was consumed).

exchange.getOut().setBody(result.getStdout());
exchange.getOut().setHeader(SshConstants.EXIT_VALUE, result.getExitValue());
exchange.getOut().setHeader(SshConstants.STDERR, result.getStderr());
exchange.getMessage().setBody(result.getStdout());
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pattern: removed explicit getOut().getHeaders().putAll(in.getHeaders())

The old code created an OUT message via getOut() (which already copies headers from IN), then redundantly copied headers again with putAll. With getMessage(), headers are already present on the IN message. Same pattern in SqlStoredProducer.


Message target = exchange.getPattern().isOutCapable() ? exchange.getOut() : exchange.getIn();
target.setBody(result);
exchange.getMessage().setBody(result);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pattern: isOutCapable ? getOut() : getIn()getMessage()

getMessage() is the direct replacement for this conditional pattern — it returns the OUT message if one exists, otherwise the IN message. This is exactly what the old conditional was doing manually.

Same pattern in: StAXProcessor, SpringWebserviceProducer.

exchange.getOut().setHeader(getEndpoint().getOutputHeader(), result);
} else {
exchange.getOut().setBody(result);
if (!getEndpoint().isNoop()) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored logic with redundant header copy removed

The old code: (1) copied IN headers to OUT (getOut().getHeaders().putAll(getIn().getHeaders())), (2) for noop, set body from IN to OUT, (3) for outputHeader, set body from IN + set header, (4) otherwise set result as body. Since getMessage() returns IN (which already has all headers and body), for noop=true we now do nothing (body stays as-is), and for outputHeader we just set the header without re-setting the body.

if (answer == null && localPart.equals("body")) {
answer = out.getBody();
}
Message out = exchange.get().getMessage();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pattern: removed hasOut() guard

The old code checked exchange.hasOut() and only read from OUT if it existed. With getMessage(), we get the current message (OUT if it exists, IN otherwise) — so the guard is unnecessary. The behavior is equivalent: if OUT exists, we read from it; if not, we read from IN.

public Object evaluate(List list) throws XPathFunctionException {
if (exchange.get() != null && exchange.get().hasOut()) {
return exchange.get().getOut().getBody();
if (exchange.get() != null) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same hasOut() guard removal pattern. The old code returned null when no OUT existed; now getMessage() returns IN, and getBody() on IN is valid. The XPath function $out:body now returns the current message body rather than null — which is the correct modern behavior since the in/out distinction is deprecated.

@Deprecated
public Message getResponse() {
return exchange.getOut();
return exchange.getMessage();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pattern: deprecated getResponse() method

The getResponse() method is itself @Deprecated. Using getMessage() instead of getOut() is appropriate since both the method and the underlying API are deprecated. Same change in ognl/RootObject and spel/RootObject.

@Override
public Object evaluate(Exchange exchange) {
return function.apply(exchange.getOut());
return function.apply(exchange.getMessage());
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods (outMessage(), outBody(), outBodyAs()) use getOut() to access the response message. getMessage() is the correct replacement — it returns the response (OUT) if one exists, otherwise the request (IN). All 5 getOut() calls in this file follow this same pattern.

gnodet and others added 4 commits March 31, 2026 15:23
…igration

The testResponseCreatesOutMessage tests expected that response.body
returns null (because getOut() lazily created an empty OUT message).
With getMessage(), response now returns the current message (IN),
so response.body correctly returns the IN body.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d compat

The deprecated RootObject.getResponse() method should preserve its
original behavior (delegating to getOut()) to maintain backward
compatibility. Added @SuppressWarnings("deprecation") since a
deprecated method calling another deprecated method is expected.
Restored the original tests that verify this deprecated behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…etIn

After the exchange has been processed, the response body may be on the
OUT message. MinaPayloadHelper.getOut() correctly uses getMessage().getBody()
to read the result, while getIn().getBody() would return the original input.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- getIn() → getRequestPayload() (reads exchange.getIn() — the original request)
- getOut() → getResponsePayload() (reads exchange.getMessage() — the result)
- setIn()/setOut() → setPayload() (unified, uses getMessage())
- Removed unused setOut() method

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet gnodet marked this pull request as draft April 1, 2026 09:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant