This is an automated email from the ASF dual-hosted git repository.
Croway pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-upgrade-recipes.git
The following commit(s) were added to refs/heads/main by this push:
new e23bbde Gate the remaining XML DSL recipes on a Camel document (#127)
e23bbde is described below
commit e23bbded8ca17e2480ef9daa6d26f9cc9a1cf944
Author: Federico Mariani <[email protected]>
AuthorDate: Tue Aug 25 15:11:33 2026 +0200
Gate the remaining XML DSL recipes on a Camel document (#127)
* Gate the remaining XML DSL recipes on a Camel document
Fixes #126.
The Java recipes are gated by UsesType and the YAML recipes by
camelYamlDslPrecondition, and #125 added camelXmlDslPrecondition and
applied it to two XML recipes. The other ten visited every XML document
in a project, so a matcher that happens to fit an unrelated file rewrote
it. XmlDsl418_1SagaRecipe did not merely rename in such a file, it
removed a child element and folded it into an attribute.
Wraps every remaining XML visitor in the precondition, so the whole set
is now uniform and a new XML recipe inherits the same guard.
CameXmlDslRecipeTest.circuitBreakerFull used a synthetic <differentContext>
root, which is not a Camel document. Its sibling circuitBreaker test
already covers the <route> context, so the root becomes <camelContext>,
which is where a top level resilience4jConfiguration actually lives, and
the option coverage the test exists for is unchanged.
Adds CamelXmlDslPreconditionTest, one negative test per gated recipe,
each feeding a document carrying exactly the shape that recipe matches
under a plainly non-Camel root. Kept in one class rather than spread over
the existing test classes because the property is uniform across the
recipes, so a new XML recipe is one line away from being covered.
Verified the tests are not vacuous: with the gating reverted, 8 of the 10
fail, the other 2 being the recipes already gated by #125.
camel40.xml.XmlDslRecipe has no negative test on purpose, its matchers
are anchored at /routes/route so the document root has to be routes,
which is a Camel root.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
* Address review: accept Spring layouts, gate the last recipes
* Accept a Camel document wherever the Camel marker sits. isCamelXmlDsl
rejected any root declaring the Spring beans namespace before looking
further, so the classic <beans><camelContext xmlns="...camel..."> layout
was skipped by every gated recipe, silently under-migrating it. A Camel
namespace or a camelContext/routeContext element is now conclusive at
any depth, and the Spring namespace only rules a document out when no
Camel marker is present.
* Add the missing roots. <camel> is the most common root in Camel's own
XML test resources, and routeConfigurations, routeTemplates and
templatedRoutes are the plural wrappers. Namespace-less files with
those roots were excluded.
* Gate camel43.CamelResequenceEIPXmlRecipe, which was missed because it
extends XmlIsoVisitor directly rather than AbstractCamelXmlVisitor.
* Add FindCamelXmlDsl, a search recipe form of the precondition, and use
it from the declarative XML recipes in 4.12.yaml and 4.13.yaml, which
ran org.openrewrite.xml.ChangeTagName against any document. furyDsl is
split so that gating the XML half does not gate the Java DSL change.
* Only convert Camel beans in XmlDsl46Recipe. Accepting <camel> roots
makes files such as camel-kamelet-main's spring-camel1.xml eligible,
and those carry Spring bean definitions next to the routes. A Spring
bean declares its class with class= where a Camel bean uses type=, so
rewriting <property> into <properties> there would have broken them.
Found by testing the widened precondition rather than by review.
Adds positive tests for the Spring layout, the <camel> root and a plural
wrapper root, so the gate cannot silently narrow again.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
.../java/org/apache/camel/upgrade/RecipesUtil.java | 34 +-
.../camel40/xml/CircuitBreakerXmlDslRecipe.java | 6 +-
.../camel/upgrade/camel40/xml/XmlDslRecipe.java | 6 +-
.../apache/camel/upgrade/camel41/XmlDslRecipe.java | 6 +-
.../camel/upgrade/camel410/XmlDsl410Recipe.java | 6 +-
.../upgrade/camel418_1/XmlDsl418_1SagaRecipe.java | 6 +-
.../camel418_3/RenameHeaderPrefixInXmlDsl.java | 5 +-
.../camel43/CamelResequenceEIPXmlRecipe.java | 6 +-
.../camel/upgrade/camel46/XmlDsl46Recipe.java | 16 +-
.../camel/upgrade/camel47/XmlDsl47Recipe.java | 6 +-
.../upgrade/customRecipes/FindCamelXmlDsl.java | 47 +++
.../ReplacePropertyInComponentXml.java | 5 +-
.../ReplacePropertyInDataFormatXml.java | 6 +-
.../internal/ChangeXmlComponentUriRecipe.java | 5 +-
.../src/main/resources/META-INF/rewrite/4.12.yaml | 2 +
.../src/main/resources/META-INF/rewrite/4.13.yaml | 17 +-
.../upgrade/camel40/CameXmlDslRecipeTest.java | 8 +-
.../upgrade/xml/CamelXmlDslPreconditionTest.java | 361 +++++++++++++++++++++
18 files changed, 509 insertions(+), 39 deletions(-)
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/RecipesUtil.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/RecipesUtil.java
index e6b769b..56d0df1 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/RecipesUtil.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/RecipesUtil.java
@@ -87,8 +87,17 @@ public class RecipesUtil {
// ---------------- Camel XML DSL precondition
private static final Set<String> CAMEL_XML_DSL_ROOT_TAGS = Set.of(
- "routes", "route", "routeConfiguration", "routeTemplate",
"templatedRoute",
- "rests", "rest", "restConfiguration", "camelContext",
"routeContext", "bean", "beans");
+ "camel", "routes", "route",
+ "routeConfigurations", "routeConfiguration",
+ "routeTemplates", "routeTemplate",
+ "templatedRoutes", "templatedRoute",
+ "rests", "rest", "restConfiguration",
+ "camelContext", "routeContext", "bean", "beans");
+
+ // Elements that only ever appear in a Camel document, wherever they
happen to be nested
+ private static final Set<String> CAMEL_CONTEXT_TAGS =
Set.of("camelContext", "routeContext");
+
+ private static final String CAMEL_NAMESPACE = "camel.apache.org";
private static final String SPRING_BEANS_NAMESPACE =
"springframework.org/schema/beans";
@@ -113,18 +122,23 @@ public class RecipesUtil {
return false;
}
- // <bean> and <beans> are shared with Spring, whose namespace rules
the document out
- if (declaresNamespace(root, SPRING_BEANS_NAMESPACE)) {
- return false;
+ // A Camel namespace or a Camel context element is conclusive wherever
it sits in the document.
+ // This is what makes the classic Spring and Blueprint layouts work,
where a <camelContext> is
+ // nested in a <beans> or <blueprint> root that carries a foreign
namespace.
+ if (hasCamelMarker(root)) {
+ return true;
}
- // A Camel namespace is conclusive, whatever the root element is
- if (declaresNamespace(root, "camel.apache.org")) {
+ // Otherwise fall back on the root element. Camel XML is frequently
written without any
+ // namespace, but <bean> and <beans> are shared with Spring, whose
namespace rules them out.
+ return !declaresNamespace(root, SPRING_BEANS_NAMESPACE) &&
CAMEL_XML_DSL_ROOT_TAGS.contains(root.getName());
+ }
+
+ private static boolean hasCamelMarker(Xml.Tag tag) {
+ if (declaresNamespace(tag, CAMEL_NAMESPACE) ||
CAMEL_CONTEXT_TAGS.contains(tag.getName())) {
return true;
}
-
- // Camel XML DSL files are commonly written without any namespace, so
fall back on the root element
- return CAMEL_XML_DSL_ROOT_TAGS.contains(root.getName());
+ return
tag.getChildren().stream().anyMatch(RecipesUtil::hasCamelMarker);
}
private static boolean declaresNamespace(Xml.Tag root, String
namespaceFragment) {
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel40/xml/CircuitBreakerXmlDslRecipe.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel40/xml/CircuitBreakerXmlDslRecipe.java
index 2fdabbf..67a71f4 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel40/xml/CircuitBreakerXmlDslRecipe.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel40/xml/CircuitBreakerXmlDslRecipe.java
@@ -16,8 +16,10 @@
*/
package org.apache.camel.upgrade.camel40.xml;
+import org.apache.camel.upgrade.RecipesUtil;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
import org.jspecify.annotations.Nullable;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.Tree;
@@ -101,7 +103,7 @@ public class CircuitBreakerXmlDslRecipe extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new AbstractCamelXmlVisitor() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
AbstractCamelXmlVisitor() {
@Override
public Xml.@Nullable Tag doVisitTag(final Xml.Tag tag, final
ExecutionContext ctx) {
@@ -142,6 +144,6 @@ public class CircuitBreakerXmlDslRecipe extends Recipe {
return t;
}
- };
+ });
}
}
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel40/xml/XmlDslRecipe.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel40/xml/XmlDslRecipe.java
index 5d47bae..80e5a1e 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel40/xml/XmlDslRecipe.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel40/xml/XmlDslRecipe.java
@@ -16,8 +16,10 @@
*/
package org.apache.camel.upgrade.camel40.xml;
+import org.apache.camel.upgrade.RecipesUtil;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
import org.jspecify.annotations.Nullable;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.Tree;
@@ -69,7 +71,7 @@ public class XmlDslRecipe extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new AbstractCamelXmlVisitor() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
AbstractCamelXmlVisitor() {
@Override
public Xml.@Nullable Tag doVisitTag(final Xml.Tag tag, final
ExecutionContext ctx) {
@@ -100,6 +102,6 @@ public class XmlDslRecipe extends Recipe {
return t;
}
- };
+ });
}
}
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel41/XmlDslRecipe.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel41/XmlDslRecipe.java
index 0bfa9c1..1b32245 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel41/XmlDslRecipe.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel41/XmlDslRecipe.java
@@ -16,7 +16,9 @@
*/
package org.apache.camel.upgrade.camel41;
+import org.apache.camel.upgrade.RecipesUtil;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.Tree;
@@ -70,7 +72,7 @@ public class XmlDslRecipe extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new AbstractCamelXmlVisitor() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
AbstractCamelXmlVisitor() {
@Override
public Xml.Tag doVisitTag(final Xml.Tag tag, final
ExecutionContext ctx) {
@@ -106,6 +108,6 @@ public class XmlDslRecipe extends Recipe {
return t;
}
- };
+ });
}
}
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel410/XmlDsl410Recipe.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel410/XmlDsl410Recipe.java
index 49f13ca..8c2f3f2 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel410/XmlDsl410Recipe.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel410/XmlDsl410Recipe.java
@@ -16,7 +16,9 @@
*/
package org.apache.camel.upgrade.camel410;
+import org.apache.camel.upgrade.RecipesUtil;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
@@ -50,7 +52,7 @@ public class XmlDsl410Recipe extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new AbstractCamelXmlVisitor() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
AbstractCamelXmlVisitor() {
@Override
public Xml.Tag doVisitTag(final Xml.Tag tag, final
ExecutionContext ctx) {
@@ -64,6 +66,6 @@ public class XmlDsl410Recipe extends Recipe {
.findAny()
.orElse(t);
}
- };
+ });
}
}
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_1/XmlDsl418_1SagaRecipe.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_1/XmlDsl418_1SagaRecipe.java
index 34ed9d8..070b11a 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_1/XmlDsl418_1SagaRecipe.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_1/XmlDsl418_1SagaRecipe.java
@@ -16,7 +16,9 @@
*/
package org.apache.camel.upgrade.camel418_1;
+import org.apache.camel.upgrade.RecipesUtil;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
@@ -49,7 +51,7 @@ public class XmlDsl418_1SagaRecipe extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new AbstractCamelXmlVisitor() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
AbstractCamelXmlVisitor() {
@Override
public Xml.Tag doVisitTag(final Xml.Tag tag, final
ExecutionContext ctx) {
@@ -111,6 +113,6 @@ public class XmlDsl418_1SagaRecipe extends Recipe {
)
)));
}
- };
+ });
}
}
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderPrefixInXmlDsl.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderPrefixInXmlDsl.java
index ee54903..f5ce0e8 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderPrefixInXmlDsl.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderPrefixInXmlDsl.java
@@ -16,7 +16,9 @@
*/
package org.apache.camel.upgrade.camel418_3;
+import org.apache.camel.upgrade.RecipesUtil;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
@@ -69,7 +71,8 @@ public class RenameHeaderPrefixInXmlDsl extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new XmlHeaderPrefixVisitor(oldPrefix, newPrefix);
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(),
+ new XmlHeaderPrefixVisitor(oldPrefix,
newPrefix));
}
private static class XmlHeaderPrefixVisitor extends
AbstractCamelXmlVisitor {
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel43/CamelResequenceEIPXmlRecipe.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel43/CamelResequenceEIPXmlRecipe.java
index 44a7663..4a6f167 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel43/CamelResequenceEIPXmlRecipe.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel43/CamelResequenceEIPXmlRecipe.java
@@ -16,7 +16,9 @@
*/
package org.apache.camel.upgrade.camel43;
+import org.apache.camel.upgrade.RecipesUtil;
import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.xml.XPathMatcher;
@@ -75,7 +77,7 @@ public class CamelResequenceEIPXmlRecipe extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new XmlIsoVisitor<>() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
XmlIsoVisitor<ExecutionContext>() {
@Override
public Xml.Tag visitTag(final Xml.Tag tag, final ExecutionContext
ctx) {
@@ -89,6 +91,6 @@ public class CamelResequenceEIPXmlRecipe extends Recipe {
return t;
}
- };
+ });
}
}
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel46/XmlDsl46Recipe.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel46/XmlDsl46Recipe.java
index 4040fa9..408e72f 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel46/XmlDsl46Recipe.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel46/XmlDsl46Recipe.java
@@ -19,6 +19,7 @@ package org.apache.camel.upgrade.camel46;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
import org.apache.camel.upgrade.RecipesUtil;
import org.jspecify.annotations.Nullable;
+import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
@@ -61,7 +62,7 @@ public class XmlDsl46Recipe extends Recipe {
//save all properties into a list placed to the bean tag
//and the first property rename to properties and strip content
- if (BEAN_PROPERTY_XPATH_MATCHER.matches(getCursor())) {
+ if (BEAN_PROPERTY_XPATH_MATCHER.matches(getCursor()) &&
isCamelBean(getCursor().getParent())) {
List<Xml.Tag> sb =
getCursor().getParent().getMessage("properties");
if(sb == null) {
@@ -90,6 +91,19 @@ public class XmlDsl46Recipe extends Recipe {
return t;
}
+ /**
+ * A Camel bean declares its class with {@code type}, while a
Spring bean definition uses
+ * {@code class}. Camel XML files legitimately carry Spring bean
definitions alongside routes,
+ * and rewriting those into {@code <properties>} would break them.
+ */
+ private boolean isCamelBean(@Nullable Cursor beanCursor) {
+ if (beanCursor == null || !(beanCursor.getValue() instanceof
Xml.Tag)) {
+ return false;
+ }
+ Xml.Tag bean = (Xml.Tag) beanCursor.getValue();
+ return bean.getAttributes().stream().anyMatch(a ->
"type".equals(a.getKeyAsString()));
+ }
+
});
}
}
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel47/XmlDsl47Recipe.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel47/XmlDsl47Recipe.java
index 37eca9b..82c0c8e 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel47/XmlDsl47Recipe.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel47/XmlDsl47Recipe.java
@@ -16,7 +16,9 @@
*/
package org.apache.camel.upgrade.camel47;
+import org.apache.camel.upgrade.RecipesUtil;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
@@ -54,7 +56,7 @@ public class XmlDsl47Recipe extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new AbstractCamelXmlVisitor() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
AbstractCamelXmlVisitor() {
@Override
public Xml.Tag doVisitTag(final Xml.Tag tag, final
ExecutionContext ctx) {
@@ -68,6 +70,6 @@ public class XmlDsl47Recipe extends Recipe {
.findAny()
.orElse(t);
}
- };
+ });
}
}
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/FindCamelXmlDsl.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/FindCamelXmlDsl.java
new file mode 100644
index 0000000..59ddc51
--- /dev/null
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/FindCamelXmlDsl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.upgrade.customRecipes;
+
+import org.apache.camel.upgrade.RecipesUtil;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+
+/**
+ * Search recipe form of {@link RecipesUtil#camelXmlDslPrecondition()}, so
that declarative recipes can
+ * reference it from a {@code preconditions:} block the way the Java recipes
use it in code.
+ */
+public class FindCamelXmlDsl extends Recipe {
+
+ @Override
+ public String getDisplayName() {
+ return "Find Camel XML DSL documents";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Marks XML documents that belong to the Camel XML DSL, so that
a recipe operating on XML " +
+ "is not applied to unrelated documents such as Spring bean
definitions. A Camel namespace " +
+ "or a Camel context element anywhere in the document is
conclusive; otherwise the root " +
+ "element decides.";
+ }
+
+ @Override
+ public TreeVisitor<?, ExecutionContext> getVisitor() {
+ return RecipesUtil.camelXmlDslPrecondition();
+ }
+}
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInComponentXml.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInComponentXml.java
index ebf85fd..e820154 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInComponentXml.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInComponentXml.java
@@ -18,6 +18,7 @@ package org.apache.camel.upgrade.customRecipes;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
import org.apache.camel.upgrade.RecipesUtil;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
@@ -89,7 +90,7 @@ public class ReplacePropertyInComponentXml extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new AbstractCamelXmlVisitor() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
AbstractCamelXmlVisitor() {
@Override
public Xml.Tag doVisitTag(final Xml.Tag tag, final
ExecutionContext ctx) {
@@ -104,7 +105,7 @@ public class ReplacePropertyInComponentXml extends Recipe {
return t;
}
- };
+ });
}
private Xml.Tag replacePropertyIfPossible(final Xml.Tag tag) {
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInDataFormatXml.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInDataFormatXml.java
index 94237f3..5d51591 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInDataFormatXml.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInDataFormatXml.java
@@ -16,7 +16,9 @@
*/
package org.apache.camel.upgrade.customRecipes;
+import org.apache.camel.upgrade.RecipesUtil;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
@@ -73,7 +75,7 @@ public class ReplacePropertyInDataFormatXml extends Recipe {
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
- return new AbstractCamelXmlVisitor() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
AbstractCamelXmlVisitor() {
@Override
public Xml.Tag doVisitTag(final Xml.Tag tag, final
ExecutionContext ctx) {
@@ -84,7 +86,7 @@ public class ReplacePropertyInDataFormatXml extends Recipe {
}
return t;
}
- };
+ });
}
private Xml.Tag replacePropertyIfPossible(final Xml.Tag tag) {
diff --git
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/internal/ChangeXmlComponentUriRecipe.java
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/internal/ChangeXmlComponentUriRecipe.java
index 88b0ac4..2c97a5b 100644
---
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/internal/ChangeXmlComponentUriRecipe.java
+++
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/internal/ChangeXmlComponentUriRecipe.java
@@ -18,6 +18,7 @@ package org.apache.camel.upgrade.customRecipes.internal;
import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
import org.apache.camel.upgrade.RecipesUtil;
+import org.openrewrite.Preconditions;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
@@ -97,7 +98,7 @@ public class ChangeXmlComponentUriRecipe extends Recipe {
public TreeVisitor<?, ExecutionContext> getVisitor() {
Pattern pattern = Pattern.compile(uriPattern);
- return new AbstractCamelXmlVisitor() {
+ return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new
AbstractCamelXmlVisitor() {
@Override
public Xml.Tag doVisitTag(Xml.Tag tag, ExecutionContext ctx) {
Xml.Tag t = super.doVisitTag(tag, ctx);
@@ -109,7 +110,7 @@ public class ChangeXmlComponentUriRecipe extends Recipe {
return t;
}
- };
+ });
}
private static Xml.Tag transformXmlUri(Xml.Tag tag, Pattern pattern,
String replacement) {
diff --git
a/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.12.yaml
b/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.12.yaml
index 7d48e04..2689147 100644
--- a/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.12.yaml
+++ b/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.12.yaml
@@ -99,6 +99,8 @@ type: specs.openrewrite.org/v1beta/recipe
name: org.apache.camel.upgrade.camel412.xmlDslBearer
displayName: XML DSL bearer from rest/securityDefinitions is renamed to
bearerToken
description: Rest definition in XML DSL with security constraints, then bearer
in YAML and XML DSL has been renamed to bearerToken to be aligned with Java DSL.
+preconditions:
+ - org.apache.camel.upgrade.customRecipes.FindCamelXmlDsl
recipeList:
- org.openrewrite.xml.ChangeTagName:
elementName: //rest/securityDefinitions/bearer
diff --git
a/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.13.yaml
b/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.13.yaml
index b09d268..7abccb3 100644
--- a/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.13.yaml
+++ b/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.13.yaml
@@ -70,6 +70,20 @@ recipeList:
type: specs.openrewrite.org/v1beta/recipe
name: org.apache.camel.upgrade.camel413.furyDsl
displayName: Change dataformat fury to fury in xml/java dsl.
+recipeList:
+ - org.apache.camel.upgrade.camel413.furyXmlDsl
+ - org.openrewrite.java.ChangeMethodName:
+ methodPattern: org.apache.camel.builder.DataFormatClause fury(..)
+ newMethodName: fory
+---
+#https://camel.apache.org/manual/camel-4x-upgrade-guide-4_13.html#_camel_fury
+# Split from furyDsl so that the Camel XML DSL precondition does not gate the
Java DSL change too
+type: specs.openrewrite.org/v1beta/recipe
+name: org.apache.camel.upgrade.camel413.furyXmlDsl
+displayName: Change dataformat fury to fory in xml dsl.
+description: Change dataformat fury to fory in the Camel XML DSL.
+preconditions:
+ - org.apache.camel.upgrade.customRecipes.FindCamelXmlDsl
recipeList:
- org.openrewrite.xml.ChangeTagName:
elementName: dataFormats/fury
@@ -80,8 +94,5 @@ recipeList:
- org.openrewrite.xml.ChangeTagName:
elementName: marshal/fury
newName: fory
- - org.openrewrite.java.ChangeMethodName:
- methodPattern: org.apache.camel.builder.DataFormatClause fury(..)
- newMethodName: fory
diff --git
a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel40/CameXmlDslRecipeTest.java
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel40/CameXmlDslRecipeTest.java
index 7615142..7e3e39c 100644
---
a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel40/CameXmlDslRecipeTest.java
+++
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel40/CameXmlDslRecipeTest.java
@@ -86,7 +86,7 @@ public class CameXmlDslRecipeTest implements RewriteTest {
//language=xml
rewriteRun(xml(
"""
- <differentContext>
+ <camelContext>
<circuitBreaker>
<resilience4jConfiguration>
<bulkheadEnabled>5643</bulkheadEnabled>
@@ -98,15 +98,15 @@ public class CameXmlDslRecipeTest implements RewriteTest {
<timeoutCancelRunningFuture></timeoutCancelRunningFuture>
</resilience4jConfiguration>
</circuitBreaker>
- </differentContext>
+ </camelContext>
""",
"""
- <differentContext>
+ <camelContext>
<circuitBreaker>
<resilience4jConfiguration bulkheadEnabled="5643"
bulkheadMaxConcurrentCalls="aaaa" bulkheadMaxWaitDuration="1"
timeoutEnabled="true" timeoutExecutorService="1" timeoutDuration="1">
</resilience4jConfiguration>
</circuitBreaker>
- </differentContext>
+ </camelContext>
"""));
}
diff --git
a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/xml/CamelXmlDslPreconditionTest.java
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/xml/CamelXmlDslPreconditionTest.java
new file mode 100644
index 0000000..ef0794a
--- /dev/null
+++
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/xml/CamelXmlDslPreconditionTest.java
@@ -0,0 +1,361 @@
+/*
+ * 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.upgrade.xml;
+
+import org.apache.camel.upgrade.CamelTestUtil;
+import org.apache.camel.upgrade.camel410.XmlDsl410Recipe;
+import org.apache.camel.upgrade.camel418_1.XmlDsl418_1SagaRecipe;
+import org.apache.camel.upgrade.camel43.CamelResequenceEIPXmlRecipe;
+import org.apache.camel.upgrade.camel418_3.RenameHeaderInXmlDsl;
+import org.apache.camel.upgrade.camel418_3.RenameHeaderPrefixInXmlDsl;
+import org.apache.camel.upgrade.camel46.XmlDsl46Recipe;
+import org.apache.camel.upgrade.camel47.XmlDsl47Recipe;
+import org.apache.camel.upgrade.customRecipes.ReplacePropertyInComponentXml;
+import org.apache.camel.upgrade.customRecipes.ReplacePropertyInDataFormatXml;
+import
org.apache.camel.upgrade.customRecipes.internal.ChangeXmlComponentUriRecipe;
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.test.RewriteTest;
+import org.openrewrite.test.TypeValidation;
+
+import static org.openrewrite.xml.Assertions.xml;
+
+/**
+ * Every XML DSL recipe is gated on {@code
RecipesUtil.camelXmlDslPrecondition()}, so none of them may
+ * touch a document that is not Camel XML. Each test feeds a document carrying
exactly the shape the
+ * recipe matches, wrapped in a root element that is plainly not Camel, and
expects no change.
+ * <p>
+ * {@code camel40.xml.XmlDslRecipe} has no test here on purpose: its matchers
are anchored at
+ * {@code /routes/route}, so the document root has to be {@code routes}, which
is a Camel root.
+ */
+class CamelXmlDslPreconditionTest implements RewriteTest {
+
+ @DocumentExample
+ @Test
+ void springBeanDefinitionIsNotADataFormatOrHeaderCarrier() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new XmlDsl46Recipe()),
+ xml(
+ """
+ <beans xmlns="http://www.springframework.org/schema/beans">
+ <bean id="example" class="com.example.Example">
+ <property name="topic" value="orders"/>
+ </bean>
+ </beans>
+ """
+ )
+ );
+ }
+
+ @Test
+ void headerRenameLeavesNonCamelXmlAlone() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new RenameHeaderInXmlDsl("kafka.TOPIC",
"CamelKafkaTopic")),
+ xml(
+ """
+ <configuration xmlns="http://example.com/schema/http">
+ <endpoint url="https://example.com/publish">
+ <header name="kafka.TOPIC" value="orders"/>
+ <template>${header.kafka.TOPIC}</template>
+ </endpoint>
+ </configuration>
+ """
+ )
+ );
+ }
+
+ @Test
+ void headerPrefixRenameLeavesNonCamelXmlAlone() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new RenameHeaderPrefixInXmlDsl("SolrField.",
"CamelSolrField.")),
+ xml(
+ """
+ <configuration xmlns="http://example.com/schema/http">
+ <endpoint url="https://example.com/search">
+ <header name="SolrField.id" value="doc123"/>
+ </endpoint>
+ </configuration>
+ """
+ )
+ );
+ }
+
+ @Test
+ void sagaLeavesNonCamelXmlAlone() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new XmlDsl418_1SagaRecipe()),
+ xml(
+ """
+ <workflow xmlns="http://example.com/schema/workflow">
+ <saga>
+ <compensation uri="http://example.com/undo"/>
+ <completion uri="http://example.com/done"/>
+ </saga>
+ </workflow>
+ """
+ )
+ );
+ }
+
+ @Test
+ void circuitBreakerLeavesNonCamelXmlAlone() {
+ // driven through the whole 4.0 migration, the way
CameXmlDslRecipeTest drives it
+ //language=xml
+ rewriteRun(
+ spec -> CamelTestUtil.recipe(spec, CamelTestUtil.CamelVersion.v4_0)
+ .typeValidationOptions(TypeValidation.none()),
+ xml(
+ """
+ <application>
+ <circuitBreaker>
+ <resilience4jConfiguration>
+ <timeoutEnabled>true</timeoutEnabled>
+ <timeoutDuration>1</timeoutDuration>
+ </resilience4jConfiguration>
+ </circuitBreaker>
+ </application>
+ """
+ )
+ );
+ }
+
+ @Test
+ void interceptLeavesNonCamelXmlAlone() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new XmlDsl410Recipe()),
+ xml(
+ """
+ <pipeline xmlns="http://example.com/schema/pipeline">
+ <intercept>
+ <when>
+ <simple>true</simple>
+ </when>
+ </intercept>
+ </pipeline>
+ """
+ )
+ );
+ }
+
+ @Test
+ void loadBalanceLeavesNonCamelXmlAlone() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new XmlDsl47Recipe()),
+ xml(
+ """
+ <cluster xmlns="http://example.com/schema/cluster">
+ <loadBalance>
+ <roundRobin/>
+ </loadBalance>
+ </cluster>
+ """
+ )
+ );
+ }
+
+ @Test
+ void componentPropertyLeavesNonCamelXmlAlone() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new
ReplacePropertyInComponentXml("netty-http", "keyStoreFile", "keyStoreResource",
"file:")),
+ xml(
+ """
+ <deployment xmlns="http://example.com/schema/deployment">
+ <route>
+ <from
uri="netty-http:https://0.0.0.0:8443/service?keyStoreFile=/opt/keystore.jks"/>
+ </route>
+ </deployment>
+ """
+ )
+ );
+ }
+
+ @Test
+ void dataFormatPropertyLeavesNonCamelXmlAlone() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new ReplacePropertyInDataFormatXml("csv",
"formatRef", "format")),
+ xml(
+ """
+ <deployment xmlns="http://example.com/schema/deployment">
+ <marshal>
+ <csv formatRef="myCsvFormat"/>
+ </marshal>
+ </deployment>
+ """
+ )
+ );
+ }
+
+ @Test
+ void componentUriLeavesNonCamelXmlAlone() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new
ChangeXmlComponentUriRecipe("^langchain4j-tools:(.*)$", "ai-tool:${1}", true)),
+ xml(
+ """
+ <deployment xmlns="http://example.com/schema/deployment">
+ <route>
+ <from uri="langchain4j-tools:weather?tags=weather"/>
+ </route>
+ </deployment>
+ """
+ )
+ );
+ }
+
+ @Test
+ void resequenceLeavesNonCamelXmlAlone() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new CamelResequenceEIPXmlRecipe()),
+ xml(
+ """
+ <pipeline xmlns="http://example.com/schema/pipeline">
+ <resequence>
+ <stream-config timeout="1000"/>
+ </resequence>
+ </pipeline>
+ """
+ )
+ );
+ }
+
+ // ---- documents that must still be recognised as Camel ----
+
+ @Test
+ void springXmlLayoutIsMigrated() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new RenameHeaderInXmlDsl("kafka.TOPIC",
"CamelKafkaTopic")),
+ xml(
+ """
+ <beans xmlns="http://www.springframework.org/schema/beans">
+ <camelContext
xmlns="http://camel.apache.org/schema/spring">
+ <route>
+ <from uri="direct:start"/>
+ <setHeader name="kafka.TOPIC">
+ <constant>orders</constant>
+ </setHeader>
+ </route>
+ </camelContext>
+ </beans>
+ """,
+ """
+ <beans xmlns="http://www.springframework.org/schema/beans">
+ <camelContext
xmlns="http://camel.apache.org/schema/spring">
+ <route>
+ <from uri="direct:start"/>
+ <setHeader name="CamelKafkaTopic">
+ <constant>orders</constant>
+ </setHeader>
+ </route>
+ </camelContext>
+ </beans>
+ """
+ )
+ );
+ }
+
+ @Test
+ void camelRootIsMigrated() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new RenameHeaderInXmlDsl("kafka.TOPIC",
"CamelKafkaTopic")),
+ xml(
+ """
+ <camel>
+ <route>
+ <from uri="direct:start"/>
+ <setHeader name="kafka.TOPIC">
+ <constant>orders</constant>
+ </setHeader>
+ </route>
+ </camel>
+ """,
+ """
+ <camel>
+ <route>
+ <from uri="direct:start"/>
+ <setHeader name="CamelKafkaTopic">
+ <constant>orders</constant>
+ </setHeader>
+ </route>
+ </camel>
+ """
+ )
+ );
+ }
+
+ @Test
+ void pluralWrapperRootIsMigrated() {
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new RenameHeaderInXmlDsl("kafka.TOPIC",
"CamelKafkaTopic")),
+ xml(
+ """
+ <routeConfigurations>
+ <routeConfiguration>
+ <onException>
+ <setHeader name="kafka.TOPIC">
+ <constant>dlq</constant>
+ </setHeader>
+ </onException>
+ </routeConfiguration>
+ </routeConfigurations>
+ """,
+ """
+ <routeConfigurations>
+ <routeConfiguration>
+ <onException>
+ <setHeader name="CamelKafkaTopic">
+ <constant>dlq</constant>
+ </setHeader>
+ </onException>
+ </routeConfiguration>
+ </routeConfigurations>
+ """
+ )
+ );
+ }
+
+ @Test
+ void springStyleBeansInACamelDocumentAreLeftAlone() {
+ // a Camel XML file legitimately carries Spring bean definitions next
to its routes, and a Spring
+ // bean declares its class with class= where a Camel bean uses type=
+ //language=xml
+ rewriteRun(
+ spec -> spec.recipe(new XmlDsl46Recipe()),
+ xml(
+ """
+ <camel>
+ <bean id="bean1" class="org.apache.camel.main.app.Bean1">
+ <property name="bean" ref="bean2"/>
+ </bean>
+ </camel>
+ """
+ )
+ );
+ }
+
+}