cloud-sdk-java icon indicating copy to clipboard operation
cloud-sdk-java copied to clipboard

CDS remote OData handler update and delete call returns empty result with 0 rows when entityPath contains + character

Open MahdiBarkia opened this issue 8 months ago • 5 comments

Bug Description

In our Project, we use CAP remote service to create, update and delete ad hoc items and CAP remote Service relies on Cloud SDK Java. This works fine but when I created an ad hoc item containing + Sign Example: "Due 5 + - Due after 5th years" and tried to update or delete it, I get an error message that it cannot be updated/deleted, because it could not be found. After debugging, found out that calling remoteService.run(Delete.from(AdhocItem_.class).matching(adhocItemEntryToDelete)) returns empty result with 0 rows deleted.

Steps to Reproduce

Executing ODataRequestDelete from RemoteODataHandler https://github.wdf.sap.corp/cds-java/cds-services/blob/main/cds-feature-remote-odata/src/main/java/com/sap/cds/services/impl/odata/RemoteODataHandler.java#L368 with entity path that conatins "+"

Expected Behavior

Executing a delete always returns an empty result. This is expected. but Result.rowCount method should return number of deleted rows = 1 not 0.

After comparing the Read entityPath: .../API_CNSLDTNADHOCITEM/AdhocItem?$filter=((CnsldtnAdhocItem%20eq%20'Due%205%20%2B%20-%20Due%20after%205th%20years')%20and%20(ConsolidationChartOfAccounts%20eq%20'Y1')) with Delete entityPath: .../API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1'), the main difference is that for the GET request the plus character (+) is escaped whereas in the DELETE request it isn't. In the GET request the + character appears in the query part of the URI. In the query part, an unescaped + character has a special meaning: it is treated as a space. Hence if we use a + in the query part it needs to be escaped as %2B. in the DELETE request the + character appears in the path part of the URI. Here it looks like the Cloud SDK Java do not need to escape + character. But the remote server waits here for encoded path part because: Calling /API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1') returns /IWBEP/CX_MGW_BUSI_EXCEPTION and calling /API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20%2B%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1') returns the entity as response.

Used Versions

https://github.wdf.sap.corp/CloudConso/grdc-forms-and-reports
cloud-sdk-java 5.18.0
@sap/cds 7.9.5
@sap/cds-compiler 4.9.8
@sap/cds-dk 7.9.9
CAP Java SDK 3.9.1
Java 17.0.13
Maven 3.9.9
Spring Boot 3.4.5
cds4j 3.9.1

OS / Environment

Cloud Foundry

Dependency tree via `mvn dependency:tree`

