This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit 51f63c55f2565f0541d28453d7fba8432441c848
Author: jiriOndrusek-agent <[email protected]>
AuthorDate: Tue Oct 6 13:36:27 2026 +0000

    Fixes #9269. Add camel-quarkus-odata extension
    
    Native supported extension for the Camel 4.23 producer-only odata
    component. Preview status, as per the Camel component metadata.
    
    Tests use routes and replay WireMock recordings of the public TripPin
    OData V4 service. WireMock test support: added a customizeRecordSpec
    hook to capture the If-Match request header in recordings, and log
    when the real backend is used.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 catalog/pom.xml                                    |  13 ++
 docs/modules/ROOT/examples/components/odata.yml    |  13 ++
 docs/modules/ROOT/nav.adoc                         |   1 +
 .../ROOT/pages/reference/extensions/odata.adoc     |  52 ++++++++
 extensions/odata/deployment/pom.xml                |  67 ++++++++++
 .../component/odata/deployment/OdataProcessor.java |  29 ++++
 extensions/odata/pom.xml                           |  39 ++++++
 extensions/odata/runtime/pom.xml                   | 106 +++++++++++++++
 .../main/resources/META-INF/quarkus-extension.yaml |  36 +++++
 extensions/pom.xml                                 |   1 +
 .../WireMockTestResourceLifecycleManager.java      |  15 ++-
 integration-tests/odata/README.adoc                |  20 +++
 integration-tests/odata/pom.xml                    | 134 +++++++++++++++++++
 .../quarkus/component/odata/it/OdataResource.java  | 133 +++++++++++++++++++
 .../quarkus/component/odata/it/OdataRoutes.java    |  51 +++++++
 .../camel/quarkus/component/odata/it/OdataIT.java  |  24 ++++
 .../quarkus/component/odata/it/OdataTest.java      | 147 +++++++++++++++++++++
 .../component/odata/it/OdataTestResource.java      |  85 ++++++++++++
 ...ports-759ec2a4-1130-49cb-a9f7-4dc3e2ffaa8e.json |  38 ++++++
 ...ports-944a9fd8-333b-49f1-a957-235ec6e639e0.json |  43 ++++++
 ...eople-4e185b35-a9cf-411e-a0b0-60fded5574bd.json |  32 +++++
 ...eople-700f2ba3-4d9a-4b55-ac9d-10a7795175bc.json |  32 +++++
 ...black-1cc96092-8059-47c7-9be5-86783bc3b7e8.json |  34 +++++
 ...black-45d7ae56-29a8-4dec-a7aa-ccd02f45518b.json |  34 +++++
 ...black-4a219113-8278-4551-8391-a643d7182bf2.json |  29 ++++
 ...black-4d0f05be-da4e-43e2-b031-0b3a1dc25e30.json |  28 ++++
 ...black-659d8317-21c0-49fb-b61e-373b3408710c.json |  30 +++++
 ...icerw-94a37fd4-2e39-497c-88e0-00de259ac10b.json |  23 ++++
 integration-tests/pom.xml                          |   1 +
 poms/bom/pom.xml                                   |  15 +++
 poms/bom/src/main/generated/flattened-full-pom.xml |  15 +++
 .../src/main/generated/flattened-reduced-pom.xml   |  15 +++
 .../generated/flattened-reduced-verbose-pom.xml    |  15 +++
 tooling/scripts/test-categories.yaml               |   1 +
 34 files changed, 1349 insertions(+), 2 deletions(-)

diff --git a/catalog/pom.xml b/catalog/pom.xml
index 20b17da140..ff27d3ae63 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -3152,6 +3152,19 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-odata</artifactId>
+            <version>${project.version}</version>
+            <type>pom</type>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-ognl</artifactId>
diff --git a/docs/modules/ROOT/examples/components/odata.yml 
b/docs/modules/ROOT/examples/components/odata.yml
new file mode 100644
index 0000000000..fa5c9c72c7
--- /dev/null
+++ b/docs/modules/ROOT/examples/components/odata.yml
@@ -0,0 +1,13 @@
+# Do not edit directly!
+# This file was generated by 
camel-quarkus-maven-plugin:update-extension-doc-page
+cqArtifactId: camel-quarkus-odata
+cqArtifactIdBase: odata
+cqNativeSupported: true
+cqStatus: Stable
+cqDeprecated: false
+cqJvmSince: 4.0.0
+cqNativeSince: 4.0.0
+cqCamelPartName: odata
+cqCamelPartTitle: OData
+cqCamelPartDescription: Camel OData Component
+cqExtensionPageTitle: OData
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
index 86e6498728..a3fe6a1399 100644
--- a/docs/modules/ROOT/nav.adoc
+++ b/docs/modules/ROOT/nav.adoc
@@ -256,6 +256,7 @@
 *** xref:reference/extensions/netty-http.adoc[Netty HTTP]
 *** xref:reference/extensions/oaipmh.adoc[OAI-PMH]
 *** xref:reference/extensions/ocsf.adoc[OCSF]
+*** xref:reference/extensions/odata.adoc[OData]
 *** xref:reference/extensions/ognl.adoc[OGNL]
 *** xref:reference/extensions/milo.adoc[OPC UA Browser]
 *** xref:reference/extensions/oauth.adoc[Oauth]
diff --git a/docs/modules/ROOT/pages/reference/extensions/odata.adoc 
b/docs/modules/ROOT/pages/reference/extensions/odata.adoc
new file mode 100644
index 0000000000..e691a1dae0
--- /dev/null
+++ b/docs/modules/ROOT/pages/reference/extensions/odata.adoc
@@ -0,0 +1,52 @@
+// Do not edit directly!
+// This file was generated by 
camel-quarkus-maven-plugin:update-extension-doc-page
+[id="extensions-odata"]
+= OData
+:linkattrs:
+:cq-artifact-id: camel-quarkus-odata
+:cq-native-supported: true
+:cq-status: Preview
+:cq-status-deprecation: Preview
+:cq-description: Camel OData Component
+:cq-deprecated: false
+:cq-jvm-since: 4.0.0
+:cq-native-since: 4.0.0
+
+ifeval::[{doc-show-badges} == true]
+[.badges]
+[.badge-key]##JVM since##[.badge-supported]##4.0.0## [.badge-key]##Native 
since##[.badge-supported]##4.0.0##
+endif::[]
+
+Camel OData Component
+
+[id="extensions-odata-whats-inside"]
+== What's inside
+
+* xref:{cq-camel-components}::odata-component.adoc[OData component], URI 
syntax: `odata:httpUri`
+
+Please refer to the above link for usage and configuration details.
+
+[id="extensions-odata-maven-coordinates"]
+== Maven coordinates
+
+https://{link-quarkus-code-generator}/?extension-search=camel-quarkus-odata[Create
 a new project with this extension on {link-quarkus-code-generator}, 
window="_blank"]
+
+Or add the coordinates to your existing project:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel.quarkus</groupId>
+    <artifactId>camel-quarkus-odata</artifactId>
+</dependency>
+----
+ifeval::[{doc-show-user-guide-link} == true]
+Check the xref:user-guide/index.adoc[User guide] for more information about 
writing Camel Quarkus applications.
+endif::[]
+
+[id="extensions-odata-ssl-in-native-mode"]
+== SSL in native mode
+
+This extension auto-enables SSL support in native mode. Hence you do not need 
to add
+`quarkus.ssl.native=true` to your `application.properties` yourself. See also
+https://quarkus.io/guides/native-and-ssl[Quarkus SSL guide].
diff --git a/extensions/odata/deployment/pom.xml 
b/extensions/odata/deployment/pom.xml
new file mode 100644
index 0000000000..1a31a08175
--- /dev/null
+++ b/extensions/odata/deployment/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-odata-parent</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-quarkus-odata-deployment</artifactId>
+    <name>Camel Quarkus :: OData :: Deployment</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-core-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-http-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-odata</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>io.quarkus</groupId>
+                            
<artifactId>quarkus-extension-processor</artifactId>
+                            <version>${quarkus.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git 
a/extensions/odata/deployment/src/main/java/org/apache/camel/quarkus/component/odata/deployment/OdataProcessor.java
 
b/extensions/odata/deployment/src/main/java/org/apache/camel/quarkus/component/odata/deployment/OdataProcessor.java
new file mode 100644
index 0000000000..01a75f2479
--- /dev/null
+++ 
b/extensions/odata/deployment/src/main/java/org/apache/camel/quarkus/component/odata/deployment/OdataProcessor.java
@@ -0,0 +1,29 @@
+/*
+ * 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.quarkus.component.odata.deployment;
+
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+
+class OdataProcessor {
+    private static final String FEATURE = "camel-odata";
+
+    @BuildStep
+    FeatureBuildItem feature() {
+        return new FeatureBuildItem(FEATURE);
+    }
+}
diff --git a/extensions/odata/pom.xml b/extensions/odata/pom.xml
new file mode 100644
index 0000000000..39bccc0e15
--- /dev/null
+++ b/extensions/odata/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-extensions</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-quarkus-odata-parent</artifactId>
+    <name>Camel Quarkus :: OData</name>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>deployment</module>
+        <module>runtime</module>
+    </modules>
+</project>
diff --git a/extensions/odata/runtime/pom.xml b/extensions/odata/runtime/pom.xml
new file mode 100644
index 0000000000..589fddf405
--- /dev/null
+++ b/extensions/odata/runtime/pom.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-odata-parent</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-quarkus-odata</artifactId>
+    <name>Camel Quarkus :: OData :: Runtime</name>
+    <description>Camel OData Component</description>
+
+    <properties>
+        <quarkus.metadata.status>preview</quarkus.metadata.status>
+        <camel.quarkus.jvmSince>4.0.0</camel.quarkus.jvmSince>
+        <camel.quarkus.nativeSince>4.0.0</camel.quarkus.nativeSince>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-odata</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>io.quarkus</groupId>
+                <artifactId>quarkus-extension-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>io.quarkus</groupId>
+                            
<artifactId>quarkus-extension-processor</artifactId>
+                            <version>${quarkus.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+
+    <profiles>
+        <profile>
+            <id>full</id>
+            <activation>
+                <property>
+                    <name>!quickly</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.camel.quarkus</groupId>
+                        <artifactId>camel-quarkus-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>update-extension-doc-page</id>
+                                <goals>
+                                    <goal>update-extension-doc-page</goal>
+                                </goals>
+                                <phase>process-classes</phase>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git 
a/extensions/odata/runtime/src/main/resources/META-INF/quarkus-extension.yaml 
b/extensions/odata/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000000..3ee75b7ebd
--- /dev/null
+++ 
b/extensions/odata/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+
+# This is a generated file. Do not edit directly!
+# To re-generate, run the following command from the top level directory:
+#
+#   mvn -N cq:update-quarkus-metadata
+#
+---
+name: "Camel OData"
+description: "Camel OData Component"
+metadata:
+  icon-url: 
"https://raw.githubusercontent.com/apache/camel-website/main/antora-ui-camel/src/img/logo-d.svg";
+  sponsor: "Apache Software Foundation"
+  guide: 
"https://camel.apache.org/camel-quarkus/latest/reference/extensions/odata.html";
+  categories:
+  - "integration"
+  status: "preview"
+  integrates:
+    - name: "Camel"
+      artifact: "org.apache.camel:camel-base"
+      version: "${camel.version}"
\ No newline at end of file
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 9478ec2b8c..5a082771a6 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -227,6 +227,7 @@
         <module>oauth</module>
         <module>observability-services</module>
         <module>ocsf</module>
+        <module>odata</module>
         <module>ognl</module>
         <module>olingo4</module>
         <module>once</module>
diff --git 
a/integration-tests-support/wiremock/src/main/java/org/apache/camel/quarkus/test/wiremock/WireMockTestResourceLifecycleManager.java
 
b/integration-tests-support/wiremock/src/main/java/org/apache/camel/quarkus/test/wiremock/WireMockTestResourceLifecycleManager.java
index 15a9afe5b5..49c78bba03 100644
--- 
a/integration-tests-support/wiremock/src/main/java/org/apache/camel/quarkus/test/wiremock/WireMockTestResourceLifecycleManager.java
+++ 
b/integration-tests-support/wiremock/src/main/java/org/apache/camel/quarkus/test/wiremock/WireMockTestResourceLifecycleManager.java
@@ -29,6 +29,7 @@ import com.github.tomakehurst.wiremock.WireMockServer;
 import com.github.tomakehurst.wiremock.common.ClasspathFileSource;
 import com.github.tomakehurst.wiremock.common.FileSource;
 import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
+import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder;
 import com.github.tomakehurst.wiremock.recording.RecordingStatus;
 import com.github.tomakehurst.wiremock.recording.SnapshotRecordResult;
 import com.github.tomakehurst.wiremock.stubbing.StubMapping;
@@ -65,9 +66,11 @@ public abstract class WireMockTestResourceLifecycleManager 
implements QuarkusTes
 
                 if (recordTargetBaseUrl != null) {
                     LOG.infof("Enabling WireMock recording for %s", 
recordTargetBaseUrl);
-                    server.startRecording(recordSpec()
+                    RecordSpecBuilder recordSpec = recordSpec()
                             .forTarget(recordTargetBaseUrl)
-                            .allowNonProxied(false));
+                            .allowNonProxied(false);
+                    customizeRecordSpec(recordSpec);
+                    server.startRecording(recordSpec);
                 } else {
                     throw new IllegalStateException(
                             "Must return a non-null value from 
getRecordTargetBaseUrl() in order to support WireMock recording");
@@ -82,6 +85,8 @@ public abstract class WireMockTestResourceLifecycleManager 
implements QuarkusTes
             if (server.getOptions().httpsSettings().enabled()) {
                 properties.put("wiremock.url.ssl", "https://localhost:"; + 
server.httpsPort());
             }
+        } else {
+            MockBackendUtils.logRealBackendUsed();
         }
 
         return properties;
@@ -223,6 +228,12 @@ public abstract class WireMockTestResourceLifecycleManager 
implements QuarkusTes
     protected void customizeWiremockConfiguration(WireMockConfiguration 
config) {
     }
 
+    /**
+     * Customizes the {@link RecordSpecBuilder} used in record mode. E.g. to 
capture request headers in the recorded stubs.
+     */
+    protected void customizeRecordSpec(RecordSpecBuilder recordSpec) {
+    }
+
     /**
      * Returns the subdirectory name for organizing stubs by test module.
      * If empty (default), stubs are stored in the root mappings/ directory.
diff --git a/integration-tests/odata/README.adoc 
b/integration-tests/odata/README.adoc
new file mode 100644
index 0000000000..692eb30fe2
--- /dev/null
+++ b/integration-tests/odata/README.adoc
@@ -0,0 +1,20 @@
+== Camel Quarkus OData Integration Tests
+
+By default the OData integration tests use WireMock to stub the interactions 
with the public
+https://services.odata.org/V4/TripPinServiceRW/[TripPin] OData V4 service.
+
+To run the tests against the real service, set the following environment 
variable:
+
+[source,shell]
+----
+export ODATA_BASE_URL=https://services.odata.org
+----
+
+If the WireMock stub recordings need updating, then remove the existing files 
from `src/test/resources/mappings` and run
+tests with either:
+
+System property `-Dwiremock.record=true`
+
+Or
+
+Set environment variable `WIREMOCK_RECORD=true`
diff --git a/integration-tests/odata/pom.xml b/integration-tests/odata/pom.xml
new file mode 100644
index 0000000000..09c99f40d7
--- /dev/null
+++ b/integration-tests/odata/pom.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-build-parent-it</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../../poms/build-parent-it/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-quarkus-integration-test-odata</artifactId>
+    <name>Camel Quarkus :: Integration Tests :: OData</name>
+    <description>Integration tests for Camel Quarkus OData 
extension</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-direct</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-odata</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-resteasy</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-integration-wiremock-support</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>native</id>
+            <activation>
+                <property>
+                    <name>native</name>
+                </property>
+            </activation>
+            <properties>
+                <quarkus.native.enabled>true</quarkus.native.enabled>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>virtualDependencies</id>
+            <activation>
+                <property>
+                    <name>!noVirtualDependencies</name>
+                </property>
+            </activation>
+            <dependencies>
+                <!-- The following dependencies guarantee that this module is 
built after them. You can update them by running `mvn process-resources 
-Pformat -N` from the source tree root directory -->
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-direct-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-odata-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+
+</project>
diff --git 
a/integration-tests/odata/src/main/java/org/apache/camel/quarkus/component/odata/it/OdataResource.java
 
b/integration-tests/odata/src/main/java/org/apache/camel/quarkus/component/odata/it/OdataResource.java
new file mode 100644
index 0000000000..be08011e44
--- /dev/null
+++ 
b/integration-tests/odata/src/main/java/org/apache/camel/quarkus/component/odata/it/OdataResource.java
@@ -0,0 +1,133 @@
+/*
+ * 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.quarkus.component.odata.it;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.PATCH;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.MediaType;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.odata.ODataConstants;
+import org.apache.camel.http.base.HttpOperationFailedException;
+import org.apache.camel.util.json.JsonObject;
+
+@Path("/odata")
+@ApplicationScoped
+public class OdataResource {
+
+    @Inject
+    ProducerTemplate producerTemplate;
+
+    @Path("/airports")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public String readAirports(@QueryParam("filter") String filter, 
@QueryParam("select") String select) {
+        Map<String, Object> headers = new HashMap<>();
+        if (filter != null) {
+            headers.put(ODataConstants.FILTER, filter);
+        }
+        if (select != null) {
+            headers.put(ODataConstants.SELECT, select);
+        }
+        return request("direct:readAirports", null, headers);
+    }
+
+    @Path("/people/{userName}")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public String readPerson(@PathParam("userName") String userName) {
+        return request("direct:readPerson", null, keyHeaders(userName, null));
+    }
+
+    @Path("/people")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public String createPerson(String person) {
+        return request("direct:createPerson", person, new HashMap<>());
+    }
+
+    @Path("/people/map")
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    public String createPersonFromMap(@QueryParam("userName") String userName, 
@QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName) {
+        Map<String, Object> person = Map.of("UserName", userName, "FirstName", 
firstName, "LastName", lastName);
+        return request("direct:createPersonFromMap", person, new HashMap<>());
+    }
+
+    @Path("/people/{userName}")
+    @PATCH
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public String updatePerson(@PathParam("userName") String userName, 
@QueryParam("etag") String etag, String person) {
+        return request("direct:updatePerson", person, keyHeaders(userName, 
etag));
+    }
+
+    @Path("/people/{userName}")
+    @DELETE
+    @Produces(MediaType.APPLICATION_JSON)
+    public String deletePerson(@PathParam("userName") String userName, 
@QueryParam("etag") String etag) {
+        return request("direct:deletePerson", null, keyHeaders(userName, 
etag));
+    }
+
+    private static Map<String, Object> keyHeaders(String userName, String 
etag) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(ODataConstants.KEY, "'" + userName + "'");
+        if (etag != null) {
+            headers.put(ODataConstants.ETAG, etag);
+        }
+        return headers;
+    }
+
+    private String request(String endpointUri, Object body, Map<String, 
Object> headers) {
+        Exchange exchange = producerTemplate.request(endpointUri, e -> {
+            e.getMessage().setBody(body);
+            e.getMessage().setHeaders(headers);
+        });
+
+        JsonObject result = new JsonObject();
+        Exception exception = exchange.getException();
+        if (exception instanceof HttpOperationFailedException httpException) {
+            result.put("status", httpException.getStatusCode());
+        } else if (exception != null) {
+            throw new RuntimeCamelException(exception);
+        } else {
+            Message message = exchange.getMessage();
+            result.put("status", 
message.getHeader(Exchange.HTTP_RESPONSE_CODE));
+            result.put("etag", message.getHeader(ODataConstants.ETAG));
+            result.put("count", message.getHeader(ODataConstants.COUNT));
+            result.put("nextLink", 
message.getHeader(ODataConstants.NEXT_LINK));
+            result.put("body", message.getBody());
+        }
+        return result.toJson();
+    }
+}
diff --git 
a/integration-tests/odata/src/main/java/org/apache/camel/quarkus/component/odata/it/OdataRoutes.java
 
b/integration-tests/odata/src/main/java/org/apache/camel/quarkus/component/odata/it/OdataRoutes.java
new file mode 100644
index 0000000000..1ace1cbeae
--- /dev/null
+++ 
b/integration-tests/odata/src/main/java/org/apache/camel/quarkus/component/odata/it/OdataRoutes.java
@@ -0,0 +1,51 @@
+/*
+ * 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.quarkus.component.odata.it;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.odata.ODataConstants;
+
+public class OdataRoutes extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        // READ_SET is the default operation
+        from("direct:readAirports")
+                
.to("odata:{{odata.service.url}}/Airports?select=IcaoCode,Name&count=true");
+
+        from("direct:readPerson")
+                .setHeader(ODataConstants.OPERATION, constant("READ_ENTRY"))
+                .to("odata:{{odata.service.url}}/People");
+
+        // The operation can be set by the endpoint option as well as by the 
header
+        from("direct:createPerson")
+                .to("odata:{{odata.service.url}}/People?operation=CREATE");
+
+        // A Map body is serialized to JSON
+        from("direct:createPersonFromMap")
+                .setHeader(ODataConstants.OPERATION, constant("CREATE"))
+                .to("odata:{{odata.service.url}}/People");
+
+        from("direct:updatePerson")
+                .setHeader(ODataConstants.OPERATION, constant("UPDATE"))
+                .to("odata:{{odata.service.url}}/People");
+
+        from("direct:deletePerson")
+                .setHeader(ODataConstants.OPERATION, constant("DELETE"))
+                .to("odata:{{odata.service.url}}/People");
+    }
+}
diff --git 
a/integration-tests/odata/src/test/java/org/apache/camel/quarkus/component/odata/it/OdataIT.java
 
b/integration-tests/odata/src/test/java/org/apache/camel/quarkus/component/odata/it/OdataIT.java
new file mode 100644
index 0000000000..663fbcb78b
--- /dev/null
+++ 
b/integration-tests/odata/src/test/java/org/apache/camel/quarkus/component/odata/it/OdataIT.java
@@ -0,0 +1,24 @@
+/*
+ * 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.quarkus.component.odata.it;
+
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+
+@QuarkusIntegrationTest
+class OdataIT extends OdataTest {
+
+}
diff --git 
a/integration-tests/odata/src/test/java/org/apache/camel/quarkus/component/odata/it/OdataTest.java
 
b/integration-tests/odata/src/test/java/org/apache/camel/quarkus/component/odata/it/OdataTest.java
new file mode 100644
index 0000000000..b268cd06c4
--- /dev/null
+++ 
b/integration-tests/odata/src/test/java/org/apache/camel/quarkus/component/odata/it/OdataTest.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.odata.it;
+
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
+@QuarkusTest
+@QuarkusTestResource(OdataTestResource.class)
+class OdataTest {
+
+    @Test
+    void readSet() {
+        // The service returns the first page with a next link
+        RestAssured.get("/odata/airports")
+                .then()
+                .statusCode(200)
+                .body(
+                        "status", is(200),
+                        "count", is(15),
+                        "nextLink", containsString("skiptoken=8"),
+                        "body.value.size()", is(8),
+                        "body.value[0].Name", notNullValue(),
+                        "body.value[0].IataCode", nullValue());
+
+        // Query option headers take precedence over the endpoint options
+        RestAssured.given()
+                .queryParam("filter", "IataCode eq 'SFO'")
+                .queryParam("select", "IcaoCode,IataCode")
+                .get("/odata/airports")
+                .then()
+                .statusCode(200)
+                .body(
+                        "status", is(200),
+                        "count", is(1),
+                        "nextLink", nullValue(),
+                        "body.value[0].IcaoCode", is("KSFO"),
+                        "body.value[0].IataCode", is("SFO"),
+                        "body.value[0].Name", nullValue());
+    }
+
+    @Test
+    void crud() {
+        // Create
+        String etag = RestAssured.given()
+                .contentType(ContentType.JSON)
+                
.body("{\"UserName\":\"lewisblack\",\"FirstName\":\"Lewis\",\"LastName\":\"Black\"}")
+                .post("/odata/people")
+                .then()
+                .statusCode(200)
+                .body(
+                        "status", is(201),
+                        "etag", notNullValue(),
+                        "body.UserName", is("lewisblack"),
+                        "body.LastName", is("Black"))
+                .extract().path("etag");
+
+        // Read
+        RestAssured.get("/odata/people/lewisblack")
+                .then()
+                .statusCode(200)
+                .body(
+                        "status", is(200),
+                        "etag", is(etag),
+                        "body.FirstName", is("Lewis"));
+
+        // Update with a stale ETag is rejected by the service
+        RestAssured.given()
+                .contentType(ContentType.JSON)
+                .queryParam("etag", "W/\"stale\"")
+                .body("{\"LastName\":\"Stale\"}")
+                .patch("/odata/people/lewisblack")
+                .then()
+                .statusCode(200)
+                .body("status", is(412));
+
+        // Update
+        String updatedEtag = RestAssured.given()
+                .contentType(ContentType.JSON)
+                .queryParam("etag", etag)
+                .body("{\"LastName\":\"Blackwell\"}")
+                .patch("/odata/people/lewisblack")
+                .then()
+                .statusCode(200)
+                .body(
+                        "status", is(204),
+                        "etag", not(etag),
+                        "body", nullValue())
+                .extract().path("etag");
+
+        RestAssured.get("/odata/people/lewisblack")
+                .then()
+                .statusCode(200)
+                .body(
+                        "status", is(200),
+                        "etag", is(updatedEtag),
+                        "body.LastName", is("Blackwell"));
+
+        // Delete
+        RestAssured.given()
+                .queryParam("etag", updatedEtag)
+                .delete("/odata/people/lewisblack")
+                .then()
+                .statusCode(200)
+                .body("status", is(204));
+    }
+
+    @Test
+    void createFromMap() {
+        RestAssured.given()
+                .queryParam("userName", "janedoe")
+                .queryParam("firstName", "Jane")
+                .queryParam("lastName", "Doe")
+                .post("/odata/people/map")
+                .then()
+                .statusCode(200)
+                .body(
+                        "status", is(201),
+                        "etag", notNullValue(),
+                        "body.UserName", is("janedoe"),
+                        "body.FirstName", is("Jane"),
+                        "body.LastName", is("Doe"));
+    }
+}
diff --git 
a/integration-tests/odata/src/test/java/org/apache/camel/quarkus/component/odata/it/OdataTestResource.java
 
b/integration-tests/odata/src/test/java/org/apache/camel/quarkus/component/odata/it/OdataTestResource.java
new file mode 100644
index 0000000000..5808f5fca2
--- /dev/null
+++ 
b/integration-tests/odata/src/test/java/org/apache/camel/quarkus/component/odata/it/OdataTestResource.java
@@ -0,0 +1,85 @@
+/*
+ * 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.quarkus.component.odata.it;
+
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.util.Map;
+
+import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
+import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder;
+import 
org.apache.camel.quarkus.test.wiremock.WireMockTestResourceLifecycleManager;
+
+public class OdataTestResource extends WireMockTestResourceLifecycleManager {
+    private static final String ODATA_BASE_URL = "https://services.odata.org";;
+    private static final String ENV_ODATA_BASE_URL = "ODATA_BASE_URL";
+
+    @Override
+    public Map<String, String> start() {
+        Map<String, String> properties = super.start();
+        String baseUrl = properties.getOrDefault("wiremock.url", 
System.getenv(ENV_ODATA_BASE_URL));
+        properties.put("odata.service.url", createSession(baseUrl));
+        return properties;
+    }
+
+    /**
+     * The TripPin service keeps changes per session. It redirects to a new 
session URL like
+     * /V4/(S(abc))/TripPinServiceRW/
+     * There is no API to delete a session, the service expires it on its own.
+     */
+    private static String createSession(String baseUrl) {
+        try (HttpClient client = HttpClient.newHttpClient()) {
+            HttpRequest request = HttpRequest.newBuilder(URI.create(baseUrl + 
"/V4/TripPinServiceRW/")).build();
+            HttpResponse<Void> response = client.send(request, 
HttpResponse.BodyHandlers.discarding());
+            String location = response.headers().firstValue("Location")
+                    .orElseThrow(() -> new IllegalStateException("No TripPin 
session redirect received"));
+            return baseUrl + location.substring(0, location.length() - 1);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    protected void customizeWiremockConfiguration(WireMockConfiguration 
config) {
+        // Jetty appends --gzip to the ETag of compressed responses
+        config.gzipDisabled(true);
+    }
+
+    @Override
+    protected void customizeRecordSpec(RecordSpecBuilder recordSpec) {
+        // Stubs require the ETag sent as If-Match, like the real service
+        recordSpec.captureHeader("If-Match");
+    }
+
+    @Override
+    protected String getRecordTargetBaseUrl() {
+        return ODATA_BASE_URL;
+    }
+
+    @Override
+    protected boolean isMockingEnabled() {
+        return !envVarsPresent(ENV_ODATA_BASE_URL);
+    }
+
+    @Override
+    protected boolean isDeleteRecordedMappingsOnError() {
+        // The session redirect and the stale ETag update are expected non 2xx 
responses
+        return false;
+    }
+}
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_airports-759ec2a4-1130-49cb-a9f7-4dc3e2ffaa8e.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_airports-759ec2a4-1130-49cb-a9f7-4dc3e2ffaa8e.json
new file mode 100644
index 0000000000..21fee69f95
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_airports-759ec2a4-1130-49cb-a9f7-4dc3e2ffaa8e.json
@@ -0,0 +1,38 @@
+{
+  "id" : "759ec2a4-1130-49cb-a9f7-4dc3e2ffaa8e",
+  "name" : "v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_airports",
+  "request" : {
+    "urlPath" : "/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/Airports",
+    "method" : "GET",
+    "queryParameters" : {
+      "$select" : {
+        "hasExactly" : [ {
+          "equalTo" : "IcaoCode,Name"
+        } ]
+      },
+      "$count" : {
+        "hasExactly" : [ {
+          "equalTo" : "true"
+        } ]
+      }
+    }
+  },
+  "response" : {
+    "status" : 200,
+    "body" : 
"{\"@odata.context\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/$metadata#Airports(IcaoCode,Name)\",\"@odata.count\":15,\"@odata.nextLink\":\"https://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/Airports?%24select=IcaoCode%2cName&%24count=true&%24skiptoken=8\",\"value\":[{\"@odata.id\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/Airports('KSFO')\",\"@odata.editLink\":\"http://service
 [...]
+    "headers" : {
+      "Cache-Control" : "no-cache",
+      "Server" : "Microsoft-IIS/10.0",
+      "Access-Control-Allow-Origin" : "*",
+      "X-AspNet-Version" : "4.0.30319",
+      "OData-Version" : "4.0",
+      "Vary" : "Accept-Encoding",
+      "Date" : "Thu, 08 Oct 2026 14:10:14 GMT",
+      "X-Powered-By" : "ASP.NET",
+      "Content-Type" : 
"application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
+    }
+  },
+  "uuid" : "759ec2a4-1130-49cb-a9f7-4dc3e2ffaa8e",
+  "persistent" : true,
+  "insertionIndex" : 3
+}
\ No newline at end of file
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_airports-944a9fd8-333b-49f1-a957-235ec6e639e0.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_airports-944a9fd8-333b-49f1-a957-235ec6e639e0.json
new file mode 100644
index 0000000000..32e2fd779c
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_airports-944a9fd8-333b-49f1-a957-235ec6e639e0.json
@@ -0,0 +1,43 @@
+{
+  "id" : "944a9fd8-333b-49f1-a957-235ec6e639e0",
+  "name" : "v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_airports",
+  "request" : {
+    "urlPath" : "/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/Airports",
+    "method" : "GET",
+    "queryParameters" : {
+      "$filter" : {
+        "hasExactly" : [ {
+          "equalTo" : "IataCode eq 'SFO'"
+        } ]
+      },
+      "$select" : {
+        "hasExactly" : [ {
+          "equalTo" : "IcaoCode,IataCode"
+        } ]
+      },
+      "$count" : {
+        "hasExactly" : [ {
+          "equalTo" : "true"
+        } ]
+      }
+    }
+  },
+  "response" : {
+    "status" : 200,
+    "body" : 
"{\"@odata.context\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/$metadata#Airports(IcaoCode,IataCode)\",\"@odata.count\":1,\"value\":[{\"@odata.id\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/Airports('KSFO')\",\"@odata.editLink\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/Airports('KSFO')\",\"IcaoCode\":\"KSFO\",\"IataCode\":\"SFO\"}]}",
+    "headers" : {
+      "Cache-Control" : "no-cache",
+      "Server" : "Microsoft-IIS/10.0",
+      "Access-Control-Allow-Origin" : "*",
+      "X-AspNet-Version" : "4.0.30319",
+      "OData-Version" : "4.0",
+      "Vary" : "Accept-Encoding",
+      "Date" : "Thu, 08 Oct 2026 14:10:15 GMT",
+      "X-Powered-By" : "ASP.NET",
+      "Content-Type" : 
"application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
+    }
+  },
+  "uuid" : "944a9fd8-333b-49f1-a957-235ec6e639e0",
+  "persistent" : true,
+  "insertionIndex" : 2
+}
\ No newline at end of file
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_people-4e185b35-a9cf-411e-a0b0-60fded5574bd.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_people-4e185b35-a9cf-411e-a0b0-60fded5574bd.json
new file mode 100644
index 0000000000..bf3c71802a
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_people-4e185b35-a9cf-411e-a0b0-60fded5574bd.json
@@ -0,0 +1,32 @@
+{
+  "id" : "4e185b35-a9cf-411e-a0b0-60fded5574bd",
+  "name" : "v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_people",
+  "request" : {
+    "url" : "/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People",
+    "method" : "POST",
+    "bodyPatterns" : [ {
+      "equalToJson" : 
"{\"LastName\":\"Doe\",\"UserName\":\"janedoe\",\"FirstName\":\"Jane\"}",
+      "ignoreArrayOrder" : true,
+      "ignoreExtraElements" : true
+    } ]
+  },
+  "response" : {
+    "status" : 201,
+    "body" : 
"{\"@odata.context\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/$metadata#People/$entity\",\"@odata.id\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('janedoe')\",\"@odata.etag\":\"W/\\\"08DF2545E114A41E\\\"\",\"@odata.editLink\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('janedoe')\",\"UserName\":\"janedoe\",\"FirstName\":\"Jane\",\"LastName\":\"Doe\",\"Email
 [...]
+    "headers" : {
+      "Cache-Control" : "no-cache",
+      "Server" : "Microsoft-IIS/10.0",
+      "ETag" : "W/\"08DF2545E114A41E\"",
+      "Access-Control-Allow-Origin" : "*",
+      "X-AspNet-Version" : "4.0.30319",
+      "OData-Version" : "4.0",
+      "Date" : "Thu, 08 Oct 2026 14:10:16 GMT",
+      "X-Powered-By" : "ASP.NET",
+      "Location" : 
"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('janedoe')",
+      "Content-Type" : 
"application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
+    }
+  },
+  "uuid" : "4e185b35-a9cf-411e-a0b0-60fded5574bd",
+  "persistent" : true,
+  "insertionIndex" : 1
+}
\ No newline at end of file
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_people-700f2ba3-4d9a-4b55-ac9d-10a7795175bc.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_people-700f2ba3-4d9a-4b55-ac9d-10a7795175bc.json
new file mode 100644
index 0000000000..f4ffd72609
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_people-700f2ba3-4d9a-4b55-ac9d-10a7795175bc.json
@@ -0,0 +1,32 @@
+{
+  "id" : "700f2ba3-4d9a-4b55-ac9d-10a7795175bc",
+  "name" : "v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_people",
+  "request" : {
+    "url" : "/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People",
+    "method" : "POST",
+    "bodyPatterns" : [ {
+      "equalToJson" : 
"{\"UserName\":\"lewisblack\",\"FirstName\":\"Lewis\",\"LastName\":\"Black\"}",
+      "ignoreArrayOrder" : true,
+      "ignoreExtraElements" : true
+    } ]
+  },
+  "response" : {
+    "status" : 201,
+    "body" : 
"{\"@odata.context\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/$metadata#People/$entity\",\"@odata.id\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')\",\"@odata.etag\":\"W/\\\"08DF2545DD9C4EF9\\\"\",\"@odata.editLink\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')\",\"UserName\":\"lewisblack\",\"FirstName\":\"Lewis\",\"LastName\":\"Bla
 [...]
+    "headers" : {
+      "Cache-Control" : "no-cache",
+      "Server" : "Microsoft-IIS/10.0",
+      "ETag" : "W/\"08DF2545DD9C4EF9\"",
+      "Access-Control-Allow-Origin" : "*",
+      "X-AspNet-Version" : "4.0.30319",
+      "OData-Version" : "4.0",
+      "Date" : "Thu, 08 Oct 2026 14:10:10 GMT",
+      "X-Powered-By" : "ASP.NET",
+      "Location" : 
"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')",
+      "Content-Type" : 
"application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
+    }
+  },
+  "uuid" : "700f2ba3-4d9a-4b55-ac9d-10a7795175bc",
+  "persistent" : true,
+  "insertionIndex" : 9
+}
\ No newline at end of file
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-1cc96092-8059-47c7-9be5-86783bc3b7e8.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-1cc96092-8059-47c7-9be5-86783bc3b7e8.json
new file mode 100644
index 0000000000..18f577dac0
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-1cc96092-8059-47c7-9be5-86783bc3b7e8.json
@@ -0,0 +1,34 @@
+{
+  "id" : "1cc96092-8059-47c7-9be5-86783bc3b7e8",
+  "name" : "v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack",
+  "request" : {
+    "url" : 
"/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')",
+    "method" : "PATCH",
+    "headers" : {
+      "If-Match" : {
+        "equalTo" : "W/\"stale\""
+      }
+    },
+    "bodyPatterns" : [ {
+      "equalToJson" : "{\"LastName\":\"Stale\"}",
+      "ignoreArrayOrder" : true,
+      "ignoreExtraElements" : true
+    } ]
+  },
+  "response" : {
+    "status" : 412,
+    "headers" : {
+      "Cache-Control" : "no-cache",
+      "Server" : "Microsoft-IIS/10.0",
+      "Access-Control-Allow-Origin" : "*",
+      "X-AspNet-Version" : "4.0.30319",
+      "OData-Version" : "4.0",
+      "Date" : "Thu, 08 Oct 2026 14:10:12 GMT",
+      "X-Powered-By" : "ASP.NET",
+      "Content-Type" : "application/octet-stream"
+    }
+  },
+  "uuid" : "1cc96092-8059-47c7-9be5-86783bc3b7e8",
+  "persistent" : true,
+  "insertionIndex" : 7
+}
\ No newline at end of file
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-45d7ae56-29a8-4dec-a7aa-ccd02f45518b.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-45d7ae56-29a8-4dec-a7aa-ccd02f45518b.json
new file mode 100644
index 0000000000..d773fd4506
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-45d7ae56-29a8-4dec-a7aa-ccd02f45518b.json
@@ -0,0 +1,34 @@
+{
+  "id" : "45d7ae56-29a8-4dec-a7aa-ccd02f45518b",
+  "name" : "v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack",
+  "request" : {
+    "url" : 
"/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')",
+    "method" : "PATCH",
+    "headers" : {
+      "If-Match" : {
+        "equalTo" : "W/\"08DF2545DD9C4EF9\""
+      }
+    },
+    "bodyPatterns" : [ {
+      "equalToJson" : "{\"LastName\":\"Blackwell\"}",
+      "ignoreArrayOrder" : true,
+      "ignoreExtraElements" : true
+    } ]
+  },
+  "response" : {
+    "status" : 204,
+    "headers" : {
+      "Cache-Control" : "no-cache",
+      "Server" : "Microsoft-IIS/10.0",
+      "ETag" : "W/\"08DF2545DF1878C1\"",
+      "Access-Control-Allow-Origin" : "*",
+      "X-AspNet-Version" : "4.0.30319",
+      "OData-Version" : "4.0",
+      "Date" : "Thu, 08 Oct 2026 14:10:13 GMT",
+      "X-Powered-By" : "ASP.NET"
+    }
+  },
+  "uuid" : "45d7ae56-29a8-4dec-a7aa-ccd02f45518b",
+  "persistent" : true,
+  "insertionIndex" : 6
+}
\ No newline at end of file
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-4a219113-8278-4551-8391-a643d7182bf2.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-4a219113-8278-4551-8391-a643d7182bf2.json
new file mode 100644
index 0000000000..40b3f587cb
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-4a219113-8278-4551-8391-a643d7182bf2.json
@@ -0,0 +1,29 @@
+{
+  "id" : "4a219113-8278-4551-8391-a643d7182bf2",
+  "name" : "v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack",
+  "request" : {
+    "url" : 
"/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "body" : 
"{\"@odata.context\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/$metadata#People/$entity\",\"@odata.id\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')\",\"@odata.etag\":\"W/\\\"08DF2545DF1878C1\\\"\",\"@odata.editLink\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')\",\"UserName\":\"lewisblack\",\"FirstName\":\"Lewis\",\"LastName\":\"Bla
 [...]
+    "headers" : {
+      "Cache-Control" : "no-cache",
+      "Server" : "Microsoft-IIS/10.0",
+      "ETag" : "W/\"08DF2545DF1878C1\"",
+      "Access-Control-Allow-Origin" : "*",
+      "X-AspNet-Version" : "4.0.30319",
+      "OData-Version" : "4.0",
+      "Vary" : "Accept-Encoding",
+      "Date" : "Thu, 08 Oct 2026 14:10:13 GMT",
+      "X-Powered-By" : "ASP.NET",
+      "Content-Type" : 
"application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
+    }
+  },
+  "uuid" : "4a219113-8278-4551-8391-a643d7182bf2",
+  "persistent" : true,
+  "scenarioName" : 
"scenario-1-V4-(S(cjxxums4lcwyv1kp2j1ez5wp))-TripPinServiceRW-People('lewisblack')",
+  "requiredScenarioState" : 
"scenario-1-V4-(S(cjxxums4lcwyv1kp2j1ez5wp))-TripPinServiceRW-People('lewisblack')-2",
+  "insertionIndex" : 5
+}
\ No newline at end of file
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-4d0f05be-da4e-43e2-b031-0b3a1dc25e30.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-4d0f05be-da4e-43e2-b031-0b3a1dc25e30.json
new file mode 100644
index 0000000000..418b63aaf5
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-4d0f05be-da4e-43e2-b031-0b3a1dc25e30.json
@@ -0,0 +1,28 @@
+{
+  "id" : "4d0f05be-da4e-43e2-b031-0b3a1dc25e30",
+  "name" : "v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack",
+  "request" : {
+    "url" : 
"/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')",
+    "method" : "DELETE",
+    "headers" : {
+      "If-Match" : {
+        "equalTo" : "W/\"08DF2545DF1878C1\""
+      }
+    }
+  },
+  "response" : {
+    "status" : 204,
+    "headers" : {
+      "Cache-Control" : "no-cache",
+      "Server" : "Microsoft-IIS/10.0",
+      "Access-Control-Allow-Origin" : "*",
+      "X-AspNet-Version" : "4.0.30319",
+      "OData-Version" : "4.0",
+      "Date" : "Thu, 08 Oct 2026 14:10:14 GMT",
+      "X-Powered-By" : "ASP.NET"
+    }
+  },
+  "uuid" : "4d0f05be-da4e-43e2-b031-0b3a1dc25e30",
+  "persistent" : true,
+  "insertionIndex" : 4
+}
\ No newline at end of file
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-659d8317-21c0-49fb-b61e-373b3408710c.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-659d8317-21c0-49fb-b61e-373b3408710c.json
new file mode 100644
index 0000000000..c51ae0df5a
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack-659d8317-21c0-49fb-b61e-373b3408710c.json
@@ -0,0 +1,30 @@
+{
+  "id" : "659d8317-21c0-49fb-b61e-373b3408710c",
+  "name" : "v4_scjxxums4lcwyv1kp2j1ez5wp_trippinservicerw_peoplelewisblack",
+  "request" : {
+    "url" : 
"/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "body" : 
"{\"@odata.context\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/$metadata#People/$entity\",\"@odata.id\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')\",\"@odata.etag\":\"W/\\\"08DF2545DD9C4EF9\\\"\",\"@odata.editLink\":\"http://services.odata.org/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/People('lewisblack')\",\"UserName\":\"lewisblack\",\"FirstName\":\"Lewis\",\"LastName\":\"Bla
 [...]
+    "headers" : {
+      "Cache-Control" : "no-cache",
+      "Server" : "Microsoft-IIS/10.0",
+      "ETag" : "W/\"08DF2545DD9C4EF9\"",
+      "Access-Control-Allow-Origin" : "*",
+      "X-AspNet-Version" : "4.0.30319",
+      "OData-Version" : "4.0",
+      "Vary" : "Accept-Encoding",
+      "Date" : "Thu, 08 Oct 2026 14:10:11 GMT",
+      "X-Powered-By" : "ASP.NET",
+      "Content-Type" : 
"application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
+    }
+  },
+  "uuid" : "659d8317-21c0-49fb-b61e-373b3408710c",
+  "persistent" : true,
+  "scenarioName" : 
"scenario-1-V4-(S(cjxxums4lcwyv1kp2j1ez5wp))-TripPinServiceRW-People('lewisblack')",
+  "requiredScenarioState" : "Started",
+  "newScenarioState" : 
"scenario-1-V4-(S(cjxxums4lcwyv1kp2j1ez5wp))-TripPinServiceRW-People('lewisblack')-2",
+  "insertionIndex" : 8
+}
\ No newline at end of file
diff --git 
a/integration-tests/odata/src/test/resources/mappings/v4_trippinservicerw-94a37fd4-2e39-497c-88e0-00de259ac10b.json
 
b/integration-tests/odata/src/test/resources/mappings/v4_trippinservicerw-94a37fd4-2e39-497c-88e0-00de259ac10b.json
new file mode 100644
index 0000000000..eca96266ac
--- /dev/null
+++ 
b/integration-tests/odata/src/test/resources/mappings/v4_trippinservicerw-94a37fd4-2e39-497c-88e0-00de259ac10b.json
@@ -0,0 +1,23 @@
+{
+  "id" : "94a37fd4-2e39-497c-88e0-00de259ac10b",
+  "name" : "v4_trippinservicerw",
+  "request" : {
+    "url" : "/V4/TripPinServiceRW/",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 302,
+    "body" : "<html><head><title>Object 
moved</title></head><body>\r\n<h2>Object moved to <a 
href=\"/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/\">here</a>.</h2>\r\n</body></html>\r\n",
+    "headers" : {
+      "Server" : "Microsoft-IIS/10.0",
+      "Access-Control-Allow-Origin" : "*",
+      "Date" : "Thu, 08 Oct 2026 14:10:06 GMT",
+      "X-Powered-By" : "ASP.NET",
+      "Location" : "/V4/(S(cjxxums4lcwyv1kp2j1ez5wp))/TripPinServiceRW/",
+      "Content-Type" : "text/html; charset=utf-8"
+    }
+  },
+  "uuid" : "94a37fd4-2e39-497c-88e0-00de259ac10b",
+  "persistent" : true,
+  "insertionIndex" : 10
+}
\ No newline at end of file
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 21411e9e03..7be25439e2 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -204,6 +204,7 @@
         <module>oauth</module>
         <module>observability-services</module>
         <module>ocsf</module>
+        <module>odata</module>
         <module>ognl</module>
         <module>olingo4</module>
         <module>once</module>
diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml
index 5c6e16d87d..1583f4e97f 100644
--- a/poms/bom/pom.xml
+++ b/poms/bom/pom.xml
@@ -2526,6 +2526,11 @@
                 <artifactId>camel-ocsf</artifactId>
                 <version>${camel.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-odata</artifactId>
+                <version>${camel.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel</groupId>
                 <artifactId>camel-ognl</artifactId>
@@ -5917,6 +5922,16 @@
                 <artifactId>camel-quarkus-ocsf-deployment</artifactId>
                 <version>${camel-quarkus.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel.quarkus</groupId>
+                <artifactId>camel-quarkus-odata</artifactId>
+                <version>${camel-quarkus.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.camel.quarkus</groupId>
+                <artifactId>camel-quarkus-odata-deployment</artifactId>
+                <version>${camel-quarkus.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel.quarkus</groupId>
                 <artifactId>camel-quarkus-ognl</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-full-pom.xml 
b/poms/bom/src/main/generated/flattened-full-pom.xml
index 97aaa6353a..a9831cb3cb 100644
--- a/poms/bom/src/main/generated/flattened-full-pom.xml
+++ b/poms/bom/src/main/generated/flattened-full-pom.xml
@@ -2449,6 +2449,11 @@
         <artifactId>camel-ocsf</artifactId>
         <version>4.22.1</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-odata</artifactId>
+        <version>4.23.0-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-ognl</artifactId>
@@ -5822,6 +5827,16 @@
         <artifactId>camel-quarkus-ocsf-deployment</artifactId>
         <version>4.0.0-SNAPSHOT</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-odata</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-odata-deployment</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel.quarkus</groupId>
         <artifactId>camel-quarkus-ognl</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-reduced-pom.xml 
b/poms/bom/src/main/generated/flattened-reduced-pom.xml
index ac65ea5690..4abd7134f6 100644
--- a/poms/bom/src/main/generated/flattened-reduced-pom.xml
+++ b/poms/bom/src/main/generated/flattened-reduced-pom.xml
@@ -3829,6 +3829,11 @@
         <artifactId>camel-ocsf</artifactId>
         <version>4.22.1</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-odata</artifactId>
+        <version>4.23.0-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-ognl</artifactId>
@@ -7207,6 +7212,16 @@
         <artifactId>camel-quarkus-ocsf-deployment</artifactId>
         <version>4.0.0-SNAPSHOT</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-odata</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-odata-deployment</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel.quarkus</groupId>
         <artifactId>camel-quarkus-ognl</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml 
b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
index 6f05f58cc5..1bb2ddc97b 100644
--- a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
+++ b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
@@ -3829,6 +3829,11 @@
         <artifactId>camel-ocsf</artifactId>
         <version>4.22.1</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-odata</artifactId>
+        <version>4.23.0-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-ognl</artifactId>
@@ -7207,6 +7212,16 @@
         <artifactId>camel-quarkus-ocsf-deployment</artifactId>
         <version>4.0.0-SNAPSHOT</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-odata</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-odata-deployment</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel.quarkus</groupId>
         <artifactId>camel-quarkus-ognl</artifactId>
diff --git a/tooling/scripts/test-categories.yaml 
b/tooling/scripts/test-categories.yaml
index ce8b1114e6..644cefc4cc 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -244,6 +244,7 @@ group-12:
   - langchain4j-tools
   - langchain4j-web-search
   - mcp-server
+  - odata
   - openapi-java
   - openapi-validator
   - opentelemetry2

Reply via email to