java: the '@Component JavaDelegate' rule is a publish-time Problems entry, not a per-execution WARN - #7316
Merged
Merged
Conversation
…ntry (#7291) The rule "a JavaDelegate must NOT be a @component" was observable only as a WARN from ComponentContainer.createUnmanaged. On the ${JavaTask} + handler path that method runs for every execution of the step (the delegate is fresh per execution by design), so an annotated handler on a step that runs a thousand times a day logged a thousand identical WARNs - and none of them reached the developer who wrote the annotation, only whoever happened to read the log of a run. - ComponentContainer.rebuild now flags a bean that implements Flowable's JavaDelegate - matched by interface NAME, since engine-java cannot see the Flowable type - as a wiringWarnings() entry, carried on RebuildResult and projected by JavaSynchronizer onto the Problems view at publish. It is a warning, not a wiring error: the bean is built and usable, so the artefact stays CREATED and only the Problems entry appears. - The execution-time WARN is kept (a delegate can arrive from an AOT module the synchronizer never saw) but is logged once per class per generation and then at DEBUG, the once-then-DEBUG shape #7220/#7267 established. The suppression set is cleared by rebuild, so a republish states it again. - Its message no longer claims the class "is a JavaDelegate": the check there is isBean on whatever class was asked to be wired unmanaged, so it now says "instantiated outside the container" instead. Coverage: ComponentContainerDelegateRuleTest, with a name-only org.flowable.engine.delegate.JavaDelegate stand-in under src/test/java - which is what makes the by-name match testable without the dependency. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Moves the rule "a
JavaDelegatemust NOT be a@Component" from a per-execution log line to a publish-time Problems-view entry, and makes the log line that remains state itself once instead of forever.Since #7272 the rule was observable only as a WARN in
ComponentContainer.createUnmanaged. Two problems with that placement:${JavaTask}+handlerpath,DirigibleJavaCallDelegate.instantiatecallscreateUnmanagedfor eachexecute— the delegate is fresh per execution by design. An annotated handler on a step that runs a thousand times a day logged a thousand identical WARNs.@Component.Changes:
ComponentContainer.rebuildnow flags a bean implementing Flowable'sJavaDelegateas awiringWarnings()entry, naming the class and the rule. The interface is matched by name (org.flowable.engine.delegate.JavaDelegate), walking superclasses and super-interfaces, becauseengine-javacannot see the Flowable type — the dependency runs the other way, which is also why the execution-time check is the broaderisBean.wiringWarnings()is a new map besidewiringErrors(), carried onRebuildResultand projected byJavaSynchronizerthrough the samerecordCompilationProblemspath. The artefact staysCREATED: the bean is built and usable, so only the Problems entry appears. Routing it throughwiringErrors()would have marked the fileFAILED, which would be a lie about a class that works.rebuild, so a republish states it again for the developer who just changed the class. The DEBUG branch isisDebugEnabled-guarded so a suppressed repeat does not even build its message on a per-execution path.isBeanon whatever class was handed tocreateUnmanaged; it now says "is annotated@Componentbut is instantiated outside the container".What issues does this PR fix or reference?
Fixes #7291. Follow-up to #7223 / #7272; reuses the once-then-DEBUG pattern from #7220 and #7267.
Notes for reviewers
RebuildResultgained a component. Its only construction site isJavaLoader.rebuild, and every consumer of the record lives insideengine-java, so no downstream module is affected.wiringWarningsbranch sits inside thesucceededFqnsarm ofJavaSynchronizer.rebuildAll, so it records the Problems entry where the code previously cleared them — a class that failed to compile or failed to wire still reports that stronger failure instead.org.flowable.*.src/test/java/org/flowable/engine/delegate/JavaDelegate.javais a name-only stand-in (noexecutemethod — the name is the whole of what the container checks). It is what makes the by-name match testable at all, givenengine-javahas no Flowable dependency.ComponentContainerDelegateRuleTest(8 tests) — the warning's content, that it does not fail the bean it is about, a delegate found through a super-interface, a non-delegate bean warning nothing, the previous generation's warning being cleared, exactly one WARN and two DEBUGs across three executions, the reworded execution-time message, and re-warning after a republish. Full module suite: 145 tests, 0 failures.license-maven-plugin:checkcannot run from a git worktree at all (Bare Repository has neither a working tree, nor an index), so local verification used-Dlicense.skip=true; every new file carries the standard EPL header, and the formatter validates clean.engine-java/CLAUDE.mdis updated with where the rule is checked, why a warning rather than an error, and the guidance behind that choice.Release Notes
N/A — bug fix.
Documentation
N/A — no user-facing documentation change; the developer-facing note lives in
components/engine/engine-java/CLAUDE.md.🤖 Generated with Claude Code