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 35754b6  Add Camel 4.22.1 migration recipe for camel-openai 
storeFullResponse property (CAMEL-24539)
35754b6 is described below

commit 35754b69cb0e65d94d985f708d7571913997e7ed
Author: Federico Mariani <[email protected]>
AuthorDate: Wed Sep 16 09:53:01 2026 +0200

    Add Camel 4.22.1 migration recipe for camel-openai storeFullResponse 
property (CAMEL-24539)
---
 camel-upgrade-recipes/pom.xml                      |   8 +
 .../FlagOpenAIFullResponsePropertyInJavaDsl.java   | 130 +++++++++
 .../FlagOpenAIFullResponsePropertyInXmlDsl.java    | 129 +++++++++
 .../FlagOpenAIFullResponsePropertyInYamlDsl.java   | 112 ++++++++
 .../main/resources/META-INF/rewrite/4.22.1.yaml    |  59 ++++
 .../org/apache/camel/upgrade/CamelTestUtil.java    |   3 +-
 .../apache/camel/upgrade/CamelUpdate422_1Test.java | 296 +++++++++++++++++++++
 release_notes.adoc                                 |  75 ++++++
 8 files changed, 811 insertions(+), 1 deletion(-)

diff --git a/camel-upgrade-recipes/pom.xml b/camel-upgrade-recipes/pom.xml
index 72602f4..15c0876 100644
--- a/camel-upgrade-recipes/pom.xml
+++ b/camel-upgrade-recipes/pom.xml
@@ -635,6 +635,14 @@
                                     
<outputDirectory>${rewrite-tmp-classpath}</outputDirectory>
                                 </artifactItem>
 
+                                <!-- camel-openai for OpenAIConstants on the 
classpath (4.22.1) -->
+                                <artifactItem>
+                                    <groupId>org.apache.camel</groupId>
+                                    <artifactId>camel-openai</artifactId>
+                                    <version>4.22.0</version>
+                                    
<outputDirectory>${rewrite-tmp-classpath}</outputDirectory>
+                                </artifactItem>
+
                             </artifactItems>
                         </configuration>
                     </execution>
diff --git 
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInJavaDsl.java
 
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInJavaDsl.java
new file mode 100644
index 0000000..e7daf61
--- /dev/null
+++ 
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInJavaDsl.java
@@ -0,0 +1,130 @@
+/*
+ * 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.camel422_1;
+
+import org.apache.camel.upgrade.AbstractCamelJavaVisitor;
+import org.apache.camel.upgrade.RecipesUtil;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.TypeUtils;
+
+import java.util.Collections;
+import java.util.regex.Pattern;
+
+/**
+ * Flags camel-openai {@code CamelOpenAIResponse} / {@code 
OpenAIConstants.RESPONSE} usages in Java
+ * DSL for manual review (CAMEL-24539): with {@code storeFullResponse=true}, 
embeddings,
+ * audio-transcription and audio-translation moved to their own exchange 
property, while
+ * chat-completion is unchanged. Which one applies to a given occurrence is 
not mechanically
+ * decidable in general (exchange properties cross route boundaries via error 
handlers,
+ * {@code onCompletion}, and endpoints such as {@code direct:}), so this 
recipe marks every
+ * occurrence with a comment instead of rewriting it.
+ * <p>
+ * Comments are attached only to literal/field-access argument nodes, never to 
a method invocation
+ * that is itself part of a fluent chain: OpenRewrite prints an invocation's 
own prefix before its
+ * whole {@code select} subtree, so a comment on a chain link renders before 
the start of the chain
+ * rather than next to that link.
+ */
+public class FlagOpenAIFullResponsePropertyInJavaDsl extends Recipe {
+
+    static final String WARNING_COMMENT
+            = " CAMEL-24539 (Camel 4.22.1): with storeFullResponse=true, 
embeddings/audio-transcription/audio-translation "
+              + "now use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 "
+              + "instead of CamelOpenAIResponse; chat-completion is unchanged. 
Verify which operation this refers to and update "
+              + "the property name manually if needed.";
+
+    @Override
+    public String getDisplayName() {
+        return "Flag camel-openai CamelOpenAIResponse property in Java DSL";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Adds a review comment wherever CamelOpenAIResponse or 
OpenAIConstants.RESPONSE is used, since whether it " +
+               "should become 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 " +
+               "or stay CamelOpenAIResponse cannot be decided statically.";
+    }
+
+    @Override
+    public TreeVisitor<?, ExecutionContext> getVisitor() {
+        return RecipesUtil.newVisitor(new FlagVisitor());
+    }
+
+    private static class FlagVisitor extends AbstractCamelJavaVisitor {
+        private static final String OLD_PROPERTY_NAME = "CamelOpenAIResponse";
+        private static final String OPENAI_CONSTANTS_FQN = 
"org.apache.camel.component.openai.OpenAIConstants";
+
+        // ${exchangeProperty.CamelOpenAIResponse}, 
${exchangeProperty[CamelOpenAIResponse]},
+        // ${exchangeProperty.CamelOpenAIResponse.someOgnl}, 
${exchangeProperty(CamelOpenAIResponse)},
+        // ${exchangePropertyAs(CamelOpenAIResponse, ...)} -- whole name only, 
so CamelOpenAIResponseModel etc. don't match
+        private static final Pattern SIMPLE_EXCHANGE_PROPERTY = 
Pattern.compile(
+                
"\\$\\{exchangeProperty(?:\\.CamelOpenAIResponse[.}]|\\[CamelOpenAIResponse]}|(?:As)?\\(CamelOpenAIResponse[,)])");
+
+        @Override
+        protected J.FieldAccess doVisitFieldAccess(J.FieldAccess fieldAccess, 
ExecutionContext ctx) {
+            J.FieldAccess fa = super.doVisitFieldAccess(fieldAccess, ctx);
+
+            if (referencesOpenAIConstantsResponse(fa) && 
!RecipesUtil.isCommentBeforeElement(fa, WARNING_COMMENT)) {
+                fa = 
fa.withComments(Collections.singletonList(RecipesUtil.createMultinlineComment(WARNING_COMMENT)));
+            }
+
+            return fa;
+        }
+
+        @Override
+        protected J.Literal doVisitLiteral(J.Literal literal, ExecutionContext 
ctx) {
+            J.Literal l = super.doVisitLiteral(literal, ctx);
+
+            if (!(l.getValue() instanceof String)) {
+                return l;
+            }
+            String value = (String) l.getValue();
+
+            boolean flag = OLD_PROPERTY_NAME.equals(value) || 
SIMPLE_EXCHANGE_PROPERTY.matcher(value).find();
+            if (flag && !RecipesUtil.isCommentBeforeElement(l, 
WARNING_COMMENT)) {
+                l = 
l.withComments(Collections.singletonList(RecipesUtil.createMultinlineComment(WARNING_COMMENT)));
+            }
+
+            return l;
+        }
+
+        /**
+         * True for {@code OpenAIConstants.RESPONSE}. The type may not be 
attributed (camel-openai need not
+         * be on the recipe's own classpath), so this falls back to the class 
import when there is no type.
+         */
+        private boolean referencesOpenAIConstantsResponse(J.FieldAccess fa) {
+            if (!"RESPONSE".equals(fa.getSimpleName()) || !(fa.getTarget() 
instanceof J.Identifier)) {
+                return false;
+            }
+
+            JavaType targetType = fa.getTarget().getType();
+            if (targetType != null) {
+                return TypeUtils.isOfClassType(targetType, 
OPENAI_CONSTANTS_FQN);
+            }
+
+            if (!"OpenAIConstants".equals(((J.Identifier) 
fa.getTarget()).getSimpleName())) {
+                return false;
+            }
+            J.CompilationUnit cu = 
getCursor().firstEnclosing(J.CompilationUnit.class);
+            return cu != null && cu.getImports().stream()
+                    .anyMatch(imp -> !imp.isStatic() && 
OPENAI_CONSTANTS_FQN.equals(imp.getTypeName()));
+        }
+    }
+}
diff --git 
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInXmlDsl.java
 
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInXmlDsl.java
new file mode 100644
index 0000000..6008be2
--- /dev/null
+++ 
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInXmlDsl.java
@@ -0,0 +1,129 @@
+/*
+ * 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.camel422_1;
+
+import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
+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.tree.Content;
+import org.openrewrite.xml.tree.Xml;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import static 
org.apache.camel.upgrade.camel422_1.FlagOpenAIFullResponsePropertyInJavaDsl.WARNING_COMMENT;
+
+/**
+ * Flags camel-openai {@code CamelOpenAIResponse} usages in XML DSL for manual 
review (CAMEL-24539).
+ * See {@link FlagOpenAIFullResponsePropertyInJavaDsl} for why this marks 
instead of rewriting.
+ * <p>
+ * A comment is inserted as a real {@code Xml.Comment} sibling in the parent's 
content, right before
+ * the flagged tag, rather than as raw {@code <!--...-->} text glued into the 
tag's prefix: on reparse
+ * (e.g. a second recipe run) a prefix-embedded comment turns into its own 
sibling {@code Xml.Comment}
+ * node, so a prefix-string-based idempotency check would stop seeing it and 
duplicate the comment.
+ */
+public class FlagOpenAIFullResponsePropertyInXmlDsl extends Recipe {
+
+    // A short, unique substring of WARNING_COMMENT used to detect an 
already-added comment
+    private static final String MARKER = "CAMEL-24539";
+
+    private static final String OLD_PROPERTY_NAME = "CamelOpenAIResponse";
+
+    private static final Pattern SIMPLE_EXCHANGE_PROPERTY = Pattern.compile(
+            
"\\$\\{exchangeProperty(?:\\.CamelOpenAIResponse[.}]|\\[CamelOpenAIResponse]}|(?:As)?\\(CamelOpenAIResponse[,)])");
+
+    @Override
+    public String getDisplayName() {
+        return "Flag camel-openai CamelOpenAIResponse property in XML DSL";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Adds a review comment wherever CamelOpenAIResponse is used, 
since whether it should become " +
+               
"CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 " +
+               "or stay CamelOpenAIResponse cannot be decided statically.";
+    }
+
+    @Override
+    public TreeVisitor<?, ExecutionContext> getVisitor() {
+        return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new 
FlagVisitor());
+    }
+
+    private static class FlagVisitor extends AbstractCamelXmlVisitor {
+
+        @Override
+        public Xml.Tag doVisitTag(Xml.Tag tag, ExecutionContext ctx) {
+            Xml.Tag t = super.doVisitTag(tag, ctx);
+
+            List<? extends Content> content = t.getContent();
+            if (content == null || content.isEmpty()) {
+                return t;
+            }
+
+            List<Content> newContent = null;
+            for (int i = 0; i < content.size(); i++) {
+                Content c = content.get(i);
+                if (c instanceof Xml.Tag && shouldFlag((Xml.Tag) c) && 
!hasPrecedingMarkerComment(content, i)) {
+                    if (newContent == null) {
+                        newContent = new ArrayList<>(content.subList(0, i));
+                    }
+                    
newContent.add(RecipesUtil.createXmlComment(WARNING_COMMENT).withPrefix(c.getPrefix()));
+                }
+                if (newContent != null) {
+                    newContent.add(c);
+                }
+            }
+
+            return newContent != null ? t.withContent(newContent) : t;
+        }
+
+        private static boolean hasPrecedingMarkerComment(List<? extends 
Content> content, int index) {
+            return index > 0 && content.get(index - 1) instanceof Xml.Comment
+                    && ((Xml.Comment) content.get(index - 
1)).getText().contains(MARKER);
+        }
+
+        private static boolean shouldFlag(Xml.Tag tag) {
+            boolean propertyTag = "setProperty".equals(tag.getName()) || 
"removeProperty".equals(tag.getName());
+
+            for (Xml.Attribute attr : tag.getAttributes()) {
+                String value = attr.getValueAsString();
+                if (value == null) {
+                    continue;
+                }
+                if (propertyTag && "name".equals(attr.getKeyAsString()) && 
OLD_PROPERTY_NAME.equals(value)) {
+                    return true;
+                }
+                if (SIMPLE_EXCHANGE_PROPERTY.matcher(value).find()) {
+                    return true;
+                }
+            }
+
+            if (tag.getChildren().isEmpty()) {
+                String value = tag.getValue().orElse(null);
+                if (value != null && 
SIMPLE_EXCHANGE_PROPERTY.matcher(value).find()) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+}
diff --git 
a/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInYamlDsl.java
 
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInYamlDsl.java
new file mode 100644
index 0000000..76ff6b9
--- /dev/null
+++ 
b/camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInYamlDsl.java
@@ -0,0 +1,112 @@
+/*
+ * 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.camel422_1;
+
+import org.apache.camel.upgrade.AbstractCamelYamlVisitor;
+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.yaml.tree.Yaml;
+
+import java.util.regex.Pattern;
+
+import static 
org.apache.camel.upgrade.camel422_1.FlagOpenAIFullResponsePropertyInJavaDsl.WARNING_COMMENT;
+
+/**
+ * Flags camel-openai {@code CamelOpenAIResponse} usages in YAML DSL for 
manual review (CAMEL-24539).
+ * See {@link FlagOpenAIFullResponsePropertyInJavaDsl} for why this marks 
instead of rewriting.
+ */
+public class FlagOpenAIFullResponsePropertyInYamlDsl extends Recipe {
+
+    // A short, unique substring of WARNING_COMMENT used to detect an 
already-added comment
+    private static final String MARKER = "CAMEL-24539";
+
+    private static final String OLD_PROPERTY_NAME = "CamelOpenAIResponse";
+
+    private static final Pattern SIMPLE_EXCHANGE_PROPERTY = Pattern.compile(
+            
"\\$\\{exchangeProperty(?:\\.CamelOpenAIResponse[.}]|\\[CamelOpenAIResponse]}|(?:As)?\\(CamelOpenAIResponse[,)])");
+
+    @Override
+    public String getDisplayName() {
+        return "Flag camel-openai CamelOpenAIResponse property in YAML DSL";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Adds a review comment wherever CamelOpenAIResponse is used, 
since whether it should become " +
+               
"CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 " +
+               "or stay CamelOpenAIResponse cannot be decided statically.";
+    }
+
+    @Override
+    public TreeVisitor<?, ExecutionContext> getVisitor() {
+        return Preconditions.check(RecipesUtil.camelYamlDslPrecondition(), new 
FlagVisitor());
+    }
+
+    private static class FlagVisitor extends AbstractCamelYamlVisitor {
+
+        @Override
+        protected void clearLocalCache() {
+            // Nothing to clear
+        }
+
+        @Override
+        public Yaml.Mapping.Entry doVisitMappingEntry(Yaml.Mapping.Entry 
entry, ExecutionContext ctx) {
+            Yaml.Mapping.Entry e = super.doVisitMappingEntry(entry, ctx);
+
+            if (!(e.getValue() instanceof Yaml.Scalar)) {
+                return e;
+            }
+            Yaml.Scalar scalar = (Yaml.Scalar) e.getValue();
+
+            boolean flag = ("name".equals(e.getKey().getValue()) && 
OLD_PROPERTY_NAME.equals(scalar.getValue())
+                            && isPropertyOperation())
+                           || 
SIMPLE_EXCHANGE_PROPERTY.matcher(scalar.getValue()).find();
+
+            if (flag && !e.getPrefix().contains(MARKER)) {
+                return e.withPrefix(addCommentToPrefix(e.getPrefix()));
+            }
+
+            return e;
+        }
+
+        /**
+         * Check if this entry is within a setProperty or removeProperty 
mapping.
+         */
+        private boolean isPropertyOperation() {
+            for (int i = 0; i < 10; i++) {
+                Object value = getCursor().getParent(i) != null ? 
getCursor().getParent(i).getValue() : null;
+                if (value instanceof Yaml.Mapping) {
+                    boolean hasPropertyOp = ((Yaml.Mapping) 
value).getEntries().stream()
+                            .anyMatch(e -> 
"setProperty".equals(e.getKey().getValue()) || 
"removeProperty".equals(e.getKey().getValue()));
+                    if (hasPropertyOp) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        private static String addCommentToPrefix(String prefix) {
+            int lastNewline = prefix.lastIndexOf('\n');
+            String indent = lastNewline >= 0 ? prefix.substring(lastNewline + 
1) : "";
+            return prefix + "#" + WARNING_COMMENT + "\n" + indent;
+        }
+    }
+}
diff --git 
a/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.1.yaml 
b/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.1.yaml
new file mode 100644
index 0000000..9fe21c5
--- /dev/null
+++ b/camel-upgrade-recipes/src/main/resources/META-INF/rewrite/4.22.1.yaml
@@ -0,0 +1,59 @@
+#
+# 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.
+#
+
+#####
+# Rules coming from 
https://camel.apache.org/manual/camel-4x-upgrade-guide-4_22.html
+# Specifically changes introduced in 4.22.1 (upgrading from 4.22.0 to 4.22.1)
+#
+# This patch is not yet referenced from any other recipe: there is no 
4.23.yaml on this
+# branch to chain it from (see RECIPE-CONVENTIONS.md), and the 4.22 LTS 
aggregate is tracked
+# separately (https://github.com/apache/camel-upgrade-recipes/issues/129). Run 
it directly
+# with 
-Drewrite.activeRecipes=org.apache.camel.upgrade.camel422_1.CamelMigrationRecipe
 until
+# one of those exists.
+#####
+
+#####
+# Update the Camel project from 4.22.0 to 4.22.1
+#####
+---
+type: specs.openrewrite.org/v1beta/recipe
+name: org.apache.camel.upgrade.camel422_1.CamelMigrationRecipe
+displayName: Migrates `camel 4.22.0` application to `camel 4.22.1`
+description: Migrates `camel 4.22.0` application to `camel 4.22.1`.
+recipeList:
+  - org.apache.camel.upgrade.camel422_1.flagOpenAIFullResponseProperty
+---
+## 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#camel-openai-1
+type: specs.openrewrite.org/v1beta/recipe
+name: org.apache.camel.upgrade.camel422_1.flagOpenAIFullResponseProperty
+displayName: Flag camel-openai CamelOpenAIResponse property for manual review 
(CAMEL-24539)
+description: >-
+  With storeFullResponse=true, the embeddings, audio-transcription and 
audio-translation camel-openai
+  operations now store their full response under an operation-specific 
exchange property instead of the
+  shared CamelOpenAIResponse property (chat-completion is unchanged). Which 
one applies to a given
+  CamelOpenAIResponse/OpenAIConstants.RESPONSE occurrence is not mechanically 
decidable in general -
+  exchange properties cross route boundaries via error handlers, onCompletion 
and endpoints such as
+  direct: - so this recipe adds a review comment at every occurrence instead 
of rewriting it. Only
+  applies if the camel-openai dependency is present.
+preconditions:
+  - org.openrewrite.java.dependencies.search.ModuleHasDependency:
+      groupIdPattern: org.apache.camel
+      artifactIdPattern: camel-openai
+recipeList:
+  - org.apache.camel.upgrade.camel422_1.FlagOpenAIFullResponsePropertyInJavaDsl
+  - org.apache.camel.upgrade.camel422_1.FlagOpenAIFullResponsePropertyInXmlDsl
+  - org.apache.camel.upgrade.camel422_1.FlagOpenAIFullResponsePropertyInYamlDsl
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..32df9e4 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
@@ -63,7 +63,8 @@ public class CamelTestUtil {
         v4_19(4, 19, 0),
         v4_20(4, 20, 0),
         v4_21(4, 21, 0),
-        v4_22(4, 22, 0);
+        v4_22(4, 22, 0),
+        v4_22_1(4, 22, 1, true);
 
         private int major;
         private int minor;
diff --git 
a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate422_1Test.java
 
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate422_1Test.java
new file mode 100644
index 0000000..16c2151
--- /dev/null
+++ 
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate422_1Test.java
@@ -0,0 +1,296 @@
+/*
+ * 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;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+import org.openrewrite.test.TypeValidation;
+
+import static org.openrewrite.java.Assertions.java;
+import static org.openrewrite.java.Assertions.mavenProject;
+import static org.openrewrite.xml.Assertions.xml;
+import static org.openrewrite.yaml.Assertions.yaml;
+
+/**
+ * Tests for migrating from Camel 4.22.0 to 4.22.1 (CAMEL-24539, camel-openai).
+ * <p>
+ * Whether a given CamelOpenAIResponse occurrence should become the 
embeddings/audio-transcription/
+ * audio-translation property, or stay CamelOpenAIResponse (chat-completion), 
is not mechanically
+ * decidable in general -- see {@code 
org.apache.camel.upgrade.camel422_1.FlagOpenAIFullResponsePropertyInJavaDsl}
+ * for why. So the recipe flags every occurrence with a review comment instead 
of rewriting it.
+ */
+public class CamelUpdate422_1Test implements RewriteTest {
+
+    @Override
+    public void defaults(RecipeSpec spec) {
+        CamelTestUtil.recipe(spec, CamelTestUtil.CamelVersion.v4_22_1)
+                
.parser(CamelTestUtil.parserFromClasspath(CamelTestUtil.CamelVersion.v4_22, 
"camel-api",
+                        "camel-core-model", "camel-support", "camel-openai"))
+                .typeValidationOptions(TypeValidation.none());
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, 
matches = ".+")
+    void javaDslFlagsOccurrencesAndLeavesLookalikesAndUnrelatedConstantAlone() 
{
+        //language=java
+        rewriteRun(
+                mavenProject("test-openai",
+                        CamelTestUtil.pomXmlSpec("camel-openai", 
CamelTestUtil.CamelVersion.v4_22),
+                        java(
+                        """
+                        import org.apache.camel.builder.RouteBuilder;
+                        import 
org.apache.camel.component.openai.OpenAIConstants;
+
+                        class Test extends RouteBuilder {
+                            public void configure() {
+                                from("direct:openai")
+                                    .setProperty("CamelOpenAIResponseModel", 
constant("keep-model"))
+                                    .process(exchange -> {
+                                        Object response = 
exchange.getProperty("CamelOpenAIResponse", Object.class);
+                                        
exchange.setProperty("CamelOpenAIResponse", response);
+                                    })
+                                    .setProperty(OpenAIConstants.RESPONSE, 
exchangeProperty("CamelOpenAIResponse"))
+                                    
.setBody(simple("${exchangeProperty.CamelOpenAIResponse.data}"))
+                                    .removeProperty("CamelOpenAIResponseId")
+                                    .removeProperty("CamelOpenAIResponse");
+                            }
+                        }
+                        """,
+                        """
+                        import org.apache.camel.builder.RouteBuilder;
+                        import 
org.apache.camel.component.openai.OpenAIConstants;
+
+                        class Test extends RouteBuilder {
+                            public void configure() {
+                                from("direct:openai")
+                                    .setProperty("CamelOpenAIResponseModel", 
constant("keep-model"))
+                                    .process(exchange -> {
+                                        Object response = 
exchange.getProperty(/* CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if 
needed.*/"CamelOpenAIResponse", Object.class);
+                                        exchange.setProperty(/* CAMEL-24539 
(Camel 4.22.1): with storeFullResponse=true, 
embeddings/audio-transcription/audio-translation now use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if 
needed.*/"CamelOpenAIResponse", response);
+                                    })
+                                    .setProperty(/* CAMEL-24539 (Camel 
4.22.1): with storeFullResponse=true, 
embeddings/audio-transcription/audio-translation now use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if 
needed.*/OpenAIConstants.RESPONSE, exchangeProperty(/* CAMEL-24539 (Camel 
4.22.1) [...]
+                                    .setBody(simple(/* CAMEL-24539 (Camel 
4.22.1): with storeFullResponse=true, 
embeddings/audio-transcription/audio-translation now use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if 
needed.*/"${exchangeProperty.CamelOpenAIResponse.data}"))
+                                    .removeProperty("CamelOpenAIResponseId")
+                                    .removeProperty(/* CAMEL-24539 (Camel 
4.22.1): with storeFullResponse=true, 
embeddings/audio-transcription/audio-translation now use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if 
needed.*/"CamelOpenAIResponse");
+                            }
+                        }
+                        """
+                        ),
+                        // A user's own unrelated OpenAIConstants (no 
camel-openai import) must never be flagged.
+                        java(
+                        """
+                        package com.example;
+
+                        public final class OpenAIConstants {
+                            public static final String RESPONSE = 
"SomeUnrelatedConstant";
+                        }
+                        """
+                        ),
+                        java(
+                        """
+                        package com.example;
+
+                        import org.apache.camel.builder.RouteBuilder;
+
+                        class UnrelatedRoute extends RouteBuilder {
+                            public void configure() {
+                                from("direct:other")
+                                    .setProperty(OpenAIConstants.RESPONSE, 
constant("x"));
+                            }
+                        }
+                        """
+                        )
+                )
+        );
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, 
matches = ".+")
+    void javaDslWithoutCamelOpenAIDependencyIsUnchanged() {
+        //language=java
+        rewriteRun(
+                mavenProject("test-no-openai",
+                        CamelTestUtil.pomXmlSpec("camel-core", 
CamelTestUtil.CamelVersion.v4_22),
+                        java(
+                        """
+                        import org.apache.camel.builder.RouteBuilder;
+
+                        class Test extends RouteBuilder {
+                            public void configure() {
+                                from("direct:openai")
+                                    .setProperty("CamelOpenAIResponse", 
exchangeProperty("CamelOpenAIResponse"));
+                            }
+                        }
+                        """
+                )
+                )
+        );
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, 
matches = ".+")
+    void javaDslIsIdempotent() {
+        //language=java
+        rewriteRun(
+                mavenProject("test-openai-idempotent",
+                        CamelTestUtil.pomXmlSpec("camel-openai", 
CamelTestUtil.CamelVersion.v4_22),
+                        java(
+                        """
+                        import org.apache.camel.builder.RouteBuilder;
+
+                        class Test extends RouteBuilder {
+                            public void configure() {
+                                from("direct:openai")
+                                    .setProperty(/* CAMEL-24539 (Camel 
4.22.1): with storeFullResponse=true, 
embeddings/audio-transcription/audio-translation now use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if 
needed.*/"CamelOpenAIResponse", exchangeProperty(/* CAMEL-24539 (Camel 4.22.1): 
w [...]
+                            }
+                        }
+                        """
+                )
+                )
+        );
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, 
matches = ".+")
+    void yamlDslFlagsOccurrencesAndLeavesLookalikesAlone() {
+        //language=yaml
+        rewriteRun(
+                mavenProject("test-openai-yaml",
+                        CamelTestUtil.pomXmlSpec("camel-openai", 
CamelTestUtil.CamelVersion.v4_22),
+                        yaml(
+                        """
+                        - route:
+                            from:
+                              uri: "direct:openai"
+                            steps:
+                              - setProperty:
+                                  name: CamelOpenAIResponseModel
+                                  constant: keep-model
+                              - setProperty:
+                                  name: CamelOpenAIResponse
+                                  simple: 
"${exchangeProperty.CamelOpenAIResponse}"
+                              - setBody:
+                                  simple: 
"${exchangeProperty.CamelOpenAIResponse.data}"
+                        """,
+                        """
+                        - route:
+                            from:
+                              uri: "direct:openai"
+                            steps:
+                              - setProperty:
+                                  name: CamelOpenAIResponseModel
+                                  constant: keep-model
+                              - setProperty:
+                                  # CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if needed.
+                                  name: CamelOpenAIResponse
+                                  # CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if needed.
+                                  simple: 
"${exchangeProperty.CamelOpenAIResponse}"
+                              - setBody:
+                                  # CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if needed.
+                                  simple: 
"${exchangeProperty.CamelOpenAIResponse.data}"
+                        """
+                )
+                )
+        );
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, 
matches = ".+")
+    void yamlDslIsIdempotent() {
+        //language=yaml
+        rewriteRun(
+                mavenProject("test-openai-yaml-idempotent",
+                        CamelTestUtil.pomXmlSpec("camel-openai", 
CamelTestUtil.CamelVersion.v4_22),
+                        yaml(
+                        """
+                        - route:
+                            from:
+                              uri: "direct:openai"
+                            steps:
+                              - setProperty:
+                                  # CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if needed.
+                                  name: CamelOpenAIResponse
+                                  # CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if needed.
+                                  simple: 
"${exchangeProperty.CamelOpenAIResponse}"
+                        """
+                )
+                )
+        );
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, 
matches = ".+")
+    void xmlDslFlagsOccurrencesAndLeavesLookalikesAlone() {
+        //language=xml
+        rewriteRun(
+                mavenProject("test-openai-xml",
+                        CamelTestUtil.pomXmlSpec("camel-openai", 
CamelTestUtil.CamelVersion.v4_22),
+                        xml(
+                        """
+                        <route xmlns="http://camel.apache.org/schema/spring";>
+                            <from uri="direct:openai"/>
+                            <setProperty name="CamelOpenAIResponseModel">
+                                <constant>keep-model</constant>
+                            </setProperty>
+                            <setProperty name="CamelOpenAIResponse">
+                                
<simple>${exchangeProperty.CamelOpenAIResponse}</simple>
+                            </setProperty>
+                        </route>
+                        """,
+                        """
+                        <route xmlns="http://camel.apache.org/schema/spring";>
+                            <from uri="direct:openai"/>
+                            <setProperty name="CamelOpenAIResponseModel">
+                                <constant>keep-model</constant>
+                            </setProperty>
+                            <!-- CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if needed.-->
+                            <setProperty name="CamelOpenAIResponse">
+                                <!-- CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if needed.-->
+                                
<simple>${exchangeProperty.CamelOpenAIResponse}</simple>
+                            </setProperty>
+                        </route>
+                        """
+                )
+                )
+        );
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, 
matches = ".+")
+    void xmlDslIsIdempotent() {
+        //language=xml
+        rewriteRun(
+                mavenProject("test-openai-xml-idempotent",
+                        CamelTestUtil.pomXmlSpec("camel-openai", 
CamelTestUtil.CamelVersion.v4_22),
+                        xml(
+                        """
+                        <route xmlns="http://camel.apache.org/schema/spring";>
+                            <from uri="direct:openai"/>
+                            <!-- CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if needed.-->
+                            <setProperty name="CamelOpenAIResponse">
+                                <!-- CAMEL-24539 (Camel 4.22.1): with 
storeFullResponse=true, embeddings/audio-transcription/audio-translation now 
use 
CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse
 instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which 
operation this refers to and update the property name manually if needed.-->
+                                
<simple>${exchangeProperty.CamelOpenAIResponse}</simple>
+                            </setProperty>
+                        </route>
+                        """
+                )
+                )
+        );
+    }
+}
diff --git a/release_notes.adoc b/release_notes.adoc
index d523aa6..f0af1bd 100644
--- a/release_notes.adoc
+++ b/release_notes.adoc
@@ -1,5 +1,80 @@
 = Camel Upgrade Recipes - Release notes
 
+== 4.22.1
+
+=== Summary
+
+This is a release supporting Camel, Camel Quarkus and Camel Spring Boot 4.22.1 
LTS with the required upgrade recipes (described by the 
https://camel.apache.org/manual/camel-4x-upgrade-guide-4_22.html[migration 
guide]).
+
+This recipe is not yet chained from `latest.yaml` or a Spring Boot 
`CamelMigrationRecipe`: per `RECIPE-CONVENTIONS.md`, a patch recipe is 
referenced from the *next main-version* yaml and, optionally, an LTS aggregate, 
and neither exists yet for the 4.22 line (a 4.22 LTS aggregate is tracked in 
https://github.com/apache/camel-upgrade-recipes/issues/129[#129]). Run it 
directly with 
`-Drewrite.activeRecipes=org.apache.camel.upgrade.camel422_1.CamelMigrationRecipe`
 until one of those exists.
+
+Only one 4.22.1 change is covered at all: the camel-openai `storeFullResponse` 
property change (CAMEL-24539), and it cannot be migrated mechanically -- see 
below. Everything else backported into 4.22.1 is either a 
secure-default/runtime behaviour change or a deprecation with no replacement 
yet, and needs manual review.
+
+=== Migration coverage
+
+The following table lists migration topics and indicates the level of coverage 
(full, partial, or not covered), along with additional comments.
+
+[%autowidth,stripes=hover]
+|===
+| Migration | Coverage | Comment
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#camel-openai-1[camel-openai:
 `storeFullResponse` properties]
+| ⚠️ Partial
+| Which of 
`CamelOpenAIEmbeddingsResponse`/`CamelOpenAIAudioTranscriptionResponse`/`CamelOpenAIAudioTranslationResponse`
 (or unchanged `CamelOpenAIResponse` for chat-completion) an occurrence should 
become is not mechanically decidable -- exchange properties cross route 
boundaries through error handlers, `onCompletion` and endpoints such as 
`direct:`. Rather than risk a wrong rewrite, every `CamelOpenAIResponse` / 
`OpenAIConstants.RESPONSE` occurrence (and the matching Simple-syntax form [...]
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L16[camel-hazelcast:
 ReplicatedHazelcastAggregationRepository applies the default serialization 
filter]
+| ❌ None
+| Runtime security default now also applied to the repository's 
self-bootstrapped `HazelcastInstance`/`ClientConfig`. Applications aggregating 
classes outside the default allow-list without supplying their own 
`hazelcastInstance`/`ClientConfig` must provide a 
`JavaSerializationFilterConfig`. Manual review required.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L36[camel-exec:
 `allowControlHeaders` is `insecure:dev`]
+| ❌ None
+| `allowControlHeaders=true` now fails to start under 
`camel.main.profile=prod` unless `camel.security.insecureDevPolicy` is relaxed. 
Manual configuration required.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L48[camel-azure-storage-blob/datalake
 and camel-google-storage: download symlink containment]
+| ❌ None
+| Local downloads through a symbolic link resolving outside the configured 
directory (`fileDir` / `downloadFileName`) are now rejected as a security fix; 
legitimate nested paths keep working. No migration needed.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L62[camel-jgroups:
 consumer deserialization filter]
+| ❌ None
+| The consumer now applies a JEP-290 `java.io.ObjectInputFilter` (the shared 
Camel default allow-list, or `jdk.serialFilter` when set) to the deserialized 
message body. Routes exchanging custom classes over the cluster must widen it 
with the new `deserializationFilter` endpoint option. Manual configuration 
required.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L89[camel-tika:
 `tikaConfig` deprecation]
+| ❌ None
+| `tikaConfig`/`tikaConfigUri` deprecated for removal in Camel 4.23 (Tika 4 
drops `TikaConfig` and XML configuration). No replacement option exists yet, so 
no migration is possible until 4.23.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L1829[camel-support:
 `BackgroundTask` cancellation]
+| ❌ None
+| `BackgroundTask.schedule`'s returned `Future` now correctly reports 
`isCancelled()==true` once the task completes, instead of the repeating 
schedule staying armed indefinitely. Behaviour fix, no migration needed.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L1837[camel-master:
 `backOffMaxAttempts`]
+| ❌ None
+| `backOffMaxAttempts` now correctly bounds consumer start retries instead of 
being cut short by the default five second budget. Runtime behaviour fix, no 
migration needed.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L1844[camel-core:
 REST client request validation and binary bodies]
+| ❌ None
+| With `clientRequestValidation` enabled, a required REST body is no longer 
coerced to `String`, so binary bodies (e.g. `application/octet-stream`) keep 
their original type. Bug fix, no migration needed.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L1851[camel-infinispan:
 aggregation repository recovery]
+| ❌ None
+| `InfinispanAggregationRepository` now keeps completed-but-unconfirmed 
exchanges available for recovery instead of losing them; recovery now correctly 
targets exchanges that failed after completion rather than aggregations still 
in progress. Runtime behaviour fix, no migration needed.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L1869[camel-servlet/camel-jetty:
 multipart upload whitelist and attachment header]
+| ❌ None
+| `fileNameExtWhitelist` is now checked against the submitted file name 
instead of the multipart field name (`camel-servlet`), and is now enforced at 
all (`camel-jetty`); the `camel-jetty` attachment header is now exposed under 
the multipart field name. Security fix — review the configured extension list 
before upgrading.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L1895[camel-vertx-http:
 REST producer outbound header filter]
+| ❌ None
+| The REST producer now actually applies its outbound header filter (it 
previously consulted the inbound filter), so common HTTP headers such as 
`Content-Length`/`Host`/`Connection` are no longer copied onto the outgoing 
request unless configured. Manual review required if a route relied on one of 
those headers reaching the wire.
+
+| 
https://github.com/apache/camel/blob/camel-4.22.1/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc#L1914[camel-tensorflow-serving:
 `Target`/`Credentials` headers deprecated]
+| ❌ None
+| `CamelTensorFlowServingTarget`/`CamelTensorFlowServingCredentials` are 
deprecated but were already never read by the component (the gRPC channel is 
built once from the endpoint configuration), so no migration is needed — use 
the `target`/`credentials` endpoint options instead.
+
+| 
https://github.com/apache/camel/blob/main/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc[Security-default
 backports documented only in the 4.23 guide]
+| ❌ None
+| Runtime/secure-default changes already effective as of 4.22.1 but only 
written up in the (unreleased) 4.23 guide: crypto-pgp 
`requireIntegrityProtection`, mllp `logPhi`, knative trust-all/`muteException`, 
mina/cxf/grpc `muteException`, http credential scope and OAuth2 token cache, 
http placeholders in `CamelHttpUri`, jetty/vertx CORS credentials, 
platform-http proxy exact path and header echo, netty-http security constraint, 
oauth `state`, shiro, keycloak issuer, xpath DOCTYPE, tika me [...]
+|===
+
 == 4.22.0
 
 === Summary

Reply via email to