This is an automated email from the ASF dual-hosted git repository. luigidemasi pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 8006b8b3a265a7db1b530c99b4ce0a03c4dbdbb4 Author: Luigi De Masi <[email protected]> AuthorDate: Wed Sep 30 12:56:25 2026 +0200 CAMEL-24988: Restore explicit Switch destination preparation Keep the model getters side-effect-free and prepare endpoint nodes during reification. Restore regression coverage for stable prepared nodes and independent copies. Co-authored-by: Codex <[email protected]> Signed-off-by: Luigi De Masi <[email protected]> --- .../apache/camel/model/SwitchCaseDefinition.java | 9 ++- .../org/apache/camel/model/SwitchDefinition.java | 32 +++++++---- .../camel/model/SwitchOtherwiseDefinition.java | 22 ++++++- .../apache/camel/model/SwitchDefinitionTest.java | 67 ++++++++++++++++++++++ .../org/apache/camel/reifier/SwitchReifier.java | 2 + 5 files changed, 119 insertions(+), 13 deletions(-) diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchCaseDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchCaseDefinition.java index f875ec051401..fbbabe0c9845 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchCaseDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchCaseDefinition.java @@ -78,9 +78,15 @@ public class SwitchCaseDefinition extends OptionalIdentifiedDefinition<SwitchCas /** The destination node shared by reification and management instrumentation. */ @XmlTransient public ToDefinition getToDefinition() { + return toDefinition; + } + + /** Prepare the destination node before processor creation and management instrumentation. */ + public void prepareToDefinition() { if (toDefinition == null) { - toDefinition = new ToDefinition(uri); + toDefinition = new ToDefinition(); } + toDefinition.setUri(uri); toDefinition.setParent(parent); if (hasCustomIdAssigned()) { toDefinition.setId(getId()); @@ -91,7 +97,6 @@ public class SwitchCaseDefinition extends OptionalIdentifiedDefinition<SwitchCas toDefinition.setNote(getNote()); toDefinition.setLocation(getLocation()); toDefinition.setLineNumber(getLineNumber()); - return toDefinition; } @Override diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchDefinition.java index 61b56043cd93..944d6e059e50 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchDefinition.java @@ -49,8 +49,6 @@ public class SwitchDefinition extends NoOutputDefinition<SwitchDefinition> { @XmlElement @Metadata(description = "Fixed fallback URI for null or unmatched selector results. Without a fallback processing continues.") private SwitchOtherwiseDefinition otherwise; - @XmlTransient - private ToDefinition otherwiseDefinition; public SwitchDefinition() { } @@ -62,7 +60,7 @@ public class SwitchDefinition extends NoOutputDefinition<SwitchDefinition> { protected SwitchDefinition(SwitchDefinition source) { super(source); this.selector = source.selector != null ? source.selector.copyDefinition() : null; - this.otherwise = source.otherwise != null ? source.otherwise.copyDefinition() : null; + setOtherwise(source.otherwise != null ? source.otherwise.copyDefinition() : null); for (SwitchCaseDefinition c : source.cases) { SwitchCaseDefinition copy = c.copyDefinition(); copy.setParent(this); @@ -106,19 +104,34 @@ public class SwitchDefinition extends NoOutputDefinition<SwitchDefinition> { public void setOtherwise(SwitchOtherwiseDefinition otherwise) { this.otherwise = otherwise; - this.otherwiseDefinition = null; + prepareOtherwiseDefinition(); + } + + @Override + public void setId(String id) { + super.setId(id); + prepareOtherwiseDefinition(); + } + + @Override + public void setGeneratedId(String id) { + super.setGeneratedId(id); + prepareOtherwiseDefinition(); } /** The fallback send node, used by route traversal and processor creation. */ @XmlTransient public ToDefinition getOtherwiseDefinition() { - if (otherwise == null) { - return null; - } + return otherwise != null ? otherwise.getToDefinition() : null; + } + + /** Prepare the fallback node before processor creation and management instrumentation. */ + public void prepareOtherwiseDefinition() { + ToDefinition otherwiseDefinition = getOtherwiseDefinition(); if (otherwiseDefinition == null) { - otherwiseDefinition = new ToDefinition(); - otherwiseDefinition.setParent(this); + return; } + otherwiseDefinition.setParent(this); otherwiseDefinition.setUri(otherwise.getUri()); if (getId() != null) { if (hasCustomIdAssigned()) { @@ -127,7 +140,6 @@ public class SwitchDefinition extends NoOutputDefinition<SwitchDefinition> { otherwiseDefinition.setGeneratedId(getId() + "-otherwise"); } } - return otherwiseDefinition; } /** Add a scalar literal and its destination. */ diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchOtherwiseDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchOtherwiseDefinition.java index 0c5e79d282bd..d5cd511b2089 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchOtherwiseDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchOtherwiseDefinition.java @@ -16,10 +16,12 @@ */ package org.apache.camel.model; +import jakarta.xml.bind.Unmarshaller; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAttribute; import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlTransient; import org.apache.camel.spi.Metadata; @@ -31,10 +33,12 @@ public class SwitchOtherwiseDefinition implements EndpointRequiredDefinition { @XmlAttribute(required = true) @Metadata(description = "The fixed destination URI. Supports property placeholders, but not Simple expressions.") private String uri; + @XmlTransient + private final ToDefinition toDefinition = new ToDefinition(); public SwitchOtherwiseDefinition copyDefinition() { SwitchOtherwiseDefinition copy = new SwitchOtherwiseDefinition(); - copy.uri = uri; + copy.setUri(uri); return copy; } @@ -44,9 +48,25 @@ public class SwitchOtherwiseDefinition implements EndpointRequiredDefinition { public void setUri(String uri) { this.uri = uri; + toDefinition.setUri(uri); + } + + /** The destination node, available for endpoint discovery before route startup. */ + @XmlTransient + public ToDefinition getToDefinition() { + return toDefinition; + } + + // JAXB populates fields directly, so initialize the traversal node after loading. + private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) { + toDefinition.setUri(uri); + if (parent instanceof SwitchDefinition sw) { + sw.setOtherwise(this); + } } @Override + @XmlTransient public String getEndpointUri() { return uri; } diff --git a/core/camel-core-model/src/test/java/org/apache/camel/model/SwitchDefinitionTest.java b/core/camel-core-model/src/test/java/org/apache/camel/model/SwitchDefinitionTest.java new file mode 100644 index 000000000000..715e1a31075d --- /dev/null +++ b/core/camel-core-model/src/test/java/org/apache/camel/model/SwitchDefinitionTest.java @@ -0,0 +1,67 @@ +/* + * 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 org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +class SwitchDefinitionTest { + @Test + void readingDestinationsDoesNotOverwritePreparedNodes() { + SwitchDefinition sw = new SwitchDefinition().id("dispatch") + .doCase("billing", "{{case.uri}}").otherwise("{{fallback.uri}}"); + SwitchCaseDefinition c = sw.getCases().get(0); + c.setId("billing"); + assertNull(c.getToDefinition()); + sw.getChildren(); + assertNull(c.getToDefinition()); + + c.prepareToDefinition(); + sw.prepareOtherwiseDefinition(); + ToDefinition caseSend = c.getToDefinition(); + ToDefinition fallbackSend = sw.getOtherwiseDefinition(); + caseSend.setUri("mock:billing"); + caseSend.setId("prepared-billing"); + fallbackSend.setUri("mock:review"); + fallbackSend.setId("prepared-fallback"); + + assertSame(caseSend, c.getToDefinition()); + assertSame(fallbackSend, sw.getOtherwiseDefinition()); + assertSame(fallbackSend, sw.getChildren().get(1)); + assertEquals("mock:billing", caseSend.getUri()); + assertEquals("prepared-billing", caseSend.getId()); + assertEquals("mock:review", fallbackSend.getUri()); + assertEquals("prepared-fallback", fallbackSend.getId()); + } + + @Test + void copiedFallbackHasIndependentDestinationAndParent() { + SwitchDefinition original = new SwitchDefinition().otherwise("mock:original"); + SwitchDefinition copy = original.copyDefinition(); + copy.getOtherwise().setUri("mock:copy"); + + assertNotSame(original.getOtherwiseDefinition(), copy.getOtherwiseDefinition()); + assertSame(original, original.getOtherwiseDefinition().getParent()); + assertSame(copy, copy.getOtherwiseDefinition().getParent()); + assertEquals("mock:original", original.getOtherwiseDefinition().getUri()); + assertEquals("mock:copy", copy.getOtherwiseDefinition().getUri()); + } +} diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SwitchReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SwitchReifier.java index d5d1caef8d0f..77adf6751f4c 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SwitchReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SwitchReifier.java @@ -67,6 +67,7 @@ public class SwitchReifier extends ProcessorReifier<SwitchDefinition> { c.setParent(definition); c.setCamelContext(camelContext); c.idOrCreate(ids); + c.prepareToDefinition(); ToDefinition send = c.getToDefinition(); send.setUri(uris.get(i)); cases.put(caseKeys.get(i), createSend(send)); @@ -74,6 +75,7 @@ public class SwitchReifier extends ProcessorReifier<SwitchDefinition> { Processor otherwise = null; if (otherwiseUri != null) { definition.idOrCreate(ids); + definition.prepareOtherwiseDefinition(); ToDefinition send = definition.getOtherwiseDefinition(); send.setUri(otherwiseUri); otherwise = createSend(send);
