This is an automated email from the ASF dual-hosted git repository. Croway pushed a commit to branch fix-4.22-recipe-issues in repository https://gitbox.apache.org/repos/asf/camel-upgrade-recipes.git
commit 38cb989bf49695d395c293bea9c387cb97aa7292 Author: croway <[email protected]> AuthorDate: Tue Aug 25 11:29:49 2026 +0200 Fix five defects in the Camel 4.22 upgrade recipes Found by applying the recipes to Camel 4.14, Camel 4.21 and Camel Spring Boot 4.21 test projects. * Remove migrateOpenAiChatCompletion. com.openai.models.ChatCompletion only exists in openai-java 0.8.1, while every camel-openai release from 4.17.0 onwards ships 4.13.0 or newer, where the class already lives in com.openai.models.chat.completions. The recipe could never match a real project, and its test passed only against a pinned 0.8.1 jar. The 4.22 guide entry describes a component metadata fix, so there is nothing to migrate in user code. * Rename headers in every context they appear in. RenameHeaders claimed to cover Simple expressions across all DSLs, but only rewrote strings passed to simple(). A half migrated route breaks silently at runtime, so the complete ${header.name} placeholder is now matched in any Java string literal, in XML element text and attribute values and in YAML scalars, and the header() DSL method is matched alongside setHeader() and removeHeader(). * Give Spring Boot applications camel-ai-tool-starter. The Camel recipe adds the plain camel-ai-tool artifact when migrating langchain4j-tools routes, and that artifact carries no auto configuration. The new migrateAiToolStarterDependency swaps it for the starter and drops the duplicate when the starter is already declared. * Resolve the target versions from the build instead of hardcoding 4.22.0, so that the recipes stay correct for the next release. * Rename component options that are inlined in a YAML uri. ReplacePropertyInComponentYaml only handled the parameters mapping, while the XML variant already handled both forms. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> --- .../src/main/resources/META-INF/rewrite/4.22.yaml | 17 +++- .../upgrade/springboot/CamelSpringBoot422Test.java | 92 ++++++++++++++++++++ camel-upgrade-recipes/pom.xml | 8 -- .../camel418_3/RenameHeaderInJavaMethod.java | 10 ++- .../camel418_3/RenameHeaderInSimpleExpression.java | 65 +++++++-------- .../upgrade/camel418_3/RenameHeaderInXmlDsl.java | 79 +++++++++++++----- .../upgrade/camel418_3/RenameHeaderInYamlDsl.java | 31 ++++++- .../ReplacePropertyInComponentYaml.java | 13 ++- .../src/main/resources/META-INF/rewrite/4.22.yaml | 19 +---- .../src/main/resources/versions.properties | 1 + .../org/apache/camel/upgrade/CamelTestUtil.java | 4 + .../apache/camel/upgrade/CamelUpdate415Test.java | 24 ++++++ .../apache/camel/upgrade/CamelUpdate422Test.java | 44 ++-------- .../camel418_3/RenameHeaderInJavaMethodTest.java | 32 +++++++ .../RenameHeaderInSimpleExpressionTest.java | 97 +++++++++++++++++++++- .../camel418_3/RenameHeaderInXmlDslTest.java | 55 ++++++++++++ .../camel418_3/RenameHeaderInYamlDslTest.java | 28 +++++++ 17 files changed, 492 insertions(+), 127 deletions(-) diff --git a/camel-spring-boot-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.yaml b/camel-spring-boot-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.yaml index 2e5e17c..d345138 100644 --- a/camel-spring-boot-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.yaml +++ b/camel-spring-boot-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.yaml @@ -23,6 +23,7 @@ recipeList: - org.apache.camel.upgrade.camel421.CamelSpringBootMigrationRecipe - org.apache.camel.upgrade.camel422.CamelMigrationRecipe - org.apache.camel.upgrade.camel422.migrateSpringAiToolsStarterDependency + - org.apache.camel.upgrade.camel422.migrateAiToolStarterDependency --- ## https://github.com/apache/camel/blob/main/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#camel-spring-ai-chat type: specs.openrewrite.org/v1beta/recipe @@ -35,4 +36,18 @@ recipeList: oldArtifactId: camel-spring-ai-tools-starter newGroupId: org.apache.camel.springboot newArtifactId: camel-ai-tool-starter - newVersion: 4.22.0 + newVersion: @camel-spring-boot-version@ +--- +## https://github.com/apache/camel/blob/main/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#camel-langchain4j-tools-deprecated +type: specs.openrewrite.org/v1beta/recipe +name: org.apache.camel.upgrade.camel422.migrateAiToolStarterDependency +displayName: Use camel-ai-tool-starter instead of camel-ai-tool +description: Replaces the plain camel-ai-tool dependency with camel-ai-tool-starter, so that a Spring Boot application gets the component auto-configuration. The plain artifact is what the Camel recipe adds when migrating langchain4j-tools routes; duplicates are removed when the starter is already declared. +recipeList: + - org.openrewrite.maven.ChangeDependencyGroupIdAndArtifactId: + oldGroupId: org.apache.camel + oldArtifactId: camel-ai-tool + newGroupId: org.apache.camel.springboot + newArtifactId: camel-ai-tool-starter + newVersion: @camel-spring-boot-version@ + - org.openrewrite.maven.RemoveDuplicateDependencies diff --git a/camel-spring-boot-upgrade-recipes/src/test/java/org/apache/camel/upgrade/springboot/CamelSpringBoot422Test.java b/camel-spring-boot-upgrade-recipes/src/test/java/org/apache/camel/upgrade/springboot/CamelSpringBoot422Test.java index 24345b1..84a648d 100644 --- a/camel-spring-boot-upgrade-recipes/src/test/java/org/apache/camel/upgrade/springboot/CamelSpringBoot422Test.java +++ b/camel-spring-boot-upgrade-recipes/src/test/java/org/apache/camel/upgrade/springboot/CamelSpringBoot422Test.java @@ -16,6 +16,7 @@ */ package org.apache.camel.upgrade.springboot; +import org.apache.camel.upgrade.CamelTestUtil; import org.junit.jupiter.api.Test; import org.openrewrite.DocumentExample; import org.openrewrite.config.Environment; @@ -69,11 +70,102 @@ class CamelSpringBoot422Test implements RewriteTest { <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-ai-tool-starter</artifactId> + <version>%s</version> + </dependency> + </dependencies> + </project> + """.formatted(CamelTestUtil.getCamelSpringBootVersion()) + ) + ); + } + + @Test + void migrateAiToolStarterDependency() { + //language=xml + rewriteRun( + pomXml( + """ + <project> + <groupId>com.example</groupId> + <artifactId>test</artifactId> + <version>1.0.0</version> + <properties> + <maven.compiler.release>17</maven.compiler.release> + </properties> + <dependencies> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-ai-tool</artifactId> <version>4.22.0</version> </dependency> </dependencies> </project> + """, """ + <project> + <groupId>com.example</groupId> + <artifactId>test</artifactId> + <version>1.0.0</version> + <properties> + <maven.compiler.release>17</maven.compiler.release> + </properties> + <dependencies> + <dependency> + <groupId>org.apache.camel.springboot</groupId> + <artifactId>camel-ai-tool-starter</artifactId> + <version>%s</version> + </dependency> + </dependencies> + </project> + """.formatted(CamelTestUtil.getCamelSpringBootVersion()) + ) + ); + } + + @Test + void aiToolStarterIsNotDuplicated() { + //language=xml + rewriteRun( + pomXml( + """ + <project> + <groupId>com.example</groupId> + <artifactId>test</artifactId> + <version>1.0.0</version> + <properties> + <maven.compiler.release>17</maven.compiler.release> + </properties> + <dependencies> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-ai-tool</artifactId> + <version>4.22.0</version> + </dependency> + <dependency> + <groupId>org.apache.camel.springboot</groupId> + <artifactId>camel-spring-ai-tools-starter</artifactId> + <version>4.21.0</version> + </dependency> + </dependencies> + </project> + """, + """ + <project> + <groupId>com.example</groupId> + <artifactId>test</artifactId> + <version>1.0.0</version> + <properties> + <maven.compiler.release>17</maven.compiler.release> + </properties> + <dependencies> + <dependency> + <groupId>org.apache.camel.springboot</groupId> + <artifactId>camel-ai-tool-starter</artifactId> + <version>%s</version> + </dependency> + </dependencies> + </project> + """.formatted(CamelTestUtil.getCamelSpringBootVersion()) ) ); } diff --git a/camel-upgrade-recipes/pom.xml b/camel-upgrade-recipes/pom.xml index 263b43d..23a5564 100644 --- a/camel-upgrade-recipes/pom.xml +++ b/camel-upgrade-recipes/pom.xml @@ -635,14 +635,6 @@ <outputDirectory>${rewrite-tmp-classpath}</outputDirectory> </artifactItem> - <!-- OpenAI SDK with the pre-4.22 package layout for ChatCompletion migration tests (4.22) --> - <artifactItem> - <groupId>com.openai</groupId> - <artifactId>openai-java-core</artifactId> - <version>0.8.1</version> - <outputDirectory>${rewrite-tmp-classpath}</outputDirectory> - </artifactItem> - </artifactItems> </configuration> </execution> diff --git a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInJavaMethod.java b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInJavaMethod.java index 6575d32..ff1ce27 100644 --- a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInJavaMethod.java +++ b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInJavaMethod.java @@ -68,7 +68,8 @@ public class RenameHeaderInJavaMethod extends Recipe { @Override public String getDescription() { - return "Renames header references in Message.setHeader() and Message.getHeader() method calls. " + + return "Renames header references in Message.setHeader(), Message.getHeader(), and in the " + + "setHeader(), removeHeader() and header() DSL methods. " + "Only migrates string literals in safe contexts. Does NOT migrate dynamic header names or Map.get() calls."; } @@ -88,6 +89,10 @@ public class RenameHeaderInJavaMethod extends Recipe { new MethodMatcher("org.apache.camel.model.ProcessorDefinition setHeader(String, ..)", true); private static final MethodMatcher DSL_REMOVE_HEADER_MATCHER = new MethodMatcher("org.apache.camel.model.ProcessorDefinition removeHeader(String)", true); + // header("name") builds a predicate/expression on the header, it is declared on BuilderSupport + // and therefore available on RouteBuilder and the expression clauses + private static final MethodMatcher BUILDER_HEADER_MATCHER = + new MethodMatcher("org.apache.camel.builder.BuilderSupport header(String)", true); private final String oldHeaderName; private final String newHeaderName; @@ -133,7 +138,8 @@ public class RenameHeaderInJavaMethod extends Recipe { getMethodMatcher(MATCHER_GET_HEADER_3_ARGS).matches(mi) || getMethodMatcher(MATCHER_GET_HEADER_SUPPLIER).matches(mi) || DSL_SET_HEADER_MATCHER.matches(mi) || - DSL_REMOVE_HEADER_MATCHER.matches(mi); + DSL_REMOVE_HEADER_MATCHER.matches(mi) || + BUILDER_HEADER_MATCHER.matches(mi); } } } diff --git a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInSimpleExpression.java b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInSimpleExpression.java index f62c3e4..0c92f81 100644 --- a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInSimpleExpression.java +++ b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInSimpleExpression.java @@ -24,11 +24,13 @@ import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; import org.openrewrite.java.tree.J; +import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Renames header references in Simple expressions like ${header.oldName} or ${headers.oldName}. - * This recipe only transforms strings inside simple() method calls to avoid false positives. + * The whole placeholder is matched, so any string literal carrying a Simple expression is covered, + * whether it is passed to simple(), to log(), or to an endpoint URI. */ public class RenameHeaderInSimpleExpression extends Recipe { @@ -65,8 +67,9 @@ public class RenameHeaderInSimpleExpression extends Recipe { @Override public String getDescription() { - return "Renames header references in Simple expressions like ${header.oldName} → ${header.newName}. " + - "Only migrates expressions inside simple() method calls."; + return "Renames header references in Simple expressions like ${header.oldName} → ${header.newName}, " + + "in every string literal carrying a Simple expression: simple(), log(), endpoint URIs and the like. " + + "Only the complete ${header.oldName} placeholder is matched, so plain occurrences of the name are left alone."; } @Override @@ -75,58 +78,48 @@ public class RenameHeaderInSimpleExpression extends Recipe { } private static class SimpleExpressionVisitor extends AbstractCamelJavaVisitor { - private final String oldHeaderName; - private final String newHeaderName; private final Pattern headerPattern; private final Pattern headersPattern; + private final String replacement; SimpleExpressionVisitor(String oldHeaderName, String newHeaderName) { - this.oldHeaderName = oldHeaderName; - this.newHeaderName = newHeaderName; - // Escape dots in header name for regex, but keep them in the pattern String escapedOldName = Pattern.quote(oldHeaderName); // Match ${header.oldName} or ${headers.oldName} this.headerPattern = Pattern.compile("(\\$\\{header\\.)" + escapedOldName + "(\\})"); this.headersPattern = Pattern.compile("(\\$\\{headers\\.)" + escapedOldName + "(\\})"); + this.replacement = "$1" + Matcher.quoteReplacement(newHeaderName) + "$2"; } @Override - protected J.MethodInvocation doVisitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation mi = super.doVisitMethodInvocation(method, ctx); - - // Check if this is a simple() method call (any class, method name "simple") - if (mi.getSimpleName().equals("simple")) { - // Get the first argument (the Simple expression string) - if (!mi.getArguments().isEmpty() && mi.getArguments().get(0) instanceof J.Literal) { - J.Literal literal = (J.Literal) mi.getArguments().get(0); - - if (literal.getValue() instanceof String) { - String expression = (String) literal.getValue(); - String newExpression = expression; - - // Replace ${header.oldName} with ${header.newName} - newExpression = headerPattern.matcher(newExpression).replaceAll("$1" + newHeaderName + "$2"); + protected J.Literal doVisitLiteral(J.Literal literal, ExecutionContext ctx) { + J.Literal l = super.doVisitLiteral(literal, ctx); - // Replace ${headers.oldName} with ${headers.newName} - newExpression = headersPattern.matcher(newExpression).replaceAll("$1" + newHeaderName + "$2"); + if (!(l.getValue() instanceof String)) { + return l; + } - // If changed, update the literal - if (!expression.equals(newExpression)) { - J.Literal newLiteral = literal.withValue(newExpression) - .withValueSource("\"" + newExpression + "\""); + String expression = (String) l.getValue(); + String newExpression = rename(expression); + if (expression.equals(newExpression)) { + return l; + } - java.util.List<org.openrewrite.java.tree.Expression> newArgs = new java.util.ArrayList<>(mi.getArguments()); - newArgs.set(0, newLiteral); + l = l.withValue(newExpression); - return mi.withArguments(newArgs); - } - } - } + // The placeholder needs no escaping, so the same replacement can be applied to the + // source representation, which keeps the original quoting style intact + if (l.getValueSource() != null) { + l = l.withValueSource(rename(l.getValueSource())); } - return mi; + return l; + } + + private String rename(String value) { + String renamed = headerPattern.matcher(value).replaceAll(replacement); + return headersPattern.matcher(renamed).replaceAll(replacement); } } } diff --git a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInXmlDsl.java b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInXmlDsl.java index 0f889cd..a8cee37 100644 --- a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInXmlDsl.java +++ b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInXmlDsl.java @@ -25,8 +25,13 @@ import org.openrewrite.internal.ListUtils; import org.openrewrite.marker.Markers; import org.openrewrite.xml.tree.Xml; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** - * Renames header references in XML DSL <setHeader name="..."> and <header name="..."> elements. + * Renames header references in XML DSL <setHeader name="..."> and <header name="..."> elements, + * and in the Simple expressions carried by element text and attribute values. */ public class RenameHeaderInXmlDsl extends Recipe { @@ -64,7 +69,8 @@ public class RenameHeaderInXmlDsl extends Recipe { @Override public String getDescription() { return "Renames header references in XML DSL <setHeader name=\"...\">, <header name=\"...\">, " + - "and <removeHeader name=\"...\"> elements."; + "and <removeHeader name=\"...\"> elements, and the ${header.oldName} placeholder wherever it " + + "appears in element text (<simple>) or in an attribute value."; } @Override @@ -75,10 +81,18 @@ public class RenameHeaderInXmlDsl extends Recipe { private static class XmlHeaderVisitor extends AbstractCamelXmlVisitor { private final String oldHeaderName; private final String newHeaderName; + private final Pattern headerPattern; + private final Pattern headersPattern; + private final String replacement; XmlHeaderVisitor(String oldHeaderName, String newHeaderName) { this.oldHeaderName = oldHeaderName; this.newHeaderName = newHeaderName; + + String escapedOldName = Pattern.quote(oldHeaderName); + this.headerPattern = Pattern.compile("(\\$\\{header\\.)" + escapedOldName + "(\\})"); + this.headersPattern = Pattern.compile("(\\$\\{headers\\.)" + escapedOldName + "(\\})"); + this.replacement = "$1" + Matcher.quoteReplacement(newHeaderName) + "$2"; } @Override @@ -87,27 +101,54 @@ public class RenameHeaderInXmlDsl extends Recipe { // Check if this is a setHeader, header, or removeHeader tag String tagName = t.getName(); - if ("setHeader".equals(tagName) || "header".equals(tagName) || "removeHeader".equals(tagName)) { - // Look for the "name" attribute with oldHeaderName value - return t.withAttributes(ListUtils.map(t.getAttributes(), attr -> { - if ("name".equals(attr.getKeyAsString()) && - oldHeaderName.equals(attr.getValueAsString())) { - // Replace with new header name - return attr.withValue( - new Xml.Attribute.Value( - attr.getValue().getId(), - "", - Markers.EMPTY, - attr.getValue().getQuote(), - newHeaderName - ) - ); - } + boolean headerTag = "setHeader".equals(tagName) || "header".equals(tagName) || "removeHeader".equals(tagName); + + t = t.withAttributes(ListUtils.map(t.getAttributes(), attr -> { + String value = attr.getValueAsString(); + if (value == null) { return attr; - })); + } + + // The "name" attribute of a header element holds the header name itself + if (headerTag && "name".equals(attr.getKeyAsString()) && oldHeaderName.equals(value)) { + return withValue(attr, newHeaderName); + } + + // Any other attribute may carry a Simple expression, e.g. <log message="${header.x}"/> + String renamed = rename(value); + return value.equals(renamed) ? attr : withValue(attr, renamed); + })); + + // Element text holds Simple expressions too, e.g. <simple>${header.x}</simple>. + // Only leaf elements have text content of their own. + if (t.getChildren().isEmpty()) { + Optional<String> value = t.getValue(); + if (value.isPresent()) { + String renamed = rename(value.get()); + if (!value.get().equals(renamed)) { + t = t.withValue(renamed); + } + } } return t; } + + private static Xml.Attribute withValue(Xml.Attribute attr, String newValue) { + return attr.withValue( + new Xml.Attribute.Value( + attr.getValue().getId(), + "", + Markers.EMPTY, + attr.getValue().getQuote(), + newValue + ) + ); + } + + private String rename(String value) { + String renamed = headerPattern.matcher(value).replaceAll(replacement); + return headersPattern.matcher(renamed).replaceAll(replacement); + } } } diff --git a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInYamlDsl.java b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInYamlDsl.java index ff6ea84..9429c07 100644 --- a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInYamlDsl.java +++ b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInYamlDsl.java @@ -25,8 +25,12 @@ import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; import org.openrewrite.yaml.tree.Yaml; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** - * Renames header references in YAML DSL setHeader.name, header.name, and removeHeader.name entries. + * Renames header references in YAML DSL setHeader.name, header.name, and removeHeader.name entries, + * and in the Simple expressions carried by scalar values. */ public class RenameHeaderInYamlDsl extends Recipe { @@ -63,7 +67,8 @@ public class RenameHeaderInYamlDsl extends Recipe { @Override public String getDescription() { - return "Renames header references in YAML DSL setHeader.name, header.name, and removeHeader.name entries."; + return "Renames header references in YAML DSL setHeader.name, header.name, and removeHeader.name entries, " + + "and the ${header.oldName} placeholder wherever it appears in a scalar value."; } @Override @@ -75,10 +80,18 @@ public class RenameHeaderInYamlDsl extends Recipe { private static class YamlHeaderVisitor extends AbstractCamelYamlVisitor { private final String oldHeaderName; private final String newHeaderName; + private final Pattern headerPattern; + private final Pattern headersPattern; + private final String replacement; YamlHeaderVisitor(String oldHeaderName, String newHeaderName) { this.oldHeaderName = oldHeaderName; this.newHeaderName = newHeaderName; + + String escapedOldName = Pattern.quote(oldHeaderName); + this.headerPattern = Pattern.compile("(\\$\\{header\\.)" + escapedOldName + "(\\})"); + this.headersPattern = Pattern.compile("(\\$\\{headers\\.)" + escapedOldName + "(\\})"); + this.replacement = "$1" + Matcher.quoteReplacement(newHeaderName) + "$2"; } @Override @@ -103,9 +116,23 @@ public class RenameHeaderInYamlDsl extends Recipe { } } + // Any scalar may carry a Simple expression, e.g. simple: "${header.x}" + if (e.getValue() instanceof Yaml.Scalar) { + Yaml.Scalar scalarValue = (Yaml.Scalar) e.getValue(); + String renamed = rename(scalarValue.getValue()); + if (!scalarValue.getValue().equals(renamed)) { + return e.withValue(scalarValue.withValue(renamed)); + } + } + return e; } + private String rename(String value) { + String renamed = headerPattern.matcher(value).replaceAll(replacement); + return headersPattern.matcher(renamed).replaceAll(replacement); + } + /** * Check if this entry is within a setHeader, header, or removeHeader mapping. */ diff --git a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInComponentYaml.java b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInComponentYaml.java index 37c4747..1cfc6f3 100644 --- a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInComponentYaml.java +++ b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/customRecipes/ReplacePropertyInComponentYaml.java @@ -80,7 +80,8 @@ public class ReplacePropertyInComponentYaml extends Recipe { @Override public String getDescription() { - return "ARenames property of the component."; + return "Renames a property of the component in the YAML DSL, both in the parameters mapping and " + + "when the property is inlined in the endpoint uri."; } @Override @@ -124,6 +125,16 @@ public class ReplacePropertyInComponentYaml extends Recipe { } } + // The same options can be inlined in the uri, e.g. uri: "netty-http:https://host/path?keyStoreFile=..." + if (valuePrefix != null && "uri".equals(e.getKey().getValue()) && e.getValue() instanceof Yaml.Scalar) { + Yaml.Scalar uriScalar = (Yaml.Scalar) e.getValue(); + String newUri = RecipesUtil.replacePropertyInUrl(uriScalar.getValue(), component, oldPropertyKey, + newPropertyKey, valuePrefix); + if (newUri != null) { + return e.withValue(uriScalar.withValue(newUri)); + } + } + return e; } diff --git a/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.yaml b/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.yaml index 075e4b2..67a93da 100644 --- a/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.yaml +++ b/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.yaml @@ -33,7 +33,6 @@ recipeList: - org.apache.camel.upgrade.camel422.migrateMinioTypes - org.apache.camel.upgrade.camel422.removeCamelReactiveExecutorTomcatDependency - org.apache.camel.upgrade.camel422.migrateSpringAiToolsDependency - - org.apache.camel.upgrade.camel422.migrateOpenAiChatCompletion - org.apache.camel.upgrade.camel422.migrateLangchain4jToolsUris - org.apache.camel.upgrade.camel422.migrateSpringAiToolsUris - org.apache.camel.upgrade.camel422.migrateAtmosphereWebsocketHeaders @@ -128,21 +127,7 @@ recipeList: oldArtifactId: camel-spring-ai-tools newGroupId: org.apache.camel newArtifactId: camel-ai-tool - newVersion: 4.22.0 ---- -## https://github.com/apache/camel/blob/main/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#camel-openai -type: specs.openrewrite.org/v1beta/recipe -name: org.apache.camel.upgrade.camel422.migrateOpenAiChatCompletion -displayName: Migrate OpenAI ChatCompletion type to its new package -description: Migrates com.openai.models.ChatCompletion to com.openai.models.chat.completions.ChatCompletion, matching the javaType declared for the CamelOpenAIResponse exchange property since Camel 4.22. -preconditions: - - org.openrewrite.java.dependencies.search.ModuleHasDependency: - groupIdPattern: org.apache.camel - artifactIdPattern: camel-openai -recipeList: - - org.openrewrite.java.ChangeType: - oldFullyQualifiedTypeName: com.openai.models.ChatCompletion - newFullyQualifiedTypeName: com.openai.models.chat.completions.ChatCompletion + newVersion: @camel-latest-version@ --- ## https://github.com/apache/camel/blob/main/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#camel-langchain4j-tools-deprecated type: specs.openrewrite.org/v1beta/recipe @@ -164,7 +149,7 @@ recipeList: # Fallback for poms with explicit versions only: when a BOM manages camel-ai-tool, # AddDependency omits the version tag and the BOM-managed version wins. The latest # migration chain additionally bumps org.apache.camel:* to its target version. - version: 4.22.0 + version: @camel-latest-version@ --- ## https://github.com/apache/camel/blob/main/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#camel-spring-ai-chat type: specs.openrewrite.org/v1beta/recipe diff --git a/camel-upgrade-recipes/src/main/resources/versions.properties b/camel-upgrade-recipes/src/main/resources/versions.properties index df2bdb8..9cb8cd0 100644 --- a/camel-upgrade-recipes/src/main/resources/versions.properties +++ b/camel-upgrade-recipes/src/main/resources/versions.properties @@ -1,4 +1,5 @@ camel.latest.version=@camel-latest-version@ +camel.spring.boot.version=@camel-spring-boot-version@ [email protected]@ [email protected]@ diff --git a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelTestUtil.java b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelTestUtil.java index 7118070..605aa54 100644 --- a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelTestUtil.java +++ b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelTestUtil.java @@ -162,6 +162,10 @@ public class CamelTestUtil { return getString( "camel.latest.version", "Could not determine camel latest version from properties file."); } + public static String getCamelSpringBootVersion() { + return getString( + "camel.spring.boot.version", "Could not determine camel spring boot version from properties file."); + } public static String getCamel410LtsVersion() { return getString( "camel4.10.lts.version", "Could not determine 4.10 lts version from properties file."); diff --git a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate415Test.java b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate415Test.java index c9deab9..177b921 100644 --- a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate415Test.java +++ b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate415Test.java @@ -410,6 +410,30 @@ public class CamelUpdate415Test implements RewriteTest { /** * <a href="https://camel.apache.org/manual/camel-4x-upgrade-guide-4_15.html#_data_formats">Data Formats</a> in DSL */ + @Test + void nettyKeyStoreInlineUriTestYaml() { + //language=yaml + rewriteRun(yaml( + """ + - route: + id: route-3277 + from: + uri: "netty-http:tcp:12345?keyStoreFile=/testFile" + steps: + - to: + uri: "netty:tcp:12346?trustStoreFile=/testFile" + """, + """ + - route: + id: route-3277 + from: + uri: "netty-http:tcp:12345?keyStoreResource=file:/testFile" + steps: + - to: + uri: "netty:tcp:12346?trustStoreResource=file:/testFile" + """)); + } + @Test void nettyKeyStoreTestYaml() { //language=yaml diff --git a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate422Test.java b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate422Test.java index b87305e..57d0586 100644 --- a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate422Test.java +++ b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate422Test.java @@ -34,7 +34,7 @@ public class CamelUpdate422Test implements RewriteTest { CamelTestUtil.recipe(spec, CamelTestUtil.CamelVersion.v4_22, true) .parser(CamelTestUtil.parserFromClasspath(CamelTestUtil.CamelVersion.v4_21, "camel-core-model", "camel-api", "camel-support", "camel-azure-storage-blob", "minio", - "openai-java-core", "jakarta.xml.bind-api")) + "jakarta.xml.bind-api")) .typeValidationOptions(TypeValidation.none()) .expectedCyclesThatMakeChanges(1); } @@ -251,41 +251,11 @@ public class CamelUpdate422Test implements RewriteTest { <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-ai-tool</artifactId> - <version>4.22.0</version> + <version>%s</version> </dependency> </dependencies> </project> - """ - ) - ); - } - - @Test - void migrateOpenAiChatCompletion() { - //language=java - rewriteRun( - mavenProject("test-openai", - CamelTestUtil.pomXmlSpec("camel-openai", CamelTestUtil.CamelVersion.v4_21), - java( - """ - import com.openai.models.ChatCompletion; - - public class OpenAiExample { - public void example() { - ChatCompletion completion = null; - } - } - """, - """ - import com.openai.models.chat.completions.ChatCompletion; - - public class OpenAiExample { - public void example() { - ChatCompletion completion = null; - } - } - """ - ) + """.formatted(CamelTestUtil.getCamelLatestVersion()) ) ); } @@ -326,7 +296,7 @@ public class CamelUpdate422Test implements RewriteTest { <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-ai-tool</artifactId> - <version>4.22.0</version> + <version>%s</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> @@ -335,7 +305,7 @@ public class CamelUpdate422Test implements RewriteTest { </dependency> </dependencies> </project> - """ + """.formatted(CamelTestUtil.getCamelLatestVersion()) ), //language=java java( @@ -406,11 +376,11 @@ public class CamelUpdate422Test implements RewriteTest { <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-ai-tool</artifactId> - <version>4.22.0</version> + <version>%s</version> </dependency> </dependencies> </project> - """ + """.formatted(CamelTestUtil.getCamelLatestVersion()) ), //language=java java( diff --git a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInJavaMethodTest.java b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInJavaMethodTest.java index ea0e286..b656d1c 100644 --- a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInJavaMethodTest.java +++ b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInJavaMethodTest.java @@ -251,4 +251,36 @@ public class RenameHeaderInJavaMethodTest implements RewriteTest { ) ); } + + @Test + void headerPredicateMigration() { + //language=java + rewriteRun( + java( + """ + import org.apache.camel.builder.RouteBuilder; + + class Test extends RouteBuilder { + public void configure() { + from("direct:start") + .filter(header("kafka.TOPIC").isEqualTo("orders")) + .to("mock:result"); + } + } + """, + """ + import org.apache.camel.builder.RouteBuilder; + + class Test extends RouteBuilder { + public void configure() { + from("direct:start") + .filter(header("CamelKafkaTopic").isEqualTo("orders")) + .to("mock:result"); + } + } + """ + ) + ); + } + } diff --git a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInSimpleExpressionTest.java b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInSimpleExpressionTest.java index b41ecdf..4a6ccd9 100644 --- a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInSimpleExpressionTest.java +++ b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInSimpleExpressionTest.java @@ -184,7 +184,7 @@ public class RenameHeaderInSimpleExpressionTest implements RewriteTest { } @Test - void doesNotMigrateNonSimpleStrings() { + void migratesSimpleExpressionHeldInAVariable() { //language=java rewriteRun( java( @@ -193,12 +193,23 @@ public class RenameHeaderInSimpleExpressionTest implements RewriteTest { class Test extends RouteBuilder { public void configure() { - String expression = "${header.kafka.TOPIC}"; // Not inside simple() call - System.out.println("Expression: ${header.kafka.TOPIC}"); + String expression = "${header.kafka.TOPIC}"; + from("direct:start") + .setBody(simple(expression)); + } + } + """, + """ + import org.apache.camel.builder.RouteBuilder; + + class Test extends RouteBuilder { + public void configure() { + String expression = "${header.CamelKafkaTopic}"; + from("direct:start") + .setBody(simple(expression)); } } """ - // No change expected ) ); } @@ -242,4 +253,82 @@ public class RenameHeaderInSimpleExpressionTest implements RewriteTest { ) ); } + + @Test + void logMessageMigration() { + //language=java + rewriteRun( + java( + """ + import org.apache.camel.builder.RouteBuilder; + + class Test extends RouteBuilder { + public void configure() { + from("direct:start") + .log("topic is ${header.kafka.TOPIC}"); + } + } + """, + """ + import org.apache.camel.builder.RouteBuilder; + + class Test extends RouteBuilder { + public void configure() { + from("direct:start") + .log("topic is ${header.CamelKafkaTopic}"); + } + } + """ + ) + ); + } + + @Test + void endpointUriMigration() { + //language=java + rewriteRun( + java( + """ + import org.apache.camel.builder.RouteBuilder; + + class Test extends RouteBuilder { + public void configure() { + from("direct:start") + .toD("mock:${header.kafka.TOPIC}"); + } + } + """, + """ + import org.apache.camel.builder.RouteBuilder; + + class Test extends RouteBuilder { + public void configure() { + from("direct:start") + .toD("mock:${header.CamelKafkaTopic}"); + } + } + """ + ) + ); + } + + @Test + void plainOccurrenceOfTheNameIsLeftAlone() { + //language=java + rewriteRun( + java( + """ + import org.apache.camel.builder.RouteBuilder; + + class Test extends RouteBuilder { + public void configure() { + from("direct:start") + .log("kafka.TOPIC and ${header.kafka.TOPIC.suffix}"); + } + } + """ + ) + ); + } + } diff --git a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInXmlDslTest.java b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInXmlDslTest.java index a57d7fd..2ff8397 100644 --- a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInXmlDslTest.java +++ b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInXmlDslTest.java @@ -201,4 +201,59 @@ public class RenameHeaderInXmlDslTest implements RewriteTest { ) ); } + + @Test + void simpleExpressionInElementTextMigration() { + //language=xml + rewriteRun( + xml( + """ + <routes xmlns="http://camel.apache.org/schema/spring"> + <route> + <from uri="direct:start"/> + <setBody> + <simple>${header.kafka.TOPIC}</simple> + </setBody> + </route> + </routes> + """, + """ + <routes xmlns="http://camel.apache.org/schema/spring"> + <route> + <from uri="direct:start"/> + <setBody> + <simple>${header.CamelKafkaTopic}</simple> + </setBody> + </route> + </routes> + """ + ) + ); + } + + @Test + void simpleExpressionInAttributeMigration() { + //language=xml + rewriteRun( + xml( + """ + <routes xmlns="http://camel.apache.org/schema/spring"> + <route> + <from uri="direct:start"/> + <log message="topic is ${header.kafka.TOPIC}"/> + </route> + </routes> + """, + """ + <routes xmlns="http://camel.apache.org/schema/spring"> + <route> + <from uri="direct:start"/> + <log message="topic is ${header.CamelKafkaTopic}"/> + </route> + </routes> + """ + ) + ); + } + } diff --git a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInYamlDslTest.java b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInYamlDslTest.java index 242daa9..e7dbec0 100644 --- a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInYamlDslTest.java +++ b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/camel418_3/RenameHeaderInYamlDslTest.java @@ -232,4 +232,32 @@ public class RenameHeaderInYamlDslTest implements RewriteTest { ) ); } + + @Test + void simpleExpressionInScalarMigration() { + //language=yaml + rewriteRun( + yaml( + """ + - route: + from: + uri: "direct:start" + steps: + - setBody: + simple: "${header.kafka.TOPIC}" + - log: "topic is ${header.kafka.TOPIC}" + """, + """ + - route: + from: + uri: "direct:start" + steps: + - setBody: + simple: "${header.CamelKafkaTopic}" + - log: "topic is ${header.CamelKafkaTopic}" + """ + ) + ); + } + }