[INFO] com.sap.cloud.conso.grdc-forms-and-reports:srv:war:1.0.0 [INFO] +- com.sap.xs.auditlog:audit-java-client-api:jar:2.0.21:provided [INFO] +- com.sap.cloud.security:java-api:jar:3.6.0:provided [INFO] +- com.sap.cloud.security:java-security:jar:3.6.0:provided [INFO] | +- com.sap.cloud.security:env:jar:3.6.0:compile [INFO] | | +- com.sap.cloud.environment.servicebinding:java-sap-vcap-services:jar:0.20.0:provided [INFO] | | +- com.sap.cloud.environment.servicebinding:java-sap-service-operator:jar:0.21.0:compile [INFO] | | +- com.sap.cloud.environment.servicebinding.api:java-consumption-api:jar:0.20.0:provided [INFO] | | - org.json:json:jar:20250107:provided [INFO] | +- commons-io:commons-io:jar:2.19.0:compile [INFO] | - com.sap.cloud.security.xsuaa:token-client:jar:3.6.0:provided [INFO] | - com.github.ben-manes.caffeine:caffeine:jar:3.1.8:provided [INFO] | - org.checkerframework:checker-qual:jar:3.49.2:provided [INFO] +- com.sap.xs.java:xs-env:jar:1.8.5:provided [INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar:2.18.3:provided [INFO] | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.18.3:provided [INFO] | - com.fasterxml.jackson.core:jackson-core:jar:2.18.3:provided [INFO] +- com.sap.cloud.conso:forms-core:jar:1.0.0:compile [INFO] | +- org.springframework:spring-web:jar:6.2.6:compile [INFO] | | +- org.springframework:spring-beans:jar:6.2.6:compile [INFO] | | +- org.springframework:spring-core:jar:6.2.6:compile [INFO] | | | - org.springframework:spring-jcl:jar:6.2.6:compile [INFO] | | - io.micrometer:micrometer-observation:jar:1.14.6:compile [INFO] | | - io.micrometer:micrometer-commons:jar:1.14.6:compile [INFO] | +- org.springframework.boot:spring-boot-starter-security:jar:3.4.5:compile [INFO] | | +- org.springframework.boot:spring-boot-starter:jar:3.4.5:compile [INFO] | | | +- org.springframework.boot:spring-boot:jar:3.4.5:compile [INFO] | | | +- org.springframework.boot:spring-boot-starter-logging:jar:3.4.5:compile [INFO] | | | | +- ch.qos.logback:logback-classic:jar:1.5.18:provided [INFO] | | | | | - ch.qos.logback:logback-core:jar:1.5.18:provided [INFO] | | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.24.3:compile [INFO] | | | | | - org.apache.logging.log4j:log4j-api:jar:2.24.3:compile [INFO] | | | | - org.slf4j:jul-to-slf4j:jar:2.0.17:provided [INFO] | | | - jakarta.annotation:jakarta.annotation-api:jar:2.1.1:compile [INFO] | | +- org.springframework:spring-aop:jar:6.2.6:compile [INFO] | | +- org.springframework.security:spring-security-config:jar:6.4.5:compile [INFO] | | | - org.springframework:spring-context:jar:6.2.6:compile [INFO] | | - org.springframework.security:spring-security-web:jar:6.4.5:compile [INFO] | | - org.springframework:spring-expression:jar:6.2.6:compile [INFO] | +- org.apache.httpcomponents.client5:httpclient5:jar:5.4.4:compile [INFO] | | +- org.apache.httpcomponents.core5:httpcore5:jar:5.3.4:provided [INFO] | | - org.apache.httpcomponents.core5:httpcore5-h2:jar:5.3.4:provided [INFO] | +- org.springframework.boot:spring-boot-starter-actuator:jar:3.4.5:compile [INFO] | | +- org.springframework.boot:spring-boot-actuator-autoconfigure:jar:3.4.5:compile [INFO] | | | +- org.springframework.boot:spring-boot-actuator:jar:3.4.5:compile [INFO] | | | - com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.18.3:compile [INFO] | | - io.micrometer:micrometer-jakarta9:jar:1.14.6:compile [INFO] | +- org.springframework.boot:spring-boot-starter-validation:jar:3.4.5:compile [INFO] | | +- org.apache.tomcat.embed:tomcat-embed-el:jar:10.1.40:compile [INFO] | | - org.hibernate.validator:hibernate-validator:jar:8.0.2.Final:compile [INFO] | | +- org.jboss.logging:jboss-logging:jar:3.6.1.Final:compile [INFO] | | - com.fasterxml:classmate:jar:1.7.0:compile [INFO] | +- jakarta.validation:jakarta.validation-api:jar:3.1.1:compile [INFO] | +- com.sap.cloud.conso:common-lib:jar:6.13.9:compile [INFO] | | +- org.jboss.marshalling:jboss-marshalling:jar:2.2.3.Final:compile [INFO] | | +- org.jboss.marshalling:jboss-marshalling-river:jar:2.2.3.Final:compile [INFO] | | +- com.sap.cloud.sdk.cloudplatform:resilience4j:jar:5.18.0:compile [INFO] | | | +- io.github.resilience4j:resilience4j-circuitbreaker:jar:2.3.0:compile [INFO] | | | +- io.github.resilience4j:resilience4j-bulkhead:jar:2.3.0:compile [INFO] | | | +- io.github.resilience4j:resilience4j-timelimiter:jar:2.3.0:compile [INFO] | | | +- io.github.resilience4j:resilience4j-retry:jar:2.3.0:compile [INFO] | | | +- io.github.resilience4j:resilience4j-ratelimiter:jar:2.3.0:compile [INFO] | | | - javax.cache:cache-api:jar:1.1.1:compile [INFO] | | +- com.sap.hcp.cf.logging:cf-java-logging-support-servlet-jakarta:jar:3.8.4:compile [INFO] | | +- com.sap.hcp.cf.logging:cf-java-logging-support-logback:jar:3.8.4:compile [INFO] | | +- com.sap.hcp.cf.logging:cf-java-logging-support-core:jar:3.8.4:compile [INFO] | | | - com.fasterxml.jackson.jr:jackson-jr-objects:jar:2.18.3:provided [INFO] | | +- org.springframework.security:spring-security-core:jar:6.4.5:compile [INFO] | | | - org.springframework.security:spring-security-crypto:jar:6.4.5:compile [INFO] | | +- org.redisson:redisson:jar:3.45.1:compile [INFO] | | | +- io.netty:netty-common:jar:4.1.119.Final:compile [INFO] | | | +- io.netty:netty-codec:jar:4.1.119.Final:compile [INFO] | | | +- io.netty:netty-buffer:jar:4.1.119.Final:compile [INFO] | | | +- io.netty:netty-transport:jar:4.1.119.Final:compile [INFO] | | | +- io.netty:netty-resolver:jar:4.1.119.Final:compile [INFO] | | | +- io.netty:netty-resolver-dns:jar:4.1.119.Final:compile [INFO] | | | | - io.netty:netty-codec-dns:jar:4.1.119.Final:compile [INFO] | | | +- io.netty:netty-handler:jar:4.1.119.Final:compile [INFO] | | | | - io.netty:netty-transport-native-unix-common:jar:4.1.119.Final:compile [INFO] | | | +- io.projectreactor:reactor-core:jar:3.7.5:compile [INFO] | | | +- org.reactivestreams:reactive-streams:jar:1.0.4:compile [INFO] | | | +- io.reactivex.rxjava3:rxjava:jar:3.1.10:compile [INFO] | | | +- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.18.3:provided [INFO] | | | - org.jodd:jodd-util:jar:6.3.0:compile [INFO] | | +- org.lz4:lz4-java:jar:1.8.0:compile [INFO] | | +- io.micrometer:micrometer-core:jar:1.14.6:compile [INFO] | | | +- org.hdrhistogram:HdrHistogram:jar:2.2.2:runtime [INFO] | | | - org.latencyutils:LatencyUtils:jar:2.0.3:runtime [INFO] | | +- io.github.resilience4j:resilience4j-cache:jar:2.3.0:compile [INFO] | | | - io.github.resilience4j:resilience4j-core:jar:2.3.0:compile [INFO] | | | - org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.9.25:compile [INFO] | | | +- org.jetbrains.kotlin:kotlin-stdlib:jar:1.9.25:compile [INFO] | | | | - org.jetbrains:annotations:jar:13.0:compile [INFO] | | | - org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.9.25:compile [INFO] | | +- com.esotericsoftware:kryo:jar:5.6.2:compile [INFO] | | | +- com.esotericsoftware:reflectasm:jar:1.11.9:compile [INFO] | | | - com.esotericsoftware:minlog:jar:1.3.1:compile [INFO] | | +- software.amazon.awssdk:s3:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:aws-xml-protocol:jar:2.31.31:compile [INFO] | | | | - software.amazon.awssdk:aws-query-protocol:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:protocol-core:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:arns:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:profiles:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:crt-core:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:http-auth:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:identity-spi:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:http-auth-spi:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:http-auth-aws:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:checksums:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:checksums-spi:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:retries-spi:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:sdk-core:jar:2.31.31:compile [INFO] | | | | - software.amazon.awssdk:retries:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:auth:jar:2.31.31:compile [INFO] | | | | +- software.amazon.awssdk:http-auth-aws-eventstream:jar:2.31.31:compile [INFO] | | | | - software.amazon.eventstream:eventstream:jar:1.0.1:compile [INFO] | | | +- software.amazon.awssdk:http-client-spi:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:regions:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:annotations:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:utils:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:aws-core:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:metrics-spi:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:json-utils:jar:2.31.31:compile [INFO] | | | | - software.amazon.awssdk:third-party-jackson-core:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:endpoints-spi:jar:2.31.31:compile [INFO] | | | +- software.amazon.awssdk:apache-client:jar:2.31.31:runtime [INFO] | | | - software.amazon.awssdk:netty-nio-client:jar:2.31.31:runtime [INFO] | | | +- io.netty:netty-codec-http2:jar:4.1.119.Final:runtime [INFO] | | | - io.netty:netty-transport-classes-epoll:jar:4.1.119.Final:runtime [INFO] | | +- com.dynatrace.oneagent.sdk.java:oneagent-sdk:jar:1.9.0:compile [INFO] | | +- com.github.ben-manes.caffeine:jcache:jar:3.2.0:compile [INFO] | | | +- org.osgi:org.osgi.service.component.annotations:jar:1.5.1:compile [INFO] | | | | +- org.osgi:osgi.annotation:jar:8.1.0:compile [INFO] | | | | +- org.osgi:org.osgi.namespace.extender:jar:1.0.1:compile [INFO] | | | | +- org.osgi:org.osgi.util.function:jar:1.0.0:compile [INFO] | | | | - org.osgi:org.osgi.util.promise:jar:1.0.0:compile [INFO] | | | +- jakarta.inject:jakarta.inject-api:jar:2.0.1:compile [INFO] | | | - com.typesafe:config:jar:1.4.3:compile [INFO] | | +- com.sap.cloud.sdk.datamodel:odata-core:jar:5.18.0:compile [INFO] | | | - com.google.code.findbugs:jsr305:jar:3.0.2:compile [INFO] | | +- com.sap.cloud.sdk.datamodel:odata-v4-core:jar:5.18.0:compile [INFO] | | - org.projectlombok:lombok:jar:1.18.38:compile [INFO] | +- com.sap.cloud.security:resourceserver-security-spring-boot-starter:jar:3.6.0:compile [INFO] | | +- com.sap.cloud.security:spring-security:jar:3.6.0:compile [INFO] | | +- org.springframework.security:spring-security-oauth2-jose:jar:6.4.5:compile [INFO] | | | +- org.springframework.security:spring-security-oauth2-core:jar:6.4.5:compile [INFO] | | | - com.nimbusds:nimbus-jose-jwt:jar:9.37.3:compile [INFO] | | | - com.github.stephenc.jcip:jcip-annotations:jar:1.0-1:compile [INFO] | | +- org.springframework.security:spring-security-oauth2-resource-server:jar:6.4.5:compile [INFO] | | - org.springframework.boot:spring-boot-autoconfigure:jar:3.4.5:compile [INFO] | +- com.sap.cloud.sdk.s4hana:rfc:jar:5.18.0:compile [INFO] | | +- com.sap.cloud.sdk.s4hana:s4hana-core:jar:5.18.0:compile [INFO] | | +- com.sap.cloud.sdk.s4hana:s4hana-connectivity:jar:5.18.0:compile [INFO] | | +- com.sap.cloud.sdk.datamodel:fluent-result:jar:5.18.0:compile [INFO] | | +- io.vavr:vavr:jar:0.10.6:compile [INFO] | | | - io.vavr:vavr-match:jar:0.10.6:compile [INFO] | | +- com.google.guava:guava:jar:33.4.8-jre:compile [INFO] | | | +- com.google.guava:failureaccess:jar:1.0.3:compile [INFO] | | | +- com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:compile [INFO] | | | +- org.jspecify:jspecify:jar:1.0.0:compile [INFO] | | | - com.google.j2objc:j2objc-annotations:jar:3.0.0:compile [INFO] | | +- com.mikesamuel:json-sanitizer:jar:1.2.3:compile [INFO] | | - org.apache.httpcomponents:httpcore:jar:4.4.16:provided [INFO] | +- com.sap.cds:cds-feature-remote-odata:jar:3.9.1:runtime [INFO] | | - com.sap.cloud.sdk.datamodel:odata-client:jar:5.18.0:compile [INFO] | +- com.sap.cds:cds-feature-cloudfoundry:jar:3.9.1:compile [INFO] | +- com.sap.cds:cds-integration-cloud-sdk:jar:3.9.1:compile [INFO] | | - com.sap.cloud.sdk.cloudplatform:connectivity-apache-httpclient4:jar:5.18.0:compile [INFO] | +- com.sap.cds:cds-starter-cloudfoundry:jar:3.9.1:compile [INFO] | | - com.sap.cds:cds-feature-hana:jar:3.9.1:compile [INFO] | | - com.sap.cloud.db.jdbc:ngdbc:jar:2.24.7:provided [INFO] | +- com.sap.cds:cds-feature-identity:jar:3.9.1:compile [INFO] | +- com.sap.cds:cds-feature-message-queuing:jar:3.9.1:runtime [INFO] | | - org.apache.qpid:qpid-jms-client:jar:2.7.0:runtime [INFO] | | +- org.apache.qpid:proton-j:jar:0.34.1:runtime [INFO] | | +- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.119.Final:runtime [INFO] | | +- io.netty:netty-transport-native-kqueue:jar:osx-x86_64:4.1.119.Final:runtime [INFO] | | | - io.netty:netty-transport-classes-kqueue:jar:4.1.119.Final:runtime [INFO] | | - io.netty:netty-codec-http:jar:4.1.119.Final:runtime [INFO] | +- org.apache.axis2:axis2-adb:jar:1.7.9:compile [INFO] | | +- org.apache.axis2:axis2-kernel:jar:1.7.9:compile [INFO] | | | +- org.apache.ws.commons.axiom:axiom-api:jar:1.2.21:compile [INFO] | | | | +- jaxen:jaxen:jar:2.0.0:compile [INFO] | | | | +- org.apache.geronimo.specs:geronimo-stax-api_1.0_spec:jar:1.0.1:compile [INFO] | | | | - org.apache.james:apache-mime4j-core:jar:0.7.2:compile [INFO] | | | +- org.apache.ws.commons.axiom:axiom-impl:jar:1.2.21:runtime [INFO] | | | +- org.apache.geronimo.specs:geronimo-ws-metadata_2.0_spec:jar:1.1.2:compile [INFO] | | | +- org.apache.geronimo.specs:geronimo-jta_1.1_spec:jar:1.1:compile [INFO] | | | +- javax.servlet:servlet-api:jar:2.3:compile [INFO] | | | +- commons-fileupload:commons-fileupload:jar:1.3.3:compile [INFO] | | | +- wsdl4j:wsdl4j:jar:1.6.3:compile [INFO] | | | +- org.apache.neethi:neethi:jar:3.0.3:compile [INFO] | | | +- org.apache.woden:woden-core:jar:1.0M10:compile [INFO] | | | +- commons-logging:commons-logging:jar:1.2:provided [INFO] | | | - javax.ws.rs:jsr311-api:jar:1.1.1:compile [INFO] | | +- org.apache.ws.commons.axiom:axiom-dom:jar:1.2.21:runtime [INFO] | | | - org.codehaus.woodstox:woodstox-core-asl:jar:4.2.0:runtime [INFO] | | | - org.codehaus.woodstox:stax2-api:jar:4.2.2:runtime [INFO] | | - org.apache.geronimo.specs:geronimo-activation_1.1_spec:jar:1.0.2:compile [INFO] | +- org.xerial:sqlite-jdbc:jar:3.49.1.0:compile [INFO] | +- com.bucket4j:bucket4j-core:jar:8.10.1:compile [INFO] | +- com.bucket4j:bucket4j-jcache:jar:8.10.1:compile [INFO] | - com.bucket4j:bucket4j-redis:jar:8.10.1:compile [INFO] +- org.assertj:assertj-core:jar:3.26.3:test [INFO] | - net.bytebuddy:byte-buddy:jar:1.15.11:compile [INFO] +- org.mockito:mockito-junit-jupiter:jar:5.17.0:test [INFO] | - org.junit.jupiter:junit-jupiter-api:jar:5.11.4:test [INFO] | +- org.opentest4j:opentest4j:jar:1.3.0:test [INFO] | +- org.junit.platform:junit-platform-commons:jar:1.11.4:test [INFO] | - org.apiguardian:apiguardian-api:jar:1.1.2:test [INFO] +- org.mockito:mockito-core:jar:5.17.0:test [INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.15.11:test [INFO] | - org.objenesis:objenesis:jar:3.3:compile [INFO] +- commons-cli:commons-cli:jar:1.9.0:compile [INFO] +- com.sap.cds:cds-services-impl:jar:3.9.1:compile [INFO] | +- com.sap.cds:cds-services-api:jar:3.9.1:compile [INFO] | | +- com.sap.cds:cds4j-api:jar:3.9.1:compile [INFO] | | - com.sap.cloud.environment.servicebinding.api:java-core-api:jar:0.20.0:provided [INFO] | +- com.sap.cds:cds-services-utils:jar:3.9.1:compile [INFO] | | +- com.sap.cds:cds4j-runtime:jar:3.9.1:compile [INFO] | | | - com.sap.cds:cds4j-jdbc-spi:jar:3.9.1:compile [INFO] | | - io.opentelemetry:opentelemetry-api:jar:1.43.0:compile [INFO] | | - io.opentelemetry:opentelemetry-context:jar:1.43.0:compile [INFO] | +- com.sap.cds:cds-services-messaging:jar:3.9.1:compile [INFO] | | - jakarta.jms:jakarta.jms-api:jar:3.1.0:compile [INFO] | +- com.sap.cds:cds4j-core:jar:3.9.1:compile [INFO] | +- org.slf4j:slf4j-api:jar:2.0.17:provided [INFO] | +- com.sap.cloud.environment.servicebinding.api:java-access-api:jar:0.20.0:provided [INFO] | - org.apache.commons:commons-csv:jar:1.14.0:compile [INFO] | - commons-codec:commons-codec:jar:1.16.1:provided [INFO] +- com.sap.cds:cds-feature-mt:jar:3.9.1:compile [INFO] | +- com.sap.cds:cds-adapter-api:jar:3.9.1:compile [INFO] | - com.google.code.gson:gson:jar:2.13.1:compile [INFO] | - com.google.errorprone:error_prone_annotations:jar:2.37.0:compile [INFO] +- com.sap.cds:cds-starter-spring-boot:jar:3.9.1:compile [INFO] | +- com.sap.cds:cds-feature-jdbc:jar:3.9.1:runtime [INFO] | | - com.sap.cds:cds4j-tx:jar:3.9.1:runtime [INFO] | +- com.sap.cds:cds-framework-spring-boot:jar:3.9.1:runtime [INFO] | +- org.springframework.boot:spring-boot-starter-web:jar:3.4.5:compile [INFO] | | +- org.springframework.boot:spring-boot-starter-json:jar:3.4.5:compile [INFO] | | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.18.3:compile [INFO] | | | - com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.18.3:compile [INFO] | | +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.4.5:compile [INFO] | | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:10.1.40:compile [INFO] | | | - org.apache.tomcat.embed:tomcat-embed-websocket:jar:10.1.40:compile [INFO] | | - org.springframework:spring-webmvc:jar:6.2.6:compile [INFO] | +- org.springframework.boot:spring-boot-starter-jdbc:jar:3.4.5:compile [INFO] | | +- com.zaxxer:HikariCP:jar:5.1.0:compile [INFO] | | - org.springframework:spring-jdbc:jar:6.2.6:compile [INFO] | | - org.springframework:spring-tx:jar:6.2.6:compile [INFO] | - org.yaml:snakeyaml:jar:2.4:provided [INFO] +- com.sap.cds:cds-adapter-odata-v2:jar:3.9.1:compile [INFO] | +- com.sap.cds.repackaged:odata-v2-lib:jar:3.9.1:compile [INFO] | | - javax.ws.rs:javax.ws.rs-api:jar:2.1.1:compile [INFO] | - org.apache.commons:commons-lang3:jar:3.15.0:provided [INFO] +- com.sap.cloud.sdk:sdk-core:jar:5.18.0:compile [INFO] | +- com.sap.cloud.sdk.cloudplatform:cloudplatform-connectivity:jar:5.18.0:compile [INFO] | | +- com.sap.cloud.sdk.cloudplatform:resilience-api:jar:5.18.0:compile [INFO] | | +- org.slf4j:jcl-over-slf4j:jar:2.0.17:runtime [INFO] | | +- com.auth0:java-jwt:jar:4.5.0:compile [INFO] | | +- org.bouncycastle:bcprov-jdk18on:jar:1.80:compile [INFO] | | - org.bouncycastle:bcpkix-jdk18on:jar:1.80:compile [INFO] | | - org.bouncycastle:bcutil-jdk18on:jar:1.80:compile [INFO] | +- com.sap.cloud.sdk.cloudplatform:connectivity-destination-service:jar:5.18.0:compile [INFO] | | - org.apache.httpcomponents:httpclient:jar:4.5.14:provided [INFO] | +- com.sap.cloud.sdk.cloudplatform:connectivity-oauth:jar:5.18.0:compile [INFO] | +- com.sap.cloud.sdk.cloudplatform:cloudplatform-core:jar:5.18.0:compile [INFO] | +- com.sap.cloud.sdk.cloudplatform:servlet-jakarta:jar:5.18.0:compile [INFO] | +- com.sap.cloud.sdk.cloudplatform:tenant:jar:5.18.0:compile [INFO] | +- com.sap.cloud.sdk.cloudplatform:security:jar:5.18.0:compile [INFO] | +- com.sap.cloud.sdk.cloudplatform:resilience:jar:5.18.0:compile [INFO] | - com.sap.cloud.sdk.cloudplatform:caching:jar:5.18.0:compile [INFO] - com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:jar:20240325.1:compile [INFO] +- com.googlecode.owasp-java-html-sanitizer:java8-shim:jar:20240325.1:compile [INFO] - com.googlecode.owasp-java-html-sanitizer:java10-shim:jar:20240325.1:compile

Stack Trace

Relevant log output

Received OData response with status code '404': Returning empty result
--
com.sap.cds.services.impl.ServiceImpl | Finished emit of 'API_CNSLDTNADHOCITEM' for event 'DELETE', entity 'API_CNSLDTNADHOCITEM.AdhocItem'

com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientWrapper | Added HTTP header with key sap-client originating from a DefaultHttpDestination with target URI https://my300470.s4hana.ondemand.com for new outbound HTTP request.

com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientWrapper | Added HTTP header with key sap-language originating from a DefaultHttpDestination with target URI https://my300470.s4hana.ondemand.com for new outbound HTTP request.

com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientWrapper | Added HTTP header with key Authorization originating from a DefaultHttpDestination with target URI https://my300470.s4hana.ondemand.com for new outbound HTTP request.

com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientWrapper | Added HTTP header with key X-CorrelationID originating from a DefaultHttpDestination with target URI https://my300470.s4hana.ondemand.com for new outbound HTTP request.

com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination | Found these 4 destination header providers: [com.sap.cloud.sdk.cloudplatform.connectivity.AuthTokenHeaderProvider@171740f9, com.sap.cds.integration.cloudsdk.provider.CorrelationIdHeaderProvider@ed12b71, com.sap.cloud.sdk.cloudplatform.connectivity.ErpDestinationHeaderProvider@467f62d7, com.sap.cloud.conso.utils.GrdcDestinationHeaderProvider@74e4d4c1]

com.sap.cloud.sdk.cloudplatform.connectivity.UriPathMerger | Merged https://my300470.s4hana.ondemand.com/sap/opu/odata/sap/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1') and /? into /sap/opu/odata/sap/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1')

com.sap.cloud.sdk.cloudplatform.connectivity.UriPathMerger | Merging request path / into destination path /sap/opu/odata/sap/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1'): /sap/opu/odata/sap/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1')

com.sap.cloud.sdk.cloudplatform.connectivity.UriPathMerger | Merged https://my300470.s4hana.ondemand.com and /sap/opu/odata/sap/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1') into /sap/opu/odata/sap/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1')

com.sap.cloud.sdk.cloudplatform.connectivity.UriPathMerger | Merging request path /sap/opu/odata/sap/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1') into destination path : /sap/opu/odata/sap/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1')

com.sap.cloud.sdk.cloudplatform.connectivity.DefaultCsrfTokenRetriever | Successfully retrieved CSRF token CsrfToken(token=4gql_oPK6SyLJL6ldFIVbQ==) from service path sap/opu/odata/sap/API_CNSLDTNADHOCITEM

com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientWrapper | Added HTTP header with key sap-client originating from a DefaultHttpDestination with target URI https://my300470.s4hana.ondemand.com for new outbound HTTP request.

com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientWrapper | Added HTTP header with key sap-language originating from a DefaultHttpDestination with target URI https://my300470.s4hana.ondemand.com for new outbound HTTP request.

com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientWrapper | Added HTTP header with key Authorization originating from a DefaultHttpDestination with target URI https://my300470.s4hana.ondemand.com for new outbound HTTP request.

com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientWrapper | Added HTTP header with key X-CorrelationID originating from a DefaultHttpDestination with target URI https://my300470.s4hana.ondemand.com for new outbound HTTP request.

com.sap.cloud.sdk.datamodel.odata.client.request.ODataRequestGeneric | Version identifier for ODataRequestDelete is either not defined on the entity or is explicitly ignored.

com.sap.cloud.sdk.cloudplatform.connectivity.UriPathMerger | Merged https://my300470.s4hana.ondemand.com and sap/opu/odata/sap/API_CNSLDTNADHOCITEM into /sap/opu/odata/sap/API_CNSLDTNADHOCITEM

com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination | Found these 4 destination header providers: [com.sap.cloud.sdk.cloudplatform.connectivity.AuthTokenHeaderProvider@171740f9, com.sap.cds.integration.cloudsdk.provider.CorrelationIdHeaderProvider@ed12b71, com.sap.cloud.sdk.cloudplatform.connectivity.ErpDestinationHeaderProvider@467f62d7, com.sap.cloud.conso.utils.GrdcDestinationHeaderProvider@74e4d4c1]

com.sap.cloud.sdk.cloudplatform.connectivity.UriPathMerger | Merged https://my300470.s4hana.ondemand.com/sap/opu/odata/sap/API_CNSLDTNADHOCITEM and /? into /sap/opu/odata/sap/API_CNSLDTNADHOCITEM

com.sap.cloud.sdk.cloudplatform.connectivity.UriPathMerger | Merging request path sap/opu/odata/sap/API_CNSLDTNADHOCITEM into destination path : /sap/opu/odata/sap/API_CNSLDTNADHOCITEM

com.sap.cloud.sdk.cloudplatform.connectivity.UriPathMerger | Merging request path / into destination path /sap/opu/odata/sap/API_CNSLDTNADHOCITEM: /sap/opu/odata/sap/API_CNSLDTNADHOCITEM

com.sap.cds.services.impl.odata.RemoteODataHandler | DELETE >>sap/opu/odata/sap/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due 5 + - Due after 5th years',ConsolidationChartOfAccounts='Y1')<<

com.sap.cds.services.impl.odata.RemoteODataHandler | CQN (projected) >>{"DELETE":{"from":{"ref":["API_CNSLDTNADHOCITEM.AdhocItem"]},"where":[{"ref":["CnsldtnAdhocItem"]},"=",{"val":"Due 5 + - Due after 5th years"},"and",{"ref":["ConsolidationChartOfAccounts"]},"=",{"val":"Y1"}]}}<<

com.sap.cds.services.impl.odata.RemoteODataClient | CQN >>{"DELETE":{"from":{"ref":["API_CNSLDTNADHOCITEM.AdhocItem"]},"where":[{"ref":["CnsldtnAdhocItem"]},"=",{"val":"Due 5 + - Due after 5th years"},"and",{"ref":["ConsolidationChartOfAccounts"]},"=",{"val":"Y1"}]}}<<

Impact

Impaired

MahdiBarkia avatar May 13 '25 12:05 MahdiBarkia

🚫/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20+%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1')

/API_CNSLDTNADHOCITEM/AdhocItem(CnsldtnAdhocItem='Due%205%20%2B%20-%20Due%20after%205th%20years',ConsolidationChartOfAccounts='Y1')

Just an early comment without suggestion: Normally + only requires escaping in query-part of an URL. This is why you see it escaped in your GET-With-Filter (+ in query) and not-escaped in your DELETE-By-Key (+ in path) .

I do not know why S/4 OData Gateway is shitty again.

newtork avatar May 13 '25 13:05 newtork

Hi @MahdiBarkia

We are currently looking into resolving your issue on our side. Unfortunately, we cannot offer a reasonable workaround for you at this point (except for not using + in the relevant names of course).

We will let you know as soon as we have more information. Best, Jonas

Jonas-Isr avatar May 13 '25 15:05 Jonas-Isr

Just curious, does this work for you / will it fix the issue?

Field f = com.sap.cloud.sdk.datamodel.odata.client.request.UriEncodingStrategy.class.getDeclaredField("pathPercentEscaper");
f.setAccessible(true);
f.set(com.sap.cloud.sdk.datamodel.odata.client.request.UriEncodingStrategy.REGULAR, new com.google.common.net.PercentEscaper("-._~!$'()*,;&=@:", false));

newtork avatar May 13 '25 15:05 newtork

We call remoteService.run(Delete.from(AdhocItem_.class).matching(adhocItemEntryToDelete)); which uses https://github.wdf.sap.corp/cds-java/cds-services/blob/main/cds-feature-remote-odata/src/main/java/com/sap/cds/services/impl/odata/RemoteODataHandler.java#L361 to prepare the entityPath and Cloud SDK uses ODataUriFactory to encode URI. Typically, encoding should happen at the time of constructing the URL, not within CRUD method. We need to ensure URL encoding occurs at the appropriate layer.

MahdiBarkia avatar May 14 '25 09:05 MahdiBarkia

My code suggestion is an offer to (potentially) fix it immediately for you in your code-base. Any other potential solution e.g. updating Cloud SDK or CAP will take many days / weeks.

newtork avatar May 14 '25 12:05 newtork

We decided to not fix the bug, please use the workaround instead. If more people are experiencing this issue, please leave a comment here.

CharlesDuboisSAP avatar May 22 '25 09:05 CharlesDuboisSAP

The workaround works as expected. Many thanks for your support! But CAP Colleagues asked me to discuss with you the following:

https://docs.oasis-open.org/odata/odata/v4.02/csd01/part2-url-conventions/odata-v4.02-csd01-part2-url-conventions.html#URLParsing

Note: neither RFC3986 nor this specification assign special meaning to “+” (octet 0x2B). Some implementations decode “+” (octet 0x2B) as space (octet 0x20), others take it literally.

Clients SHOULD percent-encode space (octet 0x20) as %20 and “+” (octet 0x2B) as %2B and avoid the ambiguous “+” (octet 0x2B) in URLs.

MahdiBarkia avatar May 22 '25 10:05 MahdiBarkia

We decided to not fix the bug, please use the https://github.com/SAP/cloud-sdk-java/issues/802#issuecomment-2876999103 instead.

Just to be clear: It's not a bug on client side.

Clients SHOULD percent-encode ... “+” (octet 0x2B) as %2B

Interesting. The link you shared is linking to the draft for v4.02, and this statement seems to be added there, its not in the current v4.01 version.

While I generally agree that it's better to encode, we run the risk that if we change it now, an existing use case may break. Maybe we can find a way to make the opt-in a bit easier, so that reflection isn't needed anymore and change this in the next major version.

MatKuhr avatar May 22 '25 12:05 MatKuhr

I understand the risk related to changing the current version. And hope this will be available with next major Release but as the reflection is necessary for the workaround, I need to ensure that the impact is well-contained.

MahdiBarkia avatar May 22 '25 13:05 MahdiBarkia