[ 
https://issues.apache.org/jira/browse/CAMEL-25166?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18121266#comment-18121266
 ] 

Claus Ibsen commented on CAMEL-25166:
-------------------------------------

More findings for a Camel 5 Java DSL, from checking the Java examples of the 
documentation with the Java DSL parser (CAMEL-25182, PR 
https://github.com/apache/camel/pull/27130) and from the TUI work on Switch and 
route diagrams (CAMEL-25161, CAMEL-25192, CAMEL-25193).

*1. The docs drift from the DSL, and nothing noticed until now.* About 60 of 
2,882 Java route examples called a DSL method that does not exist or with 
arguments it does not take: {{setBody("x")}} instead of 
{{setBody(constant("x"))}}, {{.thread(5)}}, {{filter("${...}")}}, 
{{onRedeliver}} for {{onRedelivery}}, {{body(String.class)}}, and removed API 
still documented ({{deadLetterChannel(...).exceptionPolicyStrategy(...)}}, 
removed in 3.7 by CAMEL-15802; {{jq(expr, type, headerName)}}). The 
parser-based doc check now guards this in the build. For Camel 5: a DSL that is 
easier to check without compiling (see the original analysis), and a doc check 
from day one.

*2. The fluent clause and the builder factory offer different things.* 
{{.marshal().univocityCsv()}}, {{univocityTsv()}}, {{univocityFixed()}} and 
{{.marshal().yaml()}} never existed on {{DataFormatClause}}, only on 
{{dataFormat()}} (DataFormatBuilderFactory), although the data format pages 
showed them. Added in CAMEL-25182. For Camel 5: one source for what each data 
format and language offers, generated for every DSL form, instead of 
hand-written clause methods.

*3. {{policy(...)}} silently wraps everything after it.* 
{{PolicyDefinition.isWrappingEntireOutput()}} is true, so 
{{.doTry().policy(p).to("a").doCatch(...)}} does not compile: doCatch lands on 
the policy. Only {{transacted}} is moved to the top of the route. The keycloak 
docs got this wrong. For Camel 5: wrapping EIPs with an explicit block 
({{policy(p, b -> b.to("a"))}}), like the block proposal in the original 
analysis.

*4. Chaining breaks where a method returns the parent.* 
{{rest().openApi("spec")}} returns the RestDefinition, so 
{{.missingOperation(...)}} cannot follow; the docs wrote it that way. 
{{resumable(strategy)}} returns the processor, so {{.intermittent(true)}} 
cannot follow. For Camel 5: a method that sets up an element returns that 
element, always.

*5. Steps do not know their line, which tools need.* {{to(...)}} returns the 
route, so the step it adds had no line number when read from source; the parser 
now assigns it from the call (CAMEL-25192). The when/otherwise of a choice are 
not ProcessorDefinitions any more (CAMEL-21620) and 
{{ChoiceDefinition.getChildren()}} does not return them, so every tool walking 
a route needs a special case for choice. For Camel 5: one uniform tree of steps 
(getChildren everywhere) with source positions.

*6. Switch shows the value of endpoint DSL parity.* Switch (CAMEL-24988) first 
took destinations as String only; the endpoint DSL overloads came in 
CAMEL-25178. For Camel 5: every endpoint-taking method accepts an endpoint 
builder by construction, not by adding overloads per EIP.

_Claude Code on behalf of davsclaus_

> Camel 5 - Java DSL: findings from reading Java DSL routes without compiling 
> them
> --------------------------------------------------------------------------------
>
>                 Key: CAMEL-25166
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25166
>             Project: Camel
>          Issue Type: Improvement
>          Components: camel-core
>            Reporter: Claus Ibsen
>            Priority: Major
>         Attachments: camel5-java-dsl-findings.md
>
>
> Input for a Java DSL in Camel 5, from the analysis done while building the 
> lightweight Java DSL parser of CAMEL-25148 (the root of this analysis).
> h3. Where the findings come from
> CAMEL-25148 adds {{LwJavaParser}} to {{camel-java-io}}: it reads the routes 
> of a Java DSL source into the Camel model without compiling it. The source is 
> read as text and each chain of calls is replayed against Camel's own DSL; 
> nothing of the project is loaded or run (design: 
> {{design/java-dsl-parser.adoc}}). To make it read what people really write, 
> it was run over about 8,400 Java sources with about 18,000 routes: the tests 
> of the components and of camel-core, the camel-spring-boot and camel-quarkus 
> repositories, the three example repositories, and round trips of the XML test 
> routes through the Java dumper.
> What was hard for the parser is what a Camel 5 Java DSL could avoid, for 
> people and for tools alike (TUI, AI, documentation checks, low-code editors).
> h3. Findings (details, examples and numbers in the attached 
> camel5-java-dsl-findings.md)
> # *Block scoping by return types.* end()/endChoice()/endDoTry() close 
> whatever is open; routingSlip(...).doCatch(...) does not compile while 
> to(...).doCatch(...) does; steps after onFallback() go into the fallback. The 
> nesting in the code is not the nesting in the model.
> # *Expression clauses and ValueBuilder predicates have no language form.* 
> setHeader("x").constant("y"), header("x").isEqualTo("y") keep Java objects in 
> the model, which no DSL can write (the Java dumper writes expression("")).
> # *The same option as a Class or its name* (throwException(Foo.class) vs 
> exceptionType, typeClass vs type, unmarshalType vs unmarshalTypeName): about 
> 25 such pairs in the model.
> # *Overloads where Object and String mean different things* (method(Object, 
> String) vs method(String, String)): only Java's most-specific rule chooses 
> right.
> # *Varargs pairs* (setHeaders("h1", expr, "h2", expr)): meaning by position 
> only.
> # *Unqualified names clashing across builders and static imports* (bean(...) 
> is the bean component in the endpoint DSL, an aggregation strategy with a 
> static import).
> # *The endpoint DSL follows rules with exceptions* (clas, coapTcp, coapsTcp, 
> restEndpoint), and multi-value option prefixes are only in the catalog.
> # *Constants and header names live in component classes* (KafkaConstants.KEY, 
> HazelcastOperation.PUT_IF_ABSENT): a tool needs the component jar or the 
> catalog.
> # *Routes are code:* ports, injected fields, helper methods and loops build 
> URIs where properties and templates would keep them data.
> # *Processors and lambdas are opaque:* about 1,200 in camel-core's tests 
> alone, with no name or purpose a tool can show.
> h3. A bridge from the current Java DSL
> The parser's replay (current Java DSL source -> current DSL -> model, without 
> compiling) is the natural shape of a bridge: an adapter JAR keeping the 
> current DSL working on the Camel 5 model, and a migration tool reading 
> current routes with LwJavaParser and writing the Camel 5 DSL, saying which 
> routes need hand work. The corpora above are the test suite for both.
> _Claude Code on behalf of davsclaus_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to