This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 3320dcdc37a1 CAMEL-25255: camel-yaml-io / camel-java-io - model 
writers write rests, route templates, beans and route error handlers as their 
DSL loads them (#27254)
3320dcdc37a1 is described below

commit 3320dcdc37a163e5fd3e71cb7aea2cbca3337c1e
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Oct 2 09:28:37 2026 +0200

    CAMEL-25255: camel-yaml-io / camel-java-io - model writers write rests, 
route templates, beans and route error handlers as their DSL loads them (#27254)
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
 .../apache/camel/model/ResequenceDefinition.java   |   3 +-
 .../org/apache/camel/model/RouteDefinition.java    |   6 +
 .../camel/java/out/JavaDslModelWriterSupport.java  |  81 +++++---
 .../org/apache/camel/java/in/RoundTripTest.java    |  53 +++++
 .../apache/camel/java/out/JavaDslCompileTest.java  |   1 +
 .../org/apache/camel/yaml/out/YamlModelWriter.java |  16 +-
 .../org/apache/camel/yaml/LwModelToYAMLDumper.java |  73 ++-----
 .../camel/yaml/out/YamlModelWriterSupport.java     |  32 +++
 .../apache/camel/yaml/out/YamlBeansDumpTest.java   |  74 +++++++
 .../src/test/resources/yaml-beans-with-route.yaml  |   4 +-
 .../src/test/resources/yaml-beans.yaml             |   7 +-
 .../src/test/resources/yaml-rest.yaml              |   3 +-
 .../src/test/resources/yaml-route-template.yaml    |   2 +-
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |  20 ++
 .../src/test/resources/blueprint-out.yaml          |   2 +-
 .../validator/YamlRestTemplateRoundTripTest.java   | 221 +++++++++++++++++++++
 .../main/resources/velocity/model-yaml-writer.vm   |  19 +-
 17 files changed, 515 insertions(+), 102 deletions(-)

diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/ResequenceDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/ResequenceDefinition.java
index a66234e573c5..ab7c64b3af12 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/ResequenceDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/ResequenceDefinition.java
@@ -147,7 +147,8 @@ public class ResequenceDefinition extends 
OutputDefinition<ResequenceDefinition>
      * @return         the builder
      */
     public ResequenceDefinition timeout(long timeout) {
-        return timeout(Duration.ofMillis(timeout));
+        // the millis as given (not 2s0ms for 2000), so the model reads as the 
route was written
+        return timeout(String.valueOf(timeout));
     }
 
     /**
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
index 3193295489d7..3e94918b6868 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
@@ -580,6 +580,12 @@ public class RouteDefinition extends 
OutputDefinition<RouteDefinition>
      */
     public RouteDefinition errorHandler(ErrorHandlerFactory 
errorHandlerBuilder) {
         setErrorHandlerFactory(errorHandlerBuilder);
+        // kept in the model as well (as the xml and yaml dsl have it), so 
dumping the route writes its error handler:
+        // as its definition (deadLetterChannel() gives a 
DeadLetterChannelBuilder, which the model writers do not know)
+        ErrorHandlerDefinition def = new ErrorHandlerDefinition();
+        def.setErrorHandlerType(errorHandlerBuilder instanceof 
CopyableDefinition<?> copyable
+                && copyable.copyDefinition() instanceof ErrorHandlerFactory 
copy ? copy : errorHandlerBuilder);
+        this.errorHandler = def;
         // we are now using a route scoped error handler
         contextScopedErrorHandler = false;
         return this;
diff --git 
a/core/camel-java-io/src/main/java/org/apache/camel/java/out/JavaDslModelWriterSupport.java
 
b/core/camel-java-io/src/main/java/org/apache/camel/java/out/JavaDslModelWriterSupport.java
index 43a77f1eaba4..1a83c60b8693 100644
--- 
a/core/camel-java-io/src/main/java/org/apache/camel/java/out/JavaDslModelWriterSupport.java
+++ 
b/core/camel-java-io/src/main/java/org/apache/camel/java/out/JavaDslModelWriterSupport.java
@@ -24,9 +24,11 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.StringJoiner;
 import java.util.function.BiConsumer;
 
 import org.apache.camel.builder.ExpressionClause;
+import org.apache.camel.builder.LanguageBuilderFactory;
 import org.apache.camel.model.BeanDefinition;
 import org.apache.camel.model.BeanFactoryDefinition;
 import org.apache.camel.model.ConvertBodyDefinition;
@@ -81,7 +83,9 @@ import org.apache.camel.model.language.ExpressionDefinition;
 import org.apache.camel.model.language.HeaderExpression;
 import org.apache.camel.model.language.JqExpression;
 import org.apache.camel.model.language.JsonPathExpression;
+import org.apache.camel.model.language.LanguageExpression;
 import org.apache.camel.model.language.MethodCallExpression;
+import org.apache.camel.model.language.NamespaceAwareExpression;
 import org.apache.camel.model.language.RefExpression;
 import org.apache.camel.model.language.SimpleExpression;
 import org.apache.camel.model.language.SingleInputTypedExpressionDefinition;
@@ -262,12 +266,6 @@ public abstract class JavaDslModelWriterSupport {
             }
         }
 
-        // extract inlined error handler — RouteBuilder-level in Java DSL
-        if (def.getErrorHandler() != null) {
-            writeErrorHandler(sb, def.getErrorHandler());
-            handledAttributes.add("errorHandler");
-        }
-
         if (def.getInput() != null) {
             
sb.append("from(").append(quote(def.getInput().getUri())).append(")");
             if (sourceLocation) {
@@ -293,6 +291,12 @@ public abstract class JavaDslModelWriterSupport {
             handledAttributes.add("routeProperty");
             handledAttributes.add("routeProperties");
         }
+        // the error handler of the route only: errorHandler() of the route 
builder would apply to all its routes
+        if (def.getErrorHandler() != null) {
+            
sb.append(NL).append(indent()).append(".errorHandler(").append(errorHandlerDsl(def.getErrorHandler()))
+                    .append(")");
+        }
+        handledAttributes.add("errorHandler");
         indentLevel--;
         doWriteRouteDefinition(sb, def);
         indentLevel++;
@@ -363,6 +367,10 @@ public abstract class JavaDslModelWriterSupport {
             }
             handledAttributes.add("routeProperty");
             handledAttributes.add("routeProperties");
+            if (route.getErrorHandler() != null) {
+                sb.append(NL).append(indent()).append(".errorHandler(")
+                        
.append(errorHandlerDsl(route.getErrorHandler())).append(")");
+            }
             handledAttributes.add("errorHandler");
             indentLevel--;
             doWriteRouteDefinition(sb, route);
@@ -482,18 +490,7 @@ public abstract class JavaDslModelWriterSupport {
     }
 
     private void writeChainedErrorHandler(StringBuilder sb, 
ErrorHandlerDefinition errorHandler) {
-        if (errorHandler.getErrorHandlerType() instanceof 
DeadLetterChannelDefinition dlc) {
-            sb.append(NL).append(indent()).append("    
.errorHandler(deadLetterChannel(")
-                    .append(quote(dlc.getDeadLetterUri())).append(")");
-            appendErrorHandlerOptions(sb, dlc);
-            sb.append(")");
-        } else if (errorHandler.getErrorHandlerType() instanceof 
DefaultErrorHandlerDefinition deh) {
-            sb.append(NL).append(indent()).append("    
.errorHandler(defaultErrorHandler()");
-            appendErrorHandlerOptions(sb, deh);
-            sb.append(")");
-        } else {
-            sb.append(NL).append(indent()).append("    
.errorHandler(noErrorHandler())");
-        }
+        sb.append(NL).append(indent()).append("    
.errorHandler(").append(errorHandlerDsl(errorHandler)).append(")");
     }
 
     private void writeTemplateParameter(StringBuilder sb, 
RouteTemplateParameterDefinition param) {
@@ -1225,18 +1222,19 @@ public abstract class JavaDslModelWriterSupport {
         sb.append(";").append(NL).append(NL);
     }
 
-    private void writeErrorHandler(StringBuilder sb, ErrorHandlerDefinition 
errorHandler) {
+    /** deadLetterChannel("uri").maximumRedeliveries(3), defaultErrorHandler() 
or noErrorHandler(). */
+    private String errorHandlerDsl(ErrorHandlerDefinition errorHandler) {
+        StringBuilder sb = new StringBuilder();
         if (errorHandler.getErrorHandlerType() instanceof 
DeadLetterChannelDefinition dlc) {
-            
sb.append("errorHandler(deadLetterChannel(").append(quote(dlc.getDeadLetterUri())).append(")");
+            
sb.append("deadLetterChannel(").append(quote(dlc.getDeadLetterUri())).append(")");
             appendErrorHandlerOptions(sb, dlc);
-            sb.append(");").append(NL).append(NL);
         } else if (errorHandler.getErrorHandlerType() instanceof 
DefaultErrorHandlerDefinition deh) {
-            sb.append("errorHandler(defaultErrorHandler()");
+            sb.append("defaultErrorHandler()");
             appendErrorHandlerOptions(sb, deh);
-            sb.append(");").append(NL).append(NL);
         } else {
-            sb.append("errorHandler(noErrorHandler());").append(NL).append(NL);
+            sb.append("noErrorHandler()");
         }
+        return sb.toString();
     }
 
     private void appendErrorHandlerOptions(StringBuilder sb, 
DefaultErrorHandlerDefinition def) {
@@ -1507,6 +1505,11 @@ public abstract class JavaDslModelWriterSupport {
         if (expr instanceof RefExpression) {
             return "ref(" + quotedValue + ")";
         }
+        String factoryMethod = languageFactoryMethod(expr);
+        if (factoryMethod != null) {
+            // groovy, ognl, ...: as their own expression, not 
language("groovy", ...)
+            return "expression()." + factoryMethod + "(" + quotedValue + 
").end()";
+        }
         String lang = expr.getLanguage();
         if (lang != null && !lang.isEmpty()) {
             return "language(" + quote(lang) + ", " + quotedValue + ")";
@@ -1557,6 +1560,10 @@ public abstract class JavaDslModelWriterSupport {
         if (expr instanceof WasmExpression) {
             return "wasm";
         }
+        String factoryMethod = languageFactoryMethod(expr);
+        if (factoryMethod != null) {
+            return factoryMethod;
+        }
         String lang = expr.getLanguage();
         if (lang != null && !lang.isEmpty()) {
             return "language";
@@ -1564,6 +1571,23 @@ public abstract class JavaDslModelWriterSupport {
         return null;
     }
 
+    /**
+     * The method of expression() that builds this kind of expression from its 
text (groovy("..."), ognl("...")), or
+     * null when there is none.
+     */
+    private static String languageFactoryMethod(ExpressionDefinition expr) {
+        String lang = expr.getLanguage();
+        if (lang == null || lang.isEmpty() || expr instanceof 
LanguageExpression) {
+            return null;
+        }
+        try {
+            Method m = LanguageBuilderFactory.class.getMethod(lang, 
String.class);
+            return m.getReturnType().getEnclosingClass() == expr.getClass() ? 
lang : null;
+        } catch (NoSuchMethodException e) {
+            return null;
+        }
+    }
+
     private String expressionBuilderOptions(ExpressionDefinition expr) {
         StringBuilder opts = new StringBuilder();
 
@@ -1576,6 +1600,15 @@ public abstract class JavaDslModelWriterSupport {
             appendOption(opts, "source", single.getSource());
         }
 
+        // the xml namespaces of xpath, xquery and xtokenize (those of the xml 
document the route was read from)
+        if (expr instanceof NamespaceAwareExpression nae && 
nae.getNamespaces() != null
+                && !nae.getNamespaces().isEmpty()) {
+            opts.append(".namespaces(Map.of(");
+            StringJoiner pairs = new StringJoiner(", ");
+            nae.getNamespaces().forEach((prefix, uri) -> 
pairs.add(quote(prefix) + ", " + quote(uri)));
+            opts.append(pairs).append("))");
+        }
+
         // type-specific options
         if (expr instanceof SimpleExpression se) {
             appendNonDefaultOption(opts, "trimResult", se.getTrimResult(), 
"false");
diff --git 
a/core/camel-java-io/src/test/java/org/apache/camel/java/in/RoundTripTest.java 
b/core/camel-java-io/src/test/java/org/apache/camel/java/in/RoundTripTest.java
index e05dbad37745..459de6a366f4 100644
--- 
a/core/camel-java-io/src/test/java/org/apache/camel/java/in/RoundTripTest.java
+++ 
b/core/camel-java-io/src/test/java/org/apache/camel/java/in/RoundTripTest.java
@@ -42,6 +42,7 @@ import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.java.LwModelToJavaDumper;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RoutesDefinition;
+import org.apache.camel.xml.LwModelToXMLDumper;
 import org.apache.camel.xml.in.ModelParser;
 import org.junit.jupiter.api.Test;
 
@@ -130,6 +131,58 @@ class RoundTripTest {
                 String.join("\n\n", failures)).isEmpty();
     }
 
+    /**
+     * Routes whose Java reads back to a model that differs from the XML one, 
and why: none of them loses what the route
+     * does.
+     */
+    private static final Map<String, String> KNOWN_XML = Map.of(
+            "barInterceptorRoute.xml", "Java has intercept() for all the 
routes of a route builder, not of one route",
+            "interceptFrom.xml", "Java has interceptFrom() for all the routes 
of a route builder, not of one route",
+            "interceptFromAndSendTo.xml",
+            "Java has interceptSendToEndpoint() for all the routes of a route 
builder, not of one route",
+            "routeInlinedErrorHandler.xml",
+            "the redelivery policy of deadLetterChannel() in Java says 
logExhausted=false, the default of a dead letter channel",
+            "circuitBreakerResilience4j.xml", "failureRateThreshold(float) 
keeps 30 as 30.0: the same value, written apart");
+
+    /**
+     * The routes of the XML corpus read back from the Java the dumper writes 
as the XML routes they were (CAMEL-25255):
+     * the Java writer leaves nothing of the route out, such as its error 
handler or the namespaces of an xpath.
+     */
+    @Test
+    void xmlCorpusReadsBackThroughJava() throws Exception {
+        assumeTrue(Files.isDirectory(CORPUS.get(0)), "the core test routes are 
next to this module");
+        List<Path> files = new ArrayList<>();
+        for (Path dir : CORPUS) {
+            try (Stream<Path> s = Files.list(dir)) {
+                files.addAll(s.filter(p -> 
p.toString().endsWith(".xml")).sorted().toList());
+            }
+        }
+        List<String> failures = new ArrayList<>();
+        int routes = 0;
+        for (Path file : files) {
+            if (KNOWN_XML.containsKey(file.getFileName().toString())) {
+                continue;
+            }
+            for (RouteDefinition route : routes(file)) {
+                routes++;
+                try (DefaultCamelContext context = new DefaultCamelContext()) {
+                    String xml = new 
LwModelToXMLDumper().dumpModelAsXml(context, route);
+                    String java = new 
LwModelToJavaDumper().dumpModelAsJava(context, route);
+                    JavaParseResult parsed = new LwJavaParser().parse(java + 
";");
+                    String back = parsed.routes().getRoutes().isEmpty()
+                            ? "" : new 
LwModelToXMLDumper().dumpModelAsXml(context, 
parsed.routes().getRoutes().get(0));
+                    if (!back.equals(xml)) {
+                        failures.add(file.getFileName() + "\n" + java + "\n--- 
was ---\n" + xml + "\n--- read back as ---\n"
+                                     + back);
+                    }
+                }
+            }
+        }
+        assertThat(routes).isGreaterThan(100);
+        assertThat(failures).as("%d of %d routes do not read back:%n%s", 
failures.size(), routes,
+                String.join("\n\n", failures)).isEmpty();
+    }
+
     /** The Java the dumper is tested to write (java-dsl-*.txt) reads back 
into the same Java. */
     @Test
     void dumperGoldenFiles() throws Exception {
diff --git 
a/core/camel-java-io/src/test/java/org/apache/camel/java/out/JavaDslCompileTest.java
 
b/core/camel-java-io/src/test/java/org/apache/camel/java/out/JavaDslCompileTest.java
index edb798a0291f..af32449f2765 100644
--- 
a/core/camel-java-io/src/test/java/org/apache/camel/java/out/JavaDslCompileTest.java
+++ 
b/core/camel-java-io/src/test/java/org/apache/camel/java/out/JavaDslCompileTest.java
@@ -444,6 +444,7 @@ public class JavaDslCompileTest {
     private static String wrapInRouteBuilder(String className, List<String> 
routeSnippets) {
         StringBuilder sb = new StringBuilder();
         sb.append("package test.generated;\n\n");
+        sb.append("import java.util.Map;\n\n");
         sb.append("import org.apache.camel.ExchangePattern;\n");
         sb.append("import org.apache.camel.LoggingLevel;\n");
         sb.append("import org.apache.camel.Predicate;\n");
diff --git 
a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java
 
b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java
index 55f7b50c48ca..3aeb60ef3950 100644
--- 
a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java
+++ 
b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java
@@ -870,8 +870,8 @@ public class YamlModelWriter extends YamlModelWriterSupport 
{
         doWriteAttribute(jo, "builderMethod", def.getBuilderMethod(), "build");
         doWriteAttribute(jo, "scriptLanguage", def.getScriptLanguage(), null);
         doWriteAttribute(jo, "scriptPropertyPlaceholders", 
def.getScriptPropertyPlaceholders(), "true");
-        doWriteChildElement(jo, "constructors", new 
BeanConstructorsAdapter().marshal(def.getConstructors()), 
this::doWriteBeanConstructorsDefinition);
-        doWriteChildElement(jo, "properties", new 
BeanPropertiesAdapter().marshal(def.getProperties()), 
this::doWriteBeanPropertiesDefinition);
+        doWriteBeanMap(jo, "constructors", def.getConstructors());
+        doWriteBeanMap(jo, "properties", def.getProperties());
         if (def.getScript() != null) {
             jo.put("script", def.getScript());
         }
@@ -1667,8 +1667,8 @@ public class YamlModelWriter extends 
YamlModelWriterSupport {
     protected JsonObject 
doWriteRouteTemplateDefinition(RouteTemplateDefinition def) {
         JsonObject jo = new JsonObject();
         doWriteOptionalIdentifiedDefinitionAttributes(jo, def);
-        doWriteChildList(jo, null, "templateParameter", 
def.getTemplateParameters(), this::doWriteRouteTemplateParameterDefinition);
-        doWriteChildList(jo, null, "templateBean", def.getTemplateBeans(), 
this::doWriteBeanFactoryDefinition);
+        doWriteChildList(jo, null, "parameters", def.getTemplateParameters(), 
this::doWriteRouteTemplateParameterDefinition);
+        doWriteChildList(jo, null, "beans", def.getTemplateBeans(), 
this::doWriteBeanFactoryDefinition);
         doWriteChildElement(jo, "route", def.getRoute(), 
this::doWriteRouteDefinition);
         return jo;
     }
@@ -2061,7 +2061,7 @@ public class YamlModelWriter extends 
YamlModelWriterSupport {
     }
     protected JsonObject doWriteValueDefinition(ValueDefinition def) {
         JsonObject jo = new JsonObject();
-        doWriteValue(jo, def.getValue());
+        doWriteAttribute(jo, "value", def.getValue(), null);
         return jo;
     }
     protected JsonObject doWriteWhenDefinition(WhenDefinition def) {
@@ -3411,7 +3411,7 @@ public class YamlModelWriter extends 
YamlModelWriterSupport {
         doWriteAttribute(jo, "enableNoContentResponse", 
def.getEnableNoContentResponse(), "false");
         doWriteAttribute(jo, "apiDocs", def.getApiDocs(), "true");
         doWriteAttribute(jo, "tag", def.getTag(), null);
-        doWriteChildList(jo, "verbs", "verbs", def.getVerbs(), 
this::doWriteVerbDefinition);
+        doWriteVerbs(jo, def.getVerbs(), this::doWriteVerbDefinition);
         doWriteChildElement(jo, "openApi", def.getOpenApi(), 
this::doWriteOpenApiDefinition);
         doWriteChildElement(jo, "securityDefinitions", 
def.getSecurityDefinitions(), this::doWriteRestSecuritiesDefinition);
         doWriteChildList(jo, null, "securityRequirements", 
def.getSecurityRequirements(), this::doWriteSecurityDefinition);
@@ -3480,9 +3480,9 @@ public class YamlModelWriter extends 
YamlModelWriterSupport {
         doWriteAttribute(jo, "consumes", def.getConsumes(), null);
     }
     protected void doWriteVerbDefinitionElements(JsonObject jo, VerbDefinition 
def) {
-        doWriteChildList(jo, "params", "params", def.getParams(), 
this::doWriteParamDefinition);
+        doWriteChildList(jo, null, "param", def.getParams(), 
this::doWriteParamDefinition);
         doWriteChildList(jo, "security", "security", def.getSecurity(), 
this::doWriteSecurityDefinition);
-        doWriteChildList(jo, "responseMsgs", "responseMsgs", 
def.getResponseMsgs(), this::doWriteResponseMessageDefinition);
+        doWriteChildList(jo, null, "responseMessage", def.getResponseMsgs(), 
this::doWriteResponseMessageDefinition);
         doWriteChildElement(jo, "to", def.getTo(), this::doWriteToDefinition);
     }
     protected JsonObject doWriteVerbDefinition(VerbDefinition def) {
diff --git 
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
 
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
index c5db9efafe79..22510f4548b7 100644
--- 
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
+++ 
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/LwModelToYAMLDumper.java
@@ -24,7 +24,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 
 import org.apache.camel.CamelContext;
@@ -407,63 +406,25 @@ public class LwModelToYAMLDumper implements 
ModelToYAMLDumper {
             if (beans.isEmpty()) {
                 return;
             }
-            buffer.write("- beans:\n");
+            // written by the model writer, so nested properties come out as 
nested maps, as the yaml dsl loads them
+            var writer = new YamlModelWriter() {
+                @Override
+                public JsonObject 
doWriteBeanFactoryDefinition(BeanFactoryDefinition<?> def) {
+                    return super.doWriteBeanFactoryDefinition(def);
+                }
+            };
+            writer.setCamelContext(camelContext);
+            JsonArray list = new JsonArray();
             for (BeanFactoryDefinition<?> b : beans) {
-                doWriteBeanFactoryDefinition(b);
-            }
-        }
-
-        private void doWriteBeanFactoryDefinition(BeanFactoryDefinition<?> b) {
-            String type = b.getType();
-            if (type.startsWith("#class:")) {
-                type = type.substring(7);
-            }
-            buffer.write(String.format("    - name: %s%n", b.getName()));
-            buffer.write(String.format("      type: \"%s\"%n", type));
-            if (b.getFactoryBean() != null) {
-                buffer.write(String.format("      factoryBean: \"%s\"%n", 
b.getFactoryBean()));
-            }
-            if (b.getFactoryMethod() != null) {
-                buffer.write(String.format("      factoryMethod: \"%s\"%n", 
b.getFactoryMethod()));
-            }
-            if (b.getBuilderClass() != null) {
-                buffer.write(String.format("      builderClass: \"%s\"%n", 
b.getBuilderClass()));
-            }
-            if (b.getBuilderMethod() != null) {
-                buffer.write(String.format("      builderMethod: \"%s\"%n", 
b.getBuilderMethod()));
-            }
-            if (b.getInitMethod() != null) {
-                buffer.write(String.format("      initMethod: \"%s\"%n", 
b.getInitMethod()));
-            }
-            if (b.getDestroyMethod() != null) {
-                buffer.write(String.format("      destroyMethod: \"%s\"%n", 
b.getDestroyMethod()));
-            }
-            if (b.getScriptLanguage() != null) {
-                buffer.write(String.format("      scriptLanguage: \"%s\"%n", 
b.getScriptLanguage()));
-            }
-            if (b.getScript() != null) {
-                buffer.write(String.format("      script: \"%s\"%n", 
b.getScript()));
-            }
-            if (b.getConstructors() != null && !b.getConstructors().isEmpty()) 
{
-                buffer.write(String.format("      constructors:%n"));
-                final AtomicInteger counter = new AtomicInteger();
-                b.getConstructors().forEach((key, value) -> {
-                    if (key == null) {
-                        key = counter.getAndIncrement();
-                    }
-                    buffer.write(String.format("        %d: \"%s\"%n", key, 
value));
-                });
-            }
-            if (b.getProperties() != null && !b.getProperties().isEmpty()) {
-                buffer.write(String.format("      properties:%n"));
-                b.getProperties().forEach((key, value) -> {
-                    if (value instanceof String) {
-                        buffer.write(String.format("        %s: \"%s\"%n", 
key, value));
-                    } else {
-                        buffer.write(String.format("        %s: %s%n", key, 
value));
-                    }
-                });
+                JsonObject bean = writer.doWriteBeanFactoryDefinition(b);
+                if (bean.get("type") instanceof String type && 
type.startsWith("#class:")) {
+                    bean.put("type", type.substring(7));
+                }
+                list.add(bean);
             }
+            JsonObject root = new JsonObject();
+            root.put("beans", list);
+            buffer.write(writer.printAsYaml(List.of(root)));
         }
     }
 
diff --git 
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/out/YamlModelWriterSupport.java
 
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/out/YamlModelWriterSupport.java
index 4fe49a127205..6af0454bb719 100644
--- 
a/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/out/YamlModelWriterSupport.java
+++ 
b/core/camel-yaml-io/src/main/java/org/apache/camel/yaml/out/YamlModelWriterSupport.java
@@ -25,6 +25,7 @@ import java.util.function.Function;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.catalog.RuntimeCamelCatalog;
+import org.apache.camel.model.rest.VerbDefinition;
 import org.apache.camel.util.URISupport;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
@@ -143,6 +144,37 @@ public abstract class YamlModelWriterSupport {
         }
     }
 
+    /**
+     * The verbs of a rest as the YAML DSL has them: a list per kind (get, 
post, ...), not one list of all verbs.
+     */
+    protected <T extends VerbDefinition> void doWriteVerbs(JsonObject jo, 
List<T> verbs, Function<T, JsonObject> writer) {
+        if (verbs != null) {
+            for (T verb : verbs) {
+                JsonObject child = writer.apply(verb);
+                if (child != null) {
+                    JsonArray arr = (JsonArray) 
jo.computeIfAbsent(verb.asVerb(), k -> new JsonArray());
+                    arr.add(child);
+                }
+            }
+        }
+    }
+
+    /**
+     * The properties or constructor arguments of a bean as the YAML DSL has 
them: a map, with a nested map for nested
+     * properties.
+     */
+    protected void doWriteBeanMap(JsonObject jo, String key, Map<?, ?> map) {
+        if (map != null && !map.isEmpty()) {
+            jo.put(key, beanMap(map));
+        }
+    }
+
+    private static JsonObject beanMap(Map<?, ?> map) {
+        JsonObject answer = new JsonObject();
+        map.forEach((k, v) -> answer.put(String.valueOf(k), v instanceof 
Map<?, ?> m ? beanMap(m) : v));
+        return answer;
+    }
+
     @SuppressWarnings("unchecked")
     protected void doWriteStringList(JsonObject jo, String wrapperKey, String 
itemKey, List<String> list) {
         if (list != null && !list.isEmpty()) {
diff --git 
a/core/camel-yaml-io/src/test/java/org/apache/camel/yaml/out/YamlBeansDumpTest.java
 
b/core/camel-yaml-io/src/test/java/org/apache/camel/yaml/out/YamlBeansDumpTest.java
new file mode 100644
index 000000000000..28e23450a3e4
--- /dev/null
+++ 
b/core/camel-yaml-io/src/test/java/org/apache/camel/yaml/out/YamlBeansDumpTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.yaml.out;
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.model.BeanFactoryDefinition;
+import org.apache.camel.model.app.BeansDefinition;
+import org.apache.camel.xml.in.ModelParser;
+import org.apache.camel.yaml.LwModelToYAMLDumper;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * The beans dumped as YAML have their properties as the YAML DSL loads them: 
nested properties as a nested map
+ * (CAMEL-25255).
+ */
+class YamlBeansDumpTest {
+
+    @Test
+    void nestedPropertiesAreANestedMap() throws Exception {
+        BeansDefinition beans;
+        try (InputStream in = 
Files.newInputStream(Paths.get("../camel-xml-io/src/test/resources/beansWithProperties.xml")))
 {
+            beans = new ModelParser(in, 
"http://camel.apache.org/schema/xml-io";).parseBeansDefinition().orElseThrow();
+        }
+        String yaml = new LwModelToYAMLDumper().dumpBeansAsYaml(null, new 
ArrayList<>(beans.getBeans()));
+        assertThat(yaml).isEqualTo("""
+                - beans:
+                    - name: b1
+                      type: org.apache.camel.xml.in.ModelParserTest.MyBean
+                      properties:
+                        p1: v1
+                        p2: v2
+                        nested:
+                          p1: v1a
+                          p2: v2a
+                    - name: b2
+                      type: org.apache.camel.xml.in.ModelParserTest.MyBean
+                      properties:
+                        p1: v1
+                        p2: v2
+                        nested.p1: v1a
+                        nested.p2: v2a
+                """);
+    }
+
+    @Test
+    void theClassPrefixOfTheTypeIsLeftOut() throws Exception {
+        BeanFactoryDefinition<?> bean = new BeanFactoryDefinition<>();
+        bean.setName("greeter");
+        bean.setType("#class:com.foo.Greeter");
+        String yaml = new LwModelToYAMLDumper().dumpBeansAsYaml(null, 
List.of(bean));
+        assertThat(yaml).contains("type: 
com.foo.Greeter").doesNotContain("#class");
+    }
+}
diff --git a/core/camel-yaml-io/src/test/resources/yaml-beans-with-route.yaml 
b/core/camel-yaml-io/src/test/resources/yaml-beans-with-route.yaml
index 64db76b553c7..02359c8af424 100644
--- a/core/camel-yaml-io/src/test/resources/yaml-beans-with-route.yaml
+++ b/core/camel-yaml-io/src/test/resources/yaml-beans-with-route.yaml
@@ -20,9 +20,7 @@
       - name: myService
         type: com.example.MyService
         properties:
-          property:
-            - key: url
-              value: http://localhost:8080
+          url: http://localhost:8080
     route:
       - customId: true
         id: myRoute
diff --git a/core/camel-yaml-io/src/test/resources/yaml-beans.yaml 
b/core/camel-yaml-io/src/test/resources/yaml-beans.yaml
index 3e50198f4fdc..841c9322fc89 100644
--- a/core/camel-yaml-io/src/test/resources/yaml-beans.yaml
+++ b/core/camel-yaml-io/src/test/resources/yaml-beans.yaml
@@ -19,11 +19,8 @@
     name: myBean
     type: com.example.MyBean
     properties:
-      property:
-        - key: greeting
-          value: Hello
-        - key: count
-          value: 5
+      greeting: Hello
+      count: "5"
 - beanFactory:
     name: myFactory
     type: com.example.MyFactory
diff --git a/core/camel-yaml-io/src/test/resources/yaml-rest.yaml 
b/core/camel-yaml-io/src/test/resources/yaml-rest.yaml
index fee9da12aaaa..9ee93c87a537 100644
--- a/core/camel-yaml-io/src/test/resources/yaml-rest.yaml
+++ b/core/camel-yaml-io/src/test/resources/yaml-rest.yaml
@@ -17,10 +17,11 @@
 
 - rest:
     path: /api
-    verbs:
+    get:
       - path: /hello
         to:
           uri: direct:hello
+    post:
       - path: /bye
         consumes: application/json
         to:
diff --git a/core/camel-yaml-io/src/test/resources/yaml-route-template.yaml 
b/core/camel-yaml-io/src/test/resources/yaml-route-template.yaml
index a1ad10bd8c38..544d3a05f61a 100644
--- a/core/camel-yaml-io/src/test/resources/yaml-route-template.yaml
+++ b/core/camel-yaml-io/src/test/resources/yaml-route-template.yaml
@@ -18,7 +18,7 @@
 - routeTemplate:
     customId: true
     id: myTemplate
-    templateParameter:
+    parameters:
       - description: the foo parameter
         name: foo
       - description: the bar parameter
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 1800adfbabfd..c15293a15c68 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -4193,3 +4193,23 @@ WebSocket transport already were. Before, it kept the 
JVM alive when the applica
 Spring Boot application whose port was in use: Camel had not started, so it 
never stopped the connector. An application
 that only kept running because of this thread now exits; keep it running on 
purpose, for example with
 `camel.main.run-controller=true` for a Spring Boot application without a web 
server.
+
+=== Route dumps as YAML and Java
+
+Routes dumped as YAML (`camel.main.dumpRoutes=yaml`, `camel transform route 
--format=yaml`) are now written as the
+YAML DSL loads them:
+
+* the verbs of a rest are listed by their kind (`get`, `post`, ...) instead of 
under `verbs`, and their parameters and
+  response messages as `param` and `responseMessage`;
+* a route template has `parameters` and `beans` instead of `templateParameter` 
and `templateBean`;
+* the properties of a bean are a map, also when they are nested, instead of a 
`property` list.
+
+Before, such a dump did not load in the YAML DSL.
+
+A route built in Java with its own error handler 
(`from("...").errorHandler(deadLetterChannel("..."))`) now has the
+error handler in its model, so dumping the route (as XML, YAML or Java) writes 
it; it was left out before. When written
+as Java, the error handler of an XML or YAML route is now `.errorHandler(...)` 
on the route, instead of an
+`errorHandler(...)` that applies to every route of the route builder.
+
+The `timeout(long)` of the Resequencer EIP in Java keeps the millis as given 
(`2000`), instead of a duration
+(`2s0ms`).
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/resources/blueprint-out.yaml 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/blueprint-out.yaml
index 754bcf2ae5e9..e304ac8d51cc 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/resources/blueprint-out.yaml
+++ b/dsl/camel-jbang/camel-jbang-core/src/test/resources/blueprint-out.yaml
@@ -17,7 +17,7 @@
 
 - beans:
     - name: userService
-      type: "org.apache.camel.example.rest.UserService"
+      type: org.apache.camel.example.rest.UserService
 - route:
     from:
       uri: direct
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlRestTemplateRoundTripTest.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlRestTemplateRoundTripTest.java
new file mode 100644
index 000000000000..e6e5792cf56e
--- /dev/null
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlRestTemplateRoundTripTest.java
@@ -0,0 +1,221 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.yaml.validator;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import com.networknt.schema.Error;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.model.ModelCamelContext;
+import org.apache.camel.model.RouteTemplatesDefinition;
+import org.apache.camel.model.rest.RestsDefinition;
+import org.apache.camel.support.PluginHelper;
+import org.apache.camel.support.ResourceHelper;
+import org.apache.camel.xml.LwModelToXMLDumper;
+import org.apache.camel.xml.in.ModelParser;
+import org.apache.camel.yaml.LwModelToYAMLDumper;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
+/**
+ * Rests and route templates dumped as YAML are loaded back by the YAML DSL as 
they were (CAMEL-25255): the YAML writer
+ * writes the verbs of a rest by their kind (get, post, ...), and the 
parameters and beans of a route template as the
+ * YAML DSL names them.
+ */
+class YamlRestTemplateRoundTripTest {
+
+    private static final String NS = "http://camel.apache.org/schema/xml-io";;
+    private static final Path CORPUS = 
Path.of("../../../core/camel-xml-io/src/test/resources");
+
+    private static final String REST = """
+            <rests xmlns="http://camel.apache.org/schema/xml-io";>
+                <rest id="api" path="/api" tag="orders" 
consumes="application/json" bindingMode="json">
+                    <securityDefinitions>
+                        <apiKey key="key" name="X-Key" inHeader="true"/>
+                        <oauth2 key="oauth" flow="implicit" 
authorizationUrl="https://auth/authorize";>
+                            <scopes key="read" value="Read orders"/>
+                        </oauth2>
+                    </securityDefinitions>
+                    <securityRequirements key="key"/>
+                    <get path="/orders/{id}" id="getOrder" 
outType="com.foo.Order" routeId="get-order"
+                         description="Gets an order">
+                        <param name="id" type="path" description="The order 
id" dataType="integer">
+                            <examples key="one" value="1"/>
+                        </param>
+                        <param name="verbose" type="query" required="false" 
defaultValue="false">
+                            <allowableValues>
+                                <value>true</value>
+                                <value>false</value>
+                            </allowableValues>
+                        </param>
+                        <responseMessage code="404" message="Not found">
+                            <header name="X-Reason" dataType="string"/>
+                            <examples key="json" value="{}"/>
+                        </responseMessage>
+                        <security key="oauth" scopes="read"/>
+                        <to uri="direct:getOrder"/>
+                    </get>
+                    <get path="/orders">
+                        <to uri="direct:listOrders"/>
+                    </get>
+                    <post path="/orders" type="com.foo.Order">
+                        <to uri="direct:createOrder"/>
+                    </post>
+                    <put path="/orders/{id}">
+                        <to uri="direct:updateOrder"/>
+                    </put>
+                    <delete path="/orders/{id}">
+                        <to uri="direct:deleteOrder"/>
+                    </delete>
+                    <head path="/orders">
+                        <to uri="direct:headOrders"/>
+                    </head>
+                    <patch path="/orders/{id}">
+                        <to uri="direct:patchOrder"/>
+                    </patch>
+                </rest>
+                <rest path="/petstore">
+                    <openApi specification="petstore.json" 
missingOperation="mock"/>
+                </rest>
+            </rests>
+            """;
+
+    private static final String TEMPLATE = """
+            <routeTemplates xmlns="http://camel.apache.org/schema/xml-io";>
+                <routeTemplate id="myTemplate">
+                    <templateParameter name="foo" description="The input"/>
+                    <templateParameter name="bar" defaultValue="out" 
required="false"/>
+                    <templateBean name="greeter" type="com.foo.Greeter">
+                        <properties>
+                            <property key="greeting" value="Hello"/>
+                        </properties>
+                    </templateBean>
+                    <route>
+                        <from uri="direct:{{foo}}"/>
+                        <to uri="mock:{{bar}}"/>
+                    </route>
+                </routeTemplate>
+            </routeTemplates>
+            """;
+
+    @Test
+    void restWithAllItsParts() throws Exception {
+        assertThat(restsRoundTrip(REST)).isNull();
+    }
+
+    @Test
+    void routeTemplateWithParametersAndBeans() throws Exception {
+        assertThat(templatesRoundTrip(TEMPLATE)).isNull();
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "barRest.xml", "simpleRest.xml", 
"restAllowedValues.xml" })
+    void restsOfTheCorpus(String file) throws Exception {
+        assumeTrue(Files.isDirectory(CORPUS), "the core test routes are in the 
source tree");
+        
assertThat(restsRoundTrip(Files.readString(CORPUS.resolve(file)))).isNull();
+    }
+
+    @Test
+    void routeTemplatesOfTheCorpus() throws Exception {
+        assumeTrue(Files.isDirectory(CORPUS), "the core test routes are in the 
source tree");
+        
assertThat(templatesRoundTrip(Files.readString(CORPUS.resolve("barTemplate.xml")))).isNull();
+    }
+
+    private static InputStream in(String xml) {
+        return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+    }
+
+    /**
+     * Null when the rests read back as they were, else what went wrong. Both 
sides are added to a context the same way,
+     * so what loading adds (such as the params of a path) is on both.
+     */
+    private static String restsRoundTrip(String xml) throws Exception {
+        RestsDefinition rests = new ModelParser(in(xml), 
NS).parseRestsDefinition().orElseThrow();
+        String yaml;
+        String before;
+        try (DefaultCamelContext context = new DefaultCamelContext()) {
+            yaml = new LwModelToYAMLDumper().dumpModelAsYaml(context, rests);
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    getRestCollection().setRests(rests.getRests());
+                }
+            });
+            before = dumpRests(context);
+        }
+        return readBack(yaml, before, 
YamlRestTemplateRoundTripTest::dumpRests);
+    }
+
+    /** Null when the route templates read back as they were, else what went 
wrong. */
+    private static String templatesRoundTrip(String xml) throws Exception {
+        RouteTemplatesDefinition templates = new ModelParser(in(xml), 
NS).parseRouteTemplatesDefinition().orElseThrow();
+        String yaml;
+        String before;
+        try (DefaultCamelContext context = new DefaultCamelContext()) {
+            yaml = new LwModelToYAMLDumper().dumpModelAsYaml(context, 
templates);
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    
getRouteTemplateCollection().setRouteTemplates(templates.getRouteTemplates());
+                }
+            });
+            before = dumpTemplates(context);
+        }
+        return readBack(yaml, before, 
YamlRestTemplateRoundTripTest::dumpTemplates);
+    }
+
+    private static String dumpRests(DefaultCamelContext context) throws 
Exception {
+        RestsDefinition rests = new RestsDefinition();
+        
rests.setRests(context.getCamelContextExtension().getContextPlugin(ModelCamelContext.class).getRestDefinitions());
+        return new LwModelToXMLDumper().dumpModelAsXml(context, rests);
+    }
+
+    private static String dumpTemplates(DefaultCamelContext context) throws 
Exception {
+        RouteTemplatesDefinition templates = new RouteTemplatesDefinition();
+        
templates.setRouteTemplates(context.getCamelContextExtension().getContextPlugin(ModelCamelContext.class)
+                .getRouteTemplateDefinitions());
+        return new LwModelToXMLDumper().dumpModelAsXml(context, templates);
+    }
+
+    private interface Dump {
+        String dump(DefaultCamelContext context) throws Exception;
+    }
+
+    private static String readBack(String yaml, String before, Dump dump) 
throws Exception {
+        List<Error> errors = new YamlValidator().validate(yaml);
+        if (!errors.isEmpty()) {
+            return yaml + "\n--- does not validate: " + errors;
+        }
+        try (DefaultCamelContext context = new DefaultCamelContext()) {
+            
PluginHelper.getRoutesLoader(context).loadRoutes(ResourceHelper.fromString("rest.yaml",
 yaml));
+            String after = dump.dump(context);
+            return after.equals(before) ? null : yaml + "\n--- was ---\n" + 
before + "\n--- read back as ---\n" + after;
+        } catch (RuntimeException e) {
+            return yaml + "\n--- does not load: " + e;
+        }
+    }
+}
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-yaml-writer.vm
 
b/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-yaml-writer.vm
index 711796bc892a..c9153ee6f1a6 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-yaml-writer.vm
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-yaml-writer.vm
@@ -15,6 +15,8 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 #set( $default = "#[[##default]]#" )
+## the YAML DSL names some lists other than the XML DSL does (keyed by 
class.member)
+#set( $yamlKeys = { "VerbDefinition.params": "param", 
"VerbDefinition.responseMsgs": "responseMessage", 
"RouteTemplateDefinition.templateParameters": "parameters", 
"RouteTemplateDefinition.templateBeans": "beans" } )
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -141,8 +143,13 @@ public class YamlModelWriter extends 
YamlModelWriterSupport {
                     #elseif( $member.xmlElementRef )
                         #set( $foo = $elementRefs.add($root) )
                         #if( $list )
+                            #set( $yamlKey = 
$yamlKeys.get("${clazz.simpleName}.${member.name}") )
                             #if( $member.name == "outputs" )
         doWriteOutputs(jo, def.${member.getter}(), 
this::doWrite${root.simpleName}Ref);
+                            #elseif( $clazz.simpleName == "RestDefinition" && 
$member.name == "verbs" )
+        doWriteVerbs(jo, def.${member.getter}(), 
this::doWrite${root.simpleName});
+                            #elseif( $yamlKey )
+        doWriteChildList(jo, null, "${yamlKey}", def.${member.getter}(), 
this::doWrite${root.simpleName});
                             #else
                                 #set( $refName = $member.xmlElementRef.name() )
                                 #if( $refName && $refName != $default && 
$refName != "" )
@@ -186,6 +193,10 @@ public class YamlModelWriter extends 
YamlModelWriterSupport {
                         #if( $n == $default )
                             #set( $n = ${member.name} )
                         #end
+                        #set( $yamlKey = 
$yamlKeys.get("${clazz.simpleName}.${member.name}") )
+                        #if( $yamlKey )
+                            #set( $n = $yamlKey )
+                        #end
                         #if( $list )
                             #set( $w = false )
                             #if( $member.xmlElementWrapper )
@@ -198,7 +209,9 @@ public class YamlModelWriter extends YamlModelWriterSupport 
{
                             #end
                         #else
                             #set( $adapter = $member.xmlJavaTypeAdapter )
-                            #if( $adapter )
+                            #if( $adapter && $clazz.simpleName == 
"BeanFactoryDefinition" )
+        doWriteBeanMap(jo, "${n}", def.${member.getter}());
+                            #elseif( $adapter )
                                 #set( $cl = $adapter.value() )
                                 #set( $actualType = false )
                                 #foreach( $m in $cl.declaredMethods )
@@ -268,7 +281,9 @@ public class YamlModelWriter extends YamlModelWriterSupport 
{
                 #writeYamlAttrs
             #end
             #set( $value = 
$mojo.getValues($mojo.getClassAndSuper($clazz)).findFirst() )
-            #if( $value.isPresent() )
+            #if( $value.isPresent() && $name == "ValueDefinition" )
+        doWriteAttribute(jo, "value", def.${value.get().getter}(), null);
+            #elseif( $value.isPresent() )
         doWriteValue(jo, def.${value.get().getter}());
             #end
             #if( $hasDerived && !$thisElements.isEmpty() )

Reply via email to