Skip to content

Convert JMSDecorator.getDestination to ClassLatch - #12720

Draft
dougqh wants to merge 2 commits into
dougqh/abstract-method-guardfrom
dougqh/classlatch-jms
Draft

dougqh wants to merge 2 commits into
dougqh/abstract-method-guardfrom
dougqh/classlatch-jms

Conversation

@dougqh

@dougqh dougqh commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Converts JMSDecorator.getDestination's catch (AbstractMethodError) fallback (JMS <=1.1 producers lack getDestination) to use ClassLatch, so the error is paid once per class rather than once per call, matching the pattern established in #12702 for JDBCDecorator.

One of the candidate sites scanned in APMLP-1895. Draft/trial PR to see how the conversion holds up for this call site.

Stacked on #12702 (ClassLatch) — not mergeable until that lands.

The <=1.1 getQueue/getTopic fallback lives in the latch's fallback override (added to ClassLatch in #12702), so getDestination is a single tryApplyOrNull call. This also settles a correctness nuance: MessageProducer.getDestination() legitimately returns null for a producer created with an unidentified destination (session.createProducer(null)), which must not be confused with a latched/unavailable method — otherwise a plain MessageProducer could hit the (TopicPublisher) ... .getTopic() cast and throw ClassCastException. With the fallback inside the latch, a real null is returned as-is and only a failed or latched call takes the fallback, with no isLatched re-check at the call site.

Behavior changes

Compared to the original catch (AbstractMethodError):

  • UnsupportedOperationException from getDestination() now takes the getQueue/getTopic fallback (never latched, since it can't be attributed to a class) instead of propagating to the caller.
  • A null producer now yields null instead of throwing NullPointerException.
  • An AbstractMethodError whose message does not name the producer's class (e.g. thrown inside a wrapper's delegate) still takes the fallback, as before, but does not latch the class.

Test plan

  • New JUnit 5 test JMSDecoratorGetDestinationTest (Proxy-based mocks, per the ParseDBInfoClientInfoTest precedent): real-destination passthrough, real-null passthrough for a plain producer, AbstractMethodError fallback to QueueSender.getQueue() with latching confirmed on a second call, fallback to TopicPublisher.getTopic(), fallback without latching for an error naming another class, and latch isolation across different proxy classes.
  • ./gradlew :dd-java-agent:instrumentation:jms:javax-jms-1.1:test on JDK 8 and JDK 11 (before the fallback rework)
  • Same task after moving the fallback into the latch, on the default local JDK only (149 tests pass)

🤖 Generated with Claude Code

@dougqh dougqh added type: refactoring inst: jms JMS instrumentation tag: ai generated Largely based on code generated by an AI or LLM labels Oct 1, 2026
@datadog-prod-us1-3

This comment has been minimized.

@dd-octo-sts

dd-octo-sts Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.81 s 14.74 s [-0.4%; +1.4%] (no difference)
startup:insecure-bank:tracing:Agent 13.77 s 13.75 s [-0.6%; +0.9%] (no difference)
startup:petclinic:appsec:Agent 16.94 s 16.97 s [-1.0%; +0.6%] (no difference)
startup:petclinic:iast:Agent 16.99 s 17.09 s [-1.2%; +0.0%] (no difference)
startup:petclinic:profiling:Agent 16.65 s 16.90 s [-2.6%; -0.3%] (maybe better)
startup:petclinic:sca:Agent 16.97 s 16.79 s [+0.2%; +2.0%] (maybe worse)
startup:petclinic:tracing:Agent 16.09 s 15.31 s [-0.8%; +11.1%] (unstable)

Commit: 39df7a5c · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@dougqh
dougqh force-pushed the dougqh/classlatch-jms branch from 8412459 to 0520d13 Compare October 1, 2026 22:52
dougqh and others added 2 commits October 1, 2026 21:05
Replaces the per-call AbstractMethodError catch (JMS <=1.1 producers
lack getDestination) with a ClassLatch so the error is paid once per
class instead of once per call. Distinguishes a producer's legitimate
null destination from a latched/unavailable method via isLatched,
since both can otherwise look identical.

Part of APMLP-1895; stacked on #12702 (ClassLatch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Uses ClassLatch's fallback hook so getDestination is a single
tryApplyOrNull, with no isLatched re-check to tell a skipped call from
an anonymous producer's real null. An AbstractMethodError that does not
name the producer's class now also takes the fallback, as it did before
the conversion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

inst: jms JMS instrumentation tag: ai generated Largely based on code generated by an AI or LLM type: refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant