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 8a62b1441059 CAMEL-25410: camel-core-model - doTry keeps doCatch and
doFinally in its outputs (#29772)
8a62b1441059 is described below
commit 8a62b14410599d9dec6e516e5a3b4042ba6f88b6
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Nov 13 08:03:41 2026 +0100
CAMEL-25410: camel-core-model - doTry keeps doCatch and doFinally in its
outputs (#29772)
TryDefinition kept doCatch/doFinally both in its outputs and in transient
fields, so walks of getOutputs() missed the YAML property-form clauses, and
a
clause removed from the outputs was still reified. The outputs are now the
single source of truth:
- setCatchClauses/setFinallyClause fold the clauses into the outputs
- getCatchClauses, getFinallyClause and getOutputsWithoutCatches are derived
- the copy constructor no longer copies the clause fields
- TryDefinition.addOutput keeps steps before the clauses (YAML key order)
- the CAMEL-25367 special case of the model writer templates is removed and
the writers regenerated
- 4.24 upgrade-guide note
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../java/org/apache/camel/model/TryDefinition.java | 115 ++++++++++++----
.../camel/model/TryDefinitionClausesTest.java | 121 +++++++++++++++++
.../interceptor/AdviceWithRemoveDoCatchTest.java | 69 ++++++++++
.../JaxbDumpModelAsXmlTryPropertyClausesTest.java | 66 +++++++++
.../apache/camel/java/out/JavaDslModelWriter.java | 19 +--
.../apache/camel/java/out/TryModelWriterTest.java | 27 +++-
.../java/org/apache/camel/xml/out/ModelWriter.java | 19 +--
.../apache/camel/xml/out/TryModelWriterTest.java | 27 +++-
.../org/apache/camel/yaml/out/YamlModelWriter.java | 18 +--
.../apache/camel/yaml/out/TryModelWriterTest.java | 27 +++-
.../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 9 ++
.../camel/dsl/yaml/TryPropertyClausesTest.java | 147 +++++++++++++++++++++
.../resources/velocity/model-java-dsl-writer.vm | 21 ---
.../src/main/resources/velocity/model-writer.vm | 21 ---
.../main/resources/velocity/model-yaml-writer.vm | 20 ---
15 files changed, 585 insertions(+), 141 deletions(-)
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/TryDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/TryDefinition.java
index 41f73f3d593a..f383c334462b 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/TryDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/TryDefinition.java
@@ -47,6 +47,9 @@ import org.apache.camel.spi.annotations.DslProperty;
eipSteps = @BodyType(Carrier.UNCHANGED))
public class TryDefinition extends OutputDefinition<TryDefinition> {
+ // the doCatch and doFinally clauses are kept in outputs (the single
source of truth, CAMEL-25410): these fields
+ // are only the YAML DSL properties (doCatch and doFinally written as
properties of doTry), and a cache derived
+ // from outputs by checkInitialized
@DslProperty
@XmlTransient
private List<CatchDefinition> catchClauses;
@@ -64,9 +67,9 @@ public class TryDefinition extends
OutputDefinition<TryDefinition> {
}
protected TryDefinition(TryDefinition source) {
+ // the clauses are in the outputs, which super copies: the cache
fields are derived again from the copied outputs
+ // (copying them too would give the copy two instances of each clause)
super(source);
- this.catchClauses =
ProcessorDefinitionHelper.deepCopyDefinitions(source.catchClauses);
- this.finallyClause = source.finallyClause != null ?
source.finallyClause.copyDefinition() : null;
}
@Override
@@ -162,34 +165,60 @@ public class TryDefinition extends
OutputDefinition<TryDefinition> {
// Properties
//
-------------------------------------------------------------------------
+ /**
+ * Adds the doCatch clauses to the outputs (before the doFinally, if any),
where the clauses of a doTry are kept.
+ * Used by the YAML DSL for doCatch written as a property of doTry.
+ */
@XmlTransient
public void setCatchClauses(List<CatchDefinition> catchClauses) {
- this.catchClauses = catchClauses;
+ if (catchClauses != null) {
+ for (CatchDefinition catchClause : catchClauses) {
+ if (!outputs.contains(catchClause)) {
+ catchClause.setParent(this);
+ configureChild(catchClause);
+ outputs.add(indexOfFinally(), catchClause);
+ }
+ }
+ }
+ initialized = false;
}
+ /**
+ * The doCatch clauses, in the order of the outputs where they are kept.
+ */
public List<CatchDefinition> getCatchClauses() {
- if (catchClauses == null) {
- checkInitialized();
- }
+ refresh();
return catchClauses;
}
+ /**
+ * Sets the doFinally clause in the outputs, where the clauses of a doTry
are kept, replacing any other. Used by the
+ * YAML DSL for doFinally written as a property of doTry.
+ */
@XmlTransient
public void setFinallyClause(FinallyDefinition finallyClause) {
- this.finallyClause = finallyClause;
+ outputs.removeIf(o -> o instanceof FinallyDefinition && o !=
finallyClause);
+ if (finallyClause != null && !outputs.contains(finallyClause)) {
+ finallyClause.setParent(this);
+ configureChild(finallyClause);
+ outputs.add(finallyClause);
+ }
+ initialized = false;
}
+ /**
+ * The doFinally clause from the outputs, or null if there is none.
+ */
public FinallyDefinition getFinallyClause() {
- if (finallyClause == null) {
- checkInitialized();
- }
+ refresh();
return finallyClause;
}
+ /**
+ * The outputs that are the steps of the doTry block: all outputs except
the doCatch and doFinally clauses.
+ */
public List<ProcessorDefinition<?>> getOutputsWithoutCatches() {
- if (outputsWithoutCatches == null) {
- checkInitialized();
- }
+ refresh();
return outputsWithoutCatches;
}
@@ -211,6 +240,18 @@ public class TryDefinition extends
OutputDefinition<TryDefinition> {
// reset end counter as we are adding some outputs
endCounter = 0;
super.addOutput(output);
+ // a step added to this doTry itself (not to the doCatch or doFinally
the Java DSL is building, which takes it
+ // as its own output) after a clause, such as YAML steps after doCatch
written as a property, goes before the
+ // clauses: the runtime takes the steps from anywhere in the outputs,
and the outputs then read (and are dumped)
+ // as steps, doCatch and doFinally in this order
+ if (!(output instanceof CatchDefinition) && !(output instanceof
FinallyDefinition)
+ && !outputs.isEmpty() && outputs.get(outputs.size() - 1) ==
output) {
+ int index = indexOfFirstClause();
+ if (index < outputs.size() - 1) {
+ outputs.remove(outputs.size() - 1);
+ outputs.add(index, output);
+ }
+ }
}
protected ProcessorDefinition<?> onEndDoTry() {
@@ -230,28 +271,56 @@ public class TryDefinition extends
OutputDefinition<TryDefinition> {
}
/**
- * Checks whether or not this object has been initialized
+ * Derives the clauses and the steps from the outputs again: the outputs
can be changed directly (for example by
+ * advice-with), so a clause that is no longer in the outputs must not
stay in the cache.
+ */
+ private void refresh() {
+ initialized = false;
+ checkInitialized();
+ }
+
+ private int indexOfFinally() {
+ for (int i = 0; i < outputs.size(); i++) {
+ if (outputs.get(i) instanceof FinallyDefinition) {
+ return i;
+ }
+ }
+ return outputs.size();
+ }
+
+ private int indexOfFirstClause() {
+ for (int i = 0; i < outputs.size(); i++) {
+ if (outputs.get(i) instanceof CatchDefinition || outputs.get(i)
instanceof FinallyDefinition) {
+ return i;
+ }
+ }
+ return outputs.size();
+ }
+
+ /**
+ * Checks whether or not this object has been initialized, and derives the
doCatch and doFinally clauses and the
+ * steps from the outputs if not.
*/
protected void checkInitialized() {
if (!initialized) {
initialized = true;
- outputsWithoutCatches = new ArrayList<>();
- if (catchClauses == null) {
- catchClauses = new ArrayList<>();
- }
+ List<ProcessorDefinition<?>> steps = new ArrayList<>();
+ List<CatchDefinition> catches = new ArrayList<>();
+ FinallyDefinition doFinally = null;
int doFinallyCounter = 0;
for (ProcessorDefinition<?> output : outputs) {
if (output instanceof CatchDefinition catchDefinition) {
- if (!catchClauses.contains(output)) {
- catchClauses.add(catchDefinition);
- }
+ catches.add(catchDefinition);
} else if (output instanceof FinallyDefinition
finallyDefinition) {
++doFinallyCounter;
- finallyClause = finallyDefinition;
+ doFinally = finallyDefinition;
} else {
- outputsWithoutCatches.add(output);
+ steps.add(output);
}
}
+ outputsWithoutCatches = steps;
+ catchClauses = catches;
+ finallyClause = doFinally;
if (doFinallyCounter > 1) {
throw new IllegalArgumentException(
"Multiple finally clauses added: " + doFinallyCounter);
diff --git
a/core/camel-core/src/test/java/org/apache/camel/model/TryDefinitionClausesTest.java
b/core/camel-core/src/test/java/org/apache/camel/model/TryDefinitionClausesTest.java
new file mode 100644
index 000000000000..81c70981452b
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/model/TryDefinitionClausesTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.model;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * The doCatch and doFinally clauses of a doTry are kept in its outputs, also
when they are set as properties (as the
+ * YAML DSL does), and the clause getters are derived from the outputs
(CAMEL-25410).
+ */
+public class TryDefinitionClausesTest {
+
+ @Test
+ public void testClausesSetAsPropertiesAreInTheOutputs() {
+ TryDefinition doTry = new TryDefinition();
+ CatchDefinition doCatch = newCatch("mock:catch");
+ FinallyDefinition doFinally = newFinally("mock:finally");
+ doTry.setFinallyClause(doFinally);
+ doTry.setCatchClauses(List.of(doCatch));
+ // steps written after the clauses (as YAML with doCatch above steps)
go before them
+ doTry.addOutput(new ToDefinition("mock:a"));
+ doTry.addOutput(new ToDefinition("mock:b"));
+
+ assertThat(doTry.getOutputs()).hasSize(4);
+ assertThat(((ToDefinition)
doTry.getOutputs().get(0)).getUri()).isEqualTo("mock:a");
+ assertThat(((ToDefinition)
doTry.getOutputs().get(1)).getUri()).isEqualTo("mock:b");
+ assertThat(doTry.getOutputs().get(2)).isSameAs(doCatch);
+ assertThat(doTry.getOutputs().get(3)).isSameAs(doFinally);
+
+ assertThat(doTry.getCatchClauses()).containsExactly(doCatch);
+ assertThat(doTry.getFinallyClause()).isSameAs(doFinally);
+ assertThat(doTry.getOutputsWithoutCatches()).hasSize(2);
+ assertThat(doCatch.getParent()).isSameAs(doTry);
+ assertThat(doFinally.getParent()).isSameAs(doTry);
+ }
+
+ @Test
+ public void testSettingTheClausesAgainDoesNotDuplicateThem() {
+ TryDefinition doTry = new TryDefinition();
+ doTry.addOutput(new ToDefinition("mock:a"));
+ CatchDefinition doCatch = newCatch("mock:catch");
+ doTry.setCatchClauses(List.of(doCatch));
+ doTry.setCatchClauses(List.of(doCatch));
+ FinallyDefinition first = newFinally("mock:first");
+ FinallyDefinition second = newFinally("mock:second");
+ doTry.setFinallyClause(first);
+ // a doTry has one doFinally: setting another replaces it
+ doTry.setFinallyClause(second);
+
+ assertThat(doTry.getOutputs()).hasSize(3);
+ assertThat(doTry.getCatchClauses()).containsExactly(doCatch);
+ assertThat(doTry.getFinallyClause()).isSameAs(second);
+ assertThat(doTry.getOutputs()).doesNotContain(first);
+ }
+
+ @Test
+ public void testClauseRemovedFromTheOutputsIsGone() {
+ TryDefinition doTry = new TryDefinition();
+ doTry.addOutput(new ToDefinition("mock:a"));
+ CatchDefinition doCatch = newCatch("mock:catch");
+ CatchDefinition other = newCatch("mock:other");
+ FinallyDefinition doFinally = newFinally("mock:finally");
+ doTry.setCatchClauses(List.of(doCatch, other));
+ doTry.setFinallyClause(doFinally);
+ assertThat(doTry.getCatchClauses()).containsExactly(doCatch, other);
+
+ // as advice-with does: the outputs are changed directly
+ doTry.getOutputs().remove(other);
+ doTry.getOutputs().remove(doFinally);
+
+ assertThat(doTry.getCatchClauses()).containsExactly(doCatch);
+ assertThat(doTry.getFinallyClause()).isNull();
+ }
+
+ @Test
+ public void testCopyHasOneInstanceOfEachClause() {
+ TryDefinition doTry = new TryDefinition();
+ doTry.addOutput(new ToDefinition("mock:a"));
+ doTry.setCatchClauses(List.of(newCatch("mock:catch")));
+ doTry.setFinallyClause(newFinally("mock:finally"));
+
+ TryDefinition copy = doTry.copyDefinition();
+
+ assertThat(copy.getOutputs()).hasSize(3);
+ assertThat(copy.getCatchClauses()).hasSize(1);
+ assertThat(copy.getOutputs()).contains(copy.getCatchClauses().get(0),
copy.getFinallyClause());
+
assertThat(copy.getCatchClauses().get(0)).isNotSameAs(doTry.getCatchClauses().get(0));
+ assertThat(copy.getCatchClauses().get(0).getParent()).isSameAs(copy);
+ }
+
+ private static CatchDefinition newCatch(String uri) {
+ CatchDefinition answer = new CatchDefinition();
+ answer.getExceptions().add("java.lang.Exception");
+ answer.addOutput(new ToDefinition(uri));
+ return answer;
+ }
+
+ private static FinallyDefinition newFinally(String uri) {
+ FinallyDefinition answer = new FinallyDefinition();
+ answer.addOutput(new ToDefinition(uri));
+ return answer;
+ }
+}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/AdviceWithRemoveDoCatchTest.java
b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/AdviceWithRemoveDoCatchTest.java
new file mode 100644
index 000000000000..3fa2e3136d43
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/processor/interceptor/AdviceWithRemoveDoCatchTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.processor.interceptor;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.AdviceWith;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.CatchDefinition;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * A doCatch removed with advice-with from a route that has been started no
longer runs (CAMEL-25410).
+ */
+public class AdviceWithRemoveDoCatchTest extends ContextTestSupport {
+
+ @Test
+ public void testRemovedDoCatchDoesNotRun() throws Exception {
+ // the route has been started, so its doTry has been reified once with
the doCatch
+ getMockEndpoint("mock:catch").expectedMessageCount(1);
+ getMockEndpoint("mock:finally").expectedMessageCount(1);
+ template.sendBody("direct:start", "Hello");
+ assertMockEndpointsSatisfied();
+
+ AdviceWith.adviceWith(context, "myRoute", a ->
a.weaveByType(CatchDefinition.class).remove());
+
+ resetMocks();
+ getMockEndpoint("mock:catch").expectedMessageCount(0);
+ getMockEndpoint("mock:finally").expectedMessageCount(1);
+ CamelExecutionException e
+ = assertThrows(CamelExecutionException.class, () ->
template.sendBody("direct:start", "World"));
+ assertInstanceOf(IllegalArgumentException.class, e.getCause());
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:start").routeId("myRoute")
+ .doTry()
+ .throwException(new
IllegalArgumentException("Forced"))
+ .doCatch(IllegalArgumentException.class)
+ .to("mock:catch")
+ .doFinally()
+ .to("mock:finally")
+ .end();
+ }
+ };
+ }
+}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/util/JaxbDumpModelAsXmlTryPropertyClausesTest.java
b/core/camel-core/src/test/java/org/apache/camel/util/JaxbDumpModelAsXmlTryPropertyClausesTest.java
new file mode 100644
index 000000000000..d64ee70a3acf
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/util/JaxbDumpModelAsXmlTryPropertyClausesTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.util;
+
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.model.CatchDefinition;
+import org.apache.camel.model.FinallyDefinition;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.ToDefinition;
+import org.apache.camel.model.TryDefinition;
+import org.apache.camel.xml.jaxb.JaxbModelToXMLDumper;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The JAXB dumper writes the doCatch and doFinally of a doTry also when they
are set as properties, as the YAML DSL
+ * does (CAMEL-25410).
+ */
+public class JaxbDumpModelAsXmlTryPropertyClausesTest extends
ContextTestSupport {
+
+ @Test
+ public void testDumpModelAsXml() throws Exception {
+ CatchDefinition doCatch = new CatchDefinition();
+ doCatch.getExceptions().add("java.lang.IllegalStateException");
+ doCatch.addOutput(new ToDefinition("mock:catch"));
+ FinallyDefinition doFinally = new FinallyDefinition();
+ doFinally.addOutput(new ToDefinition("mock:finally"));
+ TryDefinition doTry = new TryDefinition();
+ // as YAML with doCatch and doFinally written above the steps
+ doTry.setCatchClauses(List.of(doCatch));
+ doTry.setFinallyClause(doFinally);
+ doTry.addOutput(new ToDefinition("mock:try"));
+
+ RouteDefinition route = new RouteDefinition();
+ route.routeId("myRoute");
+ route.from("direct:start");
+ route.addOutput(doTry);
+
+ String xml = new JaxbModelToXMLDumper().dumpModelAsXml(context, route);
+ log.info(xml);
+
+ assertTrue(xml.contains("<doCatch"), xml);
+ assertTrue(xml.contains("<doFinally"), xml);
+ assertTrue(xml.indexOf("mock:try") < xml.indexOf("mock:catch"), xml);
+ assertTrue(xml.indexOf("mock:catch") < xml.indexOf("mock:finally"),
xml);
+ assertEquals(xml.indexOf("mock:catch"), xml.lastIndexOf("mock:catch"),
xml);
+ }
+}
diff --git
a/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java
b/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java
index ca964c452a29..8ce8a9047761 100644
---
a/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java
+++
b/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java
@@ -20,7 +20,6 @@
*/
package org.apache.camel.java.out;
-import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.function.BiConsumer;
@@ -2707,23 +2706,7 @@ public class JavaDslModelWriter extends
JavaDslModelWriterSupport {
}
protected void doWriteTryDefinition(StringBuilder sb, TryDefinition def) {
doWriteProcessorDefinitionAttributes(sb, def);
- List<ProcessorDefinition<?>> outputs = new
ArrayList<>(def.getOutputs());
- for (CatchDefinition clause : def.getCatchClauses()) {
- if (!outputs.contains(clause)) {
- int index = outputs.size();
- for (int i = 0; i < outputs.size(); i++) {
- if (outputs.get(i) instanceof FinallyDefinition) {
- index = i;
- break;
- }
- }
- outputs.add(index, clause);
- }
- }
- if (def.getFinallyClause() != null &&
!outputs.contains(def.getFinallyClause())) {
- outputs.add(def.getFinallyClause());
- }
- doWriteOutputs(sb, outputs, this::doWriteProcessorDefinitionRef);
+ doWriteOutputs(sb, def.getOutputs(),
this::doWriteProcessorDefinitionRef);
}
protected void doWriteUnmarshalDefinition(StringBuilder sb,
UnmarshalDefinition def) {
doWriteProcessorDefinitionAttributes(sb, def);
diff --git
a/core/camel-java-io/src/test/java/org/apache/camel/java/out/TryModelWriterTest.java
b/core/camel-java-io/src/test/java/org/apache/camel/java/out/TryModelWriterTest.java
index aab120acefb9..28b0cabd5fdb 100644
---
a/core/camel-java-io/src/test/java/org/apache/camel/java/out/TryModelWriterTest.java
+++
b/core/camel-java-io/src/test/java/org/apache/camel/java/out/TryModelWriterTest.java
@@ -83,6 +83,26 @@ class TryModelWriterTest {
Assertions.assertEquals(originalOutputs, def.getOutputs());
}
+ @Test
+ void clausesSetBeforeTheStepsAreDumpedAfterThem() throws Exception {
+ // as the YAML DSL does when doCatch and doFinally are written above
steps (CAMEL-25410)
+ TryDefinition def = new TryDefinition();
+ CatchDefinition clause = new CatchDefinition();
+ clause.getExceptions().add("java.lang.Exception");
+ clause.addOutput(new ToDefinition("mock:catch"));
+ FinallyDefinition finallyClause = new FinallyDefinition();
+ finallyClause.addOutput(new ToDefinition("mock:finally"));
+ def.setCatchClauses(List.of(clause));
+ def.setFinallyClause(finallyClause);
+ def.addOutput(new ToDefinition("mock:try1"));
+ def.addOutput(new ToDefinition("mock:try2"));
+ String output = dump(def);
+ Assertions.assertTrue(output.indexOf("mock:try1") <
output.indexOf("mock:try2"), output);
+ Assertions.assertTrue(output.indexOf("mock:try2") <
output.indexOf("mock:catch"), output);
+ Assertions.assertTrue(output.indexOf("mock:catch") <
output.indexOf("mock:finally"), output);
+ Assertions.assertEquals(output.indexOf("mock:catch"),
output.lastIndexOf("mock:catch"), output);
+ }
+
@Test
void dumpingAfterAddingOutputPreservesNewStepAndMixedClauses() throws
Exception {
TryDefinition def = new TryDefinition();
@@ -102,7 +122,12 @@ class TryModelWriterTest {
Assertions.assertTrue(second.contains("mock:later"), second);
Assertions.assertEquals(second.indexOf("mock:catch"),
second.lastIndexOf("mock:catch"), second);
Assertions.assertEquals(second.indexOf("mock:finally"),
second.lastIndexOf("mock:finally"), second);
- Assertions.assertEquals(3, def.getOutputs().size());
+ // the doCatch set as a property is kept in the outputs too
(CAMEL-25410), and a step added later goes before
+ // the clauses: steps, doCatch, doFinally
+ Assertions.assertEquals(4, def.getOutputs().size());
+ Assertions.assertTrue(second.indexOf("mock:later") <
second.indexOf("mock:catch"), second);
+ Assertions.assertSame(clause, def.getOutputs().get(2));
+ Assertions.assertSame(finallyClause, def.getOutputs().get(3));
}
private String dump(TryDefinition def) throws Exception {
diff --git
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
index 4a1416e28d46..0eb472d59208 100644
---
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
+++
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
@@ -22,7 +22,6 @@ package org.apache.camel.xml.out;
import java.io.IOException;
import java.io.Writer;
-import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import javax.annotation.processing.Generated;
@@ -1983,23 +1982,7 @@ public class ModelWriter extends BaseWriter {
protected void doWriteTryDefinition(String name, TryDefinition def) throws
IOException {
startElement(name);
doWriteProcessorDefinitionAttributes(def);
- List<ProcessorDefinition<?>> outputs = new
ArrayList<>(def.getOutputs());
- for (CatchDefinition clause : def.getCatchClauses()) {
- if (!outputs.contains(clause)) {
- int index = outputs.size();
- for (int i = 0; i < outputs.size(); i++) {
- if (outputs.get(i) instanceof FinallyDefinition) {
- index = i;
- break;
- }
- }
- outputs.add(index, clause);
- }
- }
- if (def.getFinallyClause() != null &&
!outputs.contains(def.getFinallyClause())) {
- outputs.add(def.getFinallyClause());
- }
- doWriteList(null, null, outputs, this::doWriteProcessorDefinitionRef);
+ doWriteList(null, null, def.getOutputs(),
this::doWriteProcessorDefinitionRef);
endElement(name);
}
protected void doWriteUnmarshalDefinition(String name, UnmarshalDefinition
def) throws IOException {
diff --git
a/core/camel-xml-io/src/test/java/org/apache/camel/xml/out/TryModelWriterTest.java
b/core/camel-xml-io/src/test/java/org/apache/camel/xml/out/TryModelWriterTest.java
index e00df9728617..0390efbf069b 100644
---
a/core/camel-xml-io/src/test/java/org/apache/camel/xml/out/TryModelWriterTest.java
+++
b/core/camel-xml-io/src/test/java/org/apache/camel/xml/out/TryModelWriterTest.java
@@ -84,6 +84,26 @@ class TryModelWriterTest {
Assertions.assertEquals(originalOutputs, def.getOutputs());
}
+ @Test
+ void clausesSetBeforeTheStepsAreDumpedAfterThem() throws Exception {
+ // as the YAML DSL does when doCatch and doFinally are written above
steps (CAMEL-25410)
+ TryDefinition def = new TryDefinition();
+ CatchDefinition clause = new CatchDefinition();
+ clause.getExceptions().add("java.lang.Exception");
+ clause.addOutput(new ToDefinition("mock:catch"));
+ FinallyDefinition finallyClause = new FinallyDefinition();
+ finallyClause.addOutput(new ToDefinition("mock:finally"));
+ def.setCatchClauses(List.of(clause));
+ def.setFinallyClause(finallyClause);
+ def.addOutput(new ToDefinition("mock:try1"));
+ def.addOutput(new ToDefinition("mock:try2"));
+ String output = dump(def);
+ Assertions.assertTrue(output.indexOf("mock:try1") <
output.indexOf("mock:try2"), output);
+ Assertions.assertTrue(output.indexOf("mock:try2") <
output.indexOf("mock:catch"), output);
+ Assertions.assertTrue(output.indexOf("mock:catch") <
output.indexOf("mock:finally"), output);
+ Assertions.assertEquals(output.indexOf("mock:catch"),
output.lastIndexOf("mock:catch"), output);
+ }
+
@Test
void dumpingAfterAddingOutputPreservesNewStepAndMixedClauses() throws
Exception {
TryDefinition def = new TryDefinition();
@@ -103,7 +123,12 @@ class TryModelWriterTest {
Assertions.assertTrue(second.contains("mock:later"), second);
Assertions.assertEquals(second.indexOf("mock:catch"),
second.lastIndexOf("mock:catch"), second);
Assertions.assertEquals(second.indexOf("mock:finally"),
second.lastIndexOf("mock:finally"), second);
- Assertions.assertEquals(3, def.getOutputs().size());
+ // the doCatch set as a property is kept in the outputs too
(CAMEL-25410), and a step added later goes before
+ // the clauses: steps, doCatch, doFinally
+ Assertions.assertEquals(4, def.getOutputs().size());
+ Assertions.assertTrue(second.indexOf("mock:later") <
second.indexOf("mock:catch"), second);
+ Assertions.assertSame(clause, def.getOutputs().get(2));
+ Assertions.assertSame(finallyClause, def.getOutputs().get(3));
}
private String dump(TryDefinition def) throws Exception {
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 730eb07f5578..fab0593590ec 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
@@ -1982,23 +1982,7 @@ public class YamlModelWriter extends
YamlModelWriterSupport {
protected JsonObject doWriteTryDefinition(TryDefinition def) {
JsonObject jo = new JsonObject();
doWriteProcessorDefinitionAttributes(jo, def);
- List<ProcessorDefinition<?>> outputs = new
ArrayList<>(def.getOutputs());
- for (CatchDefinition clause : def.getCatchClauses()) {
- if (!outputs.contains(clause)) {
- int index = outputs.size();
- for (int i = 0; i < outputs.size(); i++) {
- if (outputs.get(i) instanceof FinallyDefinition) {
- index = i;
- break;
- }
- }
- outputs.add(index, clause);
- }
- }
- if (def.getFinallyClause() != null &&
!outputs.contains(def.getFinallyClause())) {
- outputs.add(def.getFinallyClause());
- }
- doWriteOutputs(jo, outputs, this::doWriteProcessorDefinitionRef);
+ doWriteOutputs(jo, def.getOutputs(),
this::doWriteProcessorDefinitionRef);
return jo;
}
protected JsonObject doWriteUnmarshalDefinition(UnmarshalDefinition def) {
diff --git
a/core/camel-yaml-io/src/test/java/org/apache/camel/yaml/out/TryModelWriterTest.java
b/core/camel-yaml-io/src/test/java/org/apache/camel/yaml/out/TryModelWriterTest.java
index dff4a6e3ad73..cb1b710d44c8 100644
---
a/core/camel-yaml-io/src/test/java/org/apache/camel/yaml/out/TryModelWriterTest.java
+++
b/core/camel-yaml-io/src/test/java/org/apache/camel/yaml/out/TryModelWriterTest.java
@@ -83,6 +83,26 @@ class TryModelWriterTest {
Assertions.assertEquals(originalOutputs, def.getOutputs());
}
+ @Test
+ void clausesSetBeforeTheStepsAreDumpedAfterThem() throws Exception {
+ // as the YAML DSL does when doCatch and doFinally are written above
steps (CAMEL-25410)
+ TryDefinition def = new TryDefinition();
+ CatchDefinition clause = new CatchDefinition();
+ clause.getExceptions().add("java.lang.Exception");
+ clause.addOutput(new ToDefinition("mock:catch"));
+ FinallyDefinition finallyClause = new FinallyDefinition();
+ finallyClause.addOutput(new ToDefinition("mock:finally"));
+ def.setCatchClauses(List.of(clause));
+ def.setFinallyClause(finallyClause);
+ def.addOutput(new ToDefinition("mock:try1"));
+ def.addOutput(new ToDefinition("mock:try2"));
+ String output = dump(def);
+ Assertions.assertTrue(output.indexOf("mock:try1") <
output.indexOf("mock:try2"), output);
+ Assertions.assertTrue(output.indexOf("mock:try2") <
output.indexOf("mock:catch"), output);
+ Assertions.assertTrue(output.indexOf("mock:catch") <
output.indexOf("mock:finally"), output);
+ Assertions.assertEquals(output.indexOf("mock:catch"),
output.lastIndexOf("mock:catch"), output);
+ }
+
@Test
void dumpingAfterAddingOutputPreservesNewStepAndMixedClauses() throws
Exception {
TryDefinition def = new TryDefinition();
@@ -102,7 +122,12 @@ class TryModelWriterTest {
Assertions.assertTrue(second.contains("mock:later"), second);
Assertions.assertEquals(second.indexOf("mock:catch"),
second.lastIndexOf("mock:catch"), second);
Assertions.assertEquals(second.indexOf("mock:finally"),
second.lastIndexOf("mock:finally"), second);
- Assertions.assertEquals(3, def.getOutputs().size());
+ // the doCatch set as a property is kept in the outputs too
(CAMEL-25410), and a step added later goes before
+ // the clauses: steps, doCatch, doFinally
+ Assertions.assertEquals(4, def.getOutputs().size());
+ Assertions.assertTrue(second.indexOf("mock:later") <
second.indexOf("mock:catch"), second);
+ Assertions.assertSame(clause, def.getOutputs().get(2));
+ Assertions.assertSame(finallyClause, def.getOutputs().get(3));
}
private String dump(TryDefinition def) throws Exception {
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index a6da958315b9..f73b33ada254 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -36,6 +36,15 @@ Starting in 4.24:
* The Cache EIP stores keys directly without a namespace prefix, preserving
documented cache invalidation recipes (`cache.delete(key)` and
`cache.clear()`). Note that because cache keys are un-prefixed, calling
`clear()` on a `KeyValueRepository` shared with the Cache EIP will clear all
entries in that repository, including state-store entries. It is recommended to
use a dedicated repository for the Cache EIP when co-located with state-store.
* `KeyValueAggregationRepository` safely verifies entry types before
unmarshalling, ignoring unexpected types gracefully instead of failing with a
class cast exception.
+=== camel-core-model - doTry keeps doCatch and doFinally in its outputs
+
+`doCatch` and `doFinally` written as properties of `doTry` in the YAML DSL are
now kept in the outputs of the
+`TryDefinition`, as the clauses of the Java and XML DSLs always were, after
the steps whatever the order of the YAML
+keys. Code that walks `getOutputs()` (route dumps, tooling) now sees them, and
`getCatchClauses()`,
+`getFinallyClause()` and `getOutputsWithoutCatches()` are derived from the
outputs on each call: a clause removed from
+the outputs, for example with advice-with, is no longer used, and changing the
list returned by `getCatchClauses()`
+no longer changes the doTry. Use `setCatchClauses` and `setFinallyClause`, or
the outputs, instead.
+
=== camel-ehcache - shared CacheManager and changed defaults
The following user-visible changes take effect in 4.24:
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/java/org/apache/camel/dsl/yaml/TryPropertyClausesTest.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/java/org/apache/camel/dsl/yaml/TryPropertyClausesTest.java
new file mode 100644
index 000000000000..e9d9896d0986
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/java/org/apache/camel/dsl/yaml/TryPropertyClausesTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.dsl.yaml.support.YamlTestSupport;
+import org.apache.camel.model.CatchDefinition;
+import org.apache.camel.model.FinallyDefinition;
+import org.apache.camel.model.ToDefinition;
+import org.apache.camel.model.TryDefinition;
+import org.apache.camel.yaml.LwModelToYAMLDumper;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * doCatch and doFinally written as properties of doTry are kept in its
outputs, after the steps whatever the YAML key
+ * order (CAMEL-25410).
+ */
+class TryPropertyClausesTest extends YamlTestSupport {
+
+ private static final String CLAUSES_ABOVE_STEPS = """
+ - route:
+ id: clauses
+ from:
+ uri: direct:start
+ steps:
+ - doTry:
+ doCatch:
+ - exception:
+ - java.lang.IllegalStateException
+ steps:
+ - to: mock:catch
+ doFinally:
+ steps:
+ - to: mock:finally
+ steps:
+ - to: mock:try
+ - throwException:
+ exceptionType: java.lang.IllegalStateException
+ message: Forced
+ """;
+
+ @Test
+ void clausesAboveStepsAreAfterTheStepsInTheOutputs() throws Exception {
+ loadRoutes(CLAUSES_ABOVE_STEPS);
+
+ TryDefinition doTry = (TryDefinition)
context.getRouteDefinition("clauses").getOutputs().get(0);
+ assertThat(doTry.getOutputs()).hasSize(4);
+ assertThat(doTry.getOutputs().get(0)).isInstanceOf(ToDefinition.class);
+
assertThat(doTry.getOutputs().get(2)).isInstanceOf(CatchDefinition.class);
+
assertThat(doTry.getOutputs().get(3)).isInstanceOf(FinallyDefinition.class);
+ assertThat(doTry.getCatchClauses()).containsExactly((CatchDefinition)
doTry.getOutputs().get(2));
+
assertThat(doTry.getFinallyClause()).isSameAs(doTry.getOutputs().get(3));
+
+ assertRuns();
+ }
+
+ @Test
+ void clausesAboveStepsSurviveDumpAndReload() throws Exception {
+ loadRoutes(CLAUSES_ABOVE_STEPS);
+ var route = context.getRouteDefinition("clauses");
+ String yaml = new LwModelToYAMLDumper().dumpModelAsYaml(context,
route);
+ assertThat(yaml).contains("doCatch:", "doFinally:");
+
assertThat(yaml.indexOf("mock:try")).isLessThan(yaml.indexOf("mock:catch"));
+
assertThat(yaml.indexOf("mock:catch")).isLessThan(yaml.indexOf("mock:finally"));
+
+ context.removeRouteDefinition(route);
+ loadRoutes(yaml);
+
+ assertRuns();
+ }
+
+ @Test
+ void templatedRoutesRunEachClauseOnce() throws Exception {
+ loadRoutes("""
+ - routeTemplate:
+ id: myTemplate
+ from:
+ uri: "direct:{{name}}"
+ steps:
+ - doTry:
+ steps:
+ - throwException:
+ exceptionType:
java.lang.IllegalStateException
+ message: Forced
+ doCatch:
+ - exception:
+ - java.lang.IllegalStateException
+ steps:
+ - to: "mock:catch-{{name}}"
+ doFinally:
+ steps:
+ - to: "mock:finally-{{name}}"
+ - templatedRoute:
+ routeId: one
+ routeTemplateRef: myTemplate
+ parameters:
+ - name: name
+ value: one
+ - templatedRoute:
+ routeId: two
+ routeTemplateRef: myTemplate
+ parameters:
+ - name: name
+ value: two
+ """);
+
+ for (String name : new String[] { "one", "two" }) {
+ withMock("mock:catch-" + name, mock ->
mock.expectedMessageCount(1));
+ withMock("mock:finally-" + name, mock ->
mock.expectedMessageCount(1));
+ }
+ context.start();
+
+ withTemplate(t -> t.to("direct:one").withBody("Hello").send());
+ withTemplate(t -> t.to("direct:two").withBody("World").send());
+
+ MockEndpoint.assertIsSatisfied(context);
+ TryDefinition doTry = (TryDefinition)
context.getRouteDefinition("one").getOutputs().get(0);
+ assertThat(doTry.getCatchClauses()).hasSize(1);
+ }
+
+ private void assertRuns() throws Exception {
+ withMock("mock:try", mock -> mock.expectedMessageCount(1));
+ withMock("mock:catch", mock -> mock.expectedMessageCount(1));
+ withMock("mock:finally", mock -> mock.expectedMessageCount(1));
+ context.start();
+ withTemplate(t -> t.to("direct:start").withBody("Hello").send());
+ MockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS);
+ }
+}
diff --git
a/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-java-dsl-writer.vm
b/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-java-dsl-writer.vm
index ce06ff42ae16..12dc6184d1c6 100644
---
a/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-java-dsl-writer.vm
+++
b/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-java-dsl-writer.vm
@@ -37,7 +37,6 @@
*/
package ${package};
-import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.function.BiConsumer;
@@ -151,27 +150,7 @@ public class JavaDslModelWriter extends
JavaDslModelWriterSupport {
#set( $foo = $elementRefs.add($root) )
#if( $list )
#if( $member.name == "outputs" )
- #if( $clazz.simpleName == "TryDefinition" )
- List<ProcessorDefinition<?>> outputs = new
ArrayList<>(def.getOutputs());
- for (CatchDefinition clause : def.getCatchClauses()) {
- if (!outputs.contains(clause)) {
- int index = outputs.size();
- for (int i = 0; i < outputs.size(); i++) {
- if (outputs.get(i) instanceof FinallyDefinition) {
- index = i;
- break;
- }
- }
- outputs.add(index, clause);
- }
- }
- if (def.getFinallyClause() != null &&
!outputs.contains(def.getFinallyClause())) {
- outputs.add(def.getFinallyClause());
- }
- doWriteOutputs(sb, outputs, this::doWrite${root.simpleName}Ref);
- #else
doWriteOutputs(sb, def.${member.getter}(),
this::doWrite${root.simpleName}Ref);
- #end
#else
#set( $refName = $member.xmlElementRef.name() )
#if( $refName && $refName != $default &&
$refName != "" )
diff --git
a/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-writer.vm
b/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-writer.vm
index 8fb03247d608..4b15a7fce29a 100644
---
a/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-writer.vm
+++
b/tooling/maven/camel-package-maven-plugin/src/main/resources/velocity/model-writer.vm
@@ -39,7 +39,6 @@ package ${package};
import java.io.IOException;
import java.io.Writer;
-import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import javax.annotation.processing.Generated;
@@ -145,27 +144,7 @@ public class ModelWriter extends BaseWriter {
#elseif( $member.xmlElementRef )
#set( $foo = $elementRefs.add($root) )
#if( $list )
- #if( $clazz.simpleName == "TryDefinition" &&
$member.name == "outputs" )
- List<ProcessorDefinition<?>> outputs = new
ArrayList<>(def.getOutputs());
- for (CatchDefinition clause : def.getCatchClauses()) {
- if (!outputs.contains(clause)) {
- int index = outputs.size();
- for (int i = 0; i < outputs.size(); i++) {
- if (outputs.get(i) instanceof FinallyDefinition) {
- index = i;
- break;
- }
- }
- outputs.add(index, clause);
- }
- }
- if (def.getFinallyClause() != null &&
!outputs.contains(def.getFinallyClause())) {
- outputs.add(def.getFinallyClause());
- }
- doWriteList(null, null, outputs, this::doWrite${root.simpleName}Ref);
- #else
doWriteList(null, null, def.${member.getter}(),
this::doWrite${root.simpleName}Ref);
- #end
#else
doWriteElement(null, def.${member.getter}(),
this::doWrite${root.simpleName}Ref);
#end
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 8f294d11b62f..127b2be78341 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
@@ -148,27 +148,7 @@ public class YamlModelWriter extends
YamlModelWriterSupport {
#if( $list )
#set( $yamlKey =
$yamlKeys.get("${clazz.simpleName}.${member.name}") )
#if( $member.name == "outputs" )
- #if( $clazz.simpleName == "TryDefinition" )
- List<ProcessorDefinition<?>> outputs = new
ArrayList<>(def.getOutputs());
- for (CatchDefinition clause : def.getCatchClauses()) {
- if (!outputs.contains(clause)) {
- int index = outputs.size();
- for (int i = 0; i < outputs.size(); i++) {
- if (outputs.get(i) instanceof FinallyDefinition) {
- index = i;
- break;
- }
- }
- outputs.add(index, clause);
- }
- }
- if (def.getFinallyClause() != null &&
!outputs.contains(def.getFinallyClause())) {
- outputs.add(def.getFinallyClause());
- }
- doWriteOutputs(jo, outputs, this::doWrite${root.simpleName}Ref);
- #else
doWriteOutputs(jo, def.${member.getter}(),
this::doWrite${root.simpleName}Ref);
- #end
#elseif( $clazz.simpleName == "RestDefinition" &&
$member.name == "verbs" )
doWriteVerbs(jo, def.${member.getter}(),
this::doWrite${root.simpleName});
#elseif( $yamlKey )