GsonVdmEntityAdapter causes intermittent IllegalAccessException on VdmComplex subclasses under concurrent serialization
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Java
- Estrellas
- 41
- Forks
- 33
- Merge medio
- 18 h 34 min
- PR fusionados (30 d)
- 19
Descripción
Describe the Bug
From time to time, we could observe some error logs like "Could not serialize property 'ratingPeriodStart'. Returning null instead." from logger "com.sap.cloud.sdk.datamodel.odatav4.adapter.GsonVdmEntityAdapter".
After some analysis, here is the issue:
GsonVdmEntityAdapter stores java.lang.reflect.Field objects in a shared entityProperties map. Under concurrent serialization, the setAccessible(false) restore call on a shared Field object races with another
thread's Field.get(), causing an intermittent IllegalAccessException.
Steps to Reproduce
Reproduction
Using UsageRecordAggregationRequest (a generated VdmComplex subclass) with 100 concurrent threads each performing 100,000 serializations. Reproduces ~60% of test runs.
// Mirrors ActionRequestBuilder's static final fields exactly
private static final Gson GSON = new GsonBuilder().serializeNulls().create();
private static final GsonVdmAdapterFactory GSON_VDM_ADAPTER_FACTORY = new GsonVdmAdapterFactory();
@SuppressWarnings("unchecked")
private static String serializeRequests(List<UsageRecordAggregationRequest> requests) {
var typeToken = TypeToken.get((Class<List<UsageRecordAggregationRequest>>) requests.getClass());
var adapter = GSON_VDM_ADAPTER_FACTORY.create(GSON, typeToken);
return adapter != null
? adapter.toJsonTree(requests).toString()
: GSON.toJsonTree(requests).toString();
}
@Test
void concurrentSerialization_shouldNotThrowIllegalAccessException() throws Exception {
// attach ListAppender to GsonVdmEntityAdapter logger to catch swallowed exceptions
// ... (full test in attachment)
assertThat(illegalAccessLogs).isZero();
}
Observed error log:
ERROR GsonVdmEntityAdapter -- Could not serialize property 'ratingPeriodStart'. Returning null instead.
java.lang.IllegalAccessException: class com.sap.cloud.sdk.datamodel.odatav4.adapter.GsonVdmEntityAdapter
cannot access a member of class ...UsageRecordAggregationRequest with modifiers "private"
at jdk.internal.reflect.Reflection.newIllegalAccessException
at java.lang.reflect.AccessibleObject.checkAccess
at java.lang.reflect.Field.checkAccess
at java.lang.reflect.Field.get
at GsonVdmEntityAdapter.getEntityAsJsonObject(GsonVdmEntityAdapter.java:309)
Expected Behavior
No such errors occur.
Screenshots
No response
Used Versions
- Java and Maven version via
mvn --version:
Apache Maven 3.9.16 (2bdd9fddda4b155ebf8000e807eb73fd829a51d5)
Maven home: /opt/homebrew/Cellar/maven/3.9.16/libexec
Java version: 21.0.11, vendor: SAP SE, runtime: /Library/Java/JavaVirtualMachines/sapmachine-21.jdk/Contents/Home
Default locale: en_CN, platform encoding: UTF-8
OS name: "mac os x", version: "26.5.1", arch: "aarch64", family: "mac"
- SAP Cloud SDK version: 5.31.0
- Spring Boot or CAP version: 3.5.16
Dependency tree via mvn dependency:tree
[INFO] com.sap.ngom:usage-record-client:jar:3.0.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:3.5.16:provided
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:3.5.16:provided
[INFO] | | +- org.springframework.boot:spring-boot:jar:3.5.16:provided
[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:3.5.16:provided
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:3.5.16:provided
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.5.38:provided
[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.5.38:provided
[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.25.4:provided
[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.25.4:provided
[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:2.0.18:provided
[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:2.1.1:provided
[INFO] | | \- org.yaml:snakeyaml:jar:2.4:provided
[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:3.5.16:provided
[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.21.5:provided
[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.21.5:provided
[INFO] | | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.21.5:provided
[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.5.16:provided
[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:10.1.57:provided
[INFO] | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:10.1.57:provided
[INFO] | +- org.springframework:spring-web:jar:6.2.19:provided
[INFO] | | +- org.springframework:spring-beans:jar:6.2.19:provided
[INFO] | | \- io.micrometer:micrometer-observation:jar:1.15.12:provided
[INFO] | | \- io.micrometer:micrometer-commons:jar:1.15.12:provided
[INFO] | \- org.springframework:spring-webmvc:jar:6.2.19:provided
[INFO] | +- org.springframework:spring-aop:jar:6.2.19:provided
[INFO] | +- org.springframework:spring-context:jar:6.2.19:provided
[INFO] | \- org.springframework:spring-expression:jar:6.2.19:provided
[INFO] +- org.springframework.boot:spring-boot-starter-validation:jar:3.5.16:provided
[INFO] | +- org.apache.tomcat.embed:tomcat-embed-el:jar:10.1.57:provided
[INFO] | \- org.hibernate.validator:hibernate-validator:jar:8.0.3.Final:provided
[INFO] | +- jakarta.validation:jakarta.validation-api:jar:3.0.2:provided
[INFO] | +- org.jboss.logging:jboss-logging:jar:3.6.3.Final:provided
[INFO] | \- com.fasterxml:classmate:jar:1.7.3:provided
[INFO] +- com.sap.cloud.sdk.datamodel:odata-v4-core:jar:5.31.0:compile
[INFO] | +- com.sap.cloud.sdk.datamodel:odata-client:jar:5.31.0:compile
[INFO] | +- com.sap.cloud.sdk.cloudplatform:cloudplatform-core:jar:5.31.0:compile
[INFO] | +- com.sap.cloud.sdk.cloudplatform:cloudplatform-connectivity:jar:5.31.0:compile
[INFO] | | +- com.sap.cloud.sdk.cloudplatform:resilience-api:jar:5.31.0:compile
[INFO] | | +- com.sap.cloud.sdk.cloudplatform:security:jar:5.31.0:compile
[INFO] | | +- com.sap.cloud.environment.servicebinding.api:java-core-api:jar:0.31.0:compile
[INFO] | | +- com.sap.cloud.environment.servicebinding.api:java-access-api:jar:0.31.0:compile
[INFO] | | +- com.mikesamuel:json-sanitizer:jar:1.2.3:compile
[INFO] | | +- com.auth0:java-jwt:jar:4.5.2:compile
[INFO] | | +- org.bouncycastle:bcprov-jdk18on:jar:1.84:compile
[INFO] | | \- org.bouncycastle:bcpkix-jdk18on:jar:1.84:compile
[INFO] | | \- org.bouncycastle:bcutil-jdk18on:jar:1.84:compile
[INFO] | +- com.sap.cloud.sdk.cloudplatform:connectivity-apache-httpclient4:jar:5.31.0:compile
[INFO] | | +- com.sap.cloud.sdk.cloudplatform:caching:jar:5.31.0:compile
[INFO] | | +- com.sap.cloud.sdk.cloudplatform:tenant:jar:5.31.0:compile
[INFO] | | \- com.github.ben-manes.caffeine:caffeine:jar:3.2.4:compile
[INFO] | +- com.sap.cloud.sdk.datamodel:fluent-result:jar:5.31.0:compile
[INFO] | +- org.slf4j:slf4j-api:jar:2.0.18:compile
[INFO] | +- org.slf4j:jcl-over-slf4j:jar:2.0.18:runtime
[INFO] | +- com.google.guava:guava:jar:33.6.0-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.errorprone:error_prone_annotations:jar:2.47.0:compile
[INFO] | | \- com.google.j2objc:j2objc-annotations:jar:3.1:compile
[INFO] | +- com.google.code.gson:gson:jar:2.13.2:compile
[INFO] | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.21:compile
[INFO] | +- com.fasterxml.jackson.core:jackson-core:jar:2.21.5:compile
[INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar:2.21.5:compile
[INFO] | +- org.apache.httpcomponents:httpclient:jar:4.5.14:compile
[INFO] | | \- commons-codec:commons-codec:jar:1.18.0:compile
[INFO] | +- io.vavr:vavr:jar:1.0.1:compile
[INFO] | | \- io.vavr:vavr-match:jar:1.0.0:compile
[INFO] | +- org.apache.httpcomponents:httpcore:jar:4.4.16:compile
[INFO] | \- com.google.code.findbugs:jsr305:jar:3.0.2:compile
[INFO] +- org.projectlombok:lombok:jar:1.18.46:provided
[INFO] +- org.apache.commons:commons-lang3:jar:3.18.0:compile
[INFO] +- com.sap.dwc:util-headers:jar:2.17.0:provided
[INFO] | +- com.sap.dwc:util-model:jar:2.17.0:provided
[INFO] | +- org.apache.httpcomponents.client5:httpclient5:jar:5.5.2:provided
[INFO] | | \- org.apache.httpcomponents.core5:httpcore5-h2:jar:5.3.6:provided
[INFO] | +- org.apache.httpcomponents.core5:httpcore5:jar:5.3.6:provided
[INFO] | \- com.sap.dwc.commons:commons-util:jar:2.23.0:provided
[INFO] +- com.sap.dwc:util-routing:jar:2.17.0:provided
[INFO] +- com.sap.ngom:bc-metric-client:jar:2.0.0-20260623084922_a29592b:compile
[INFO] | \- com.jayway.jsonpath:json-path:jar:2.9.0:compile
[INFO] \- org.springframework.boot:spring-boot-starter-test:jar:3.5.16:test
[INFO] +- org.springframework.boot:spring-boot-test:jar:3.5.16:test
[INFO] +- org.springframework.boot:spring-boot-test-autoconfigure:jar:3.5.16:test
[INFO] +- jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.5:test
[INFO] | \- jakarta.activation:jakarta.activation-api:jar:2.1.4:test
[INFO] +- net.minidev:json-smart:jar:2.5.2:runtime
[INFO] | \- net.minidev:accessors-smart:jar:2.5.2:runtime
[INFO] | \- org.ow2.asm:asm:jar:9.7.1:runtime
[INFO] +- org.assertj:assertj-core:jar:3.27.7:test
[INFO] | \- net.bytebuddy:byte-buddy:jar:1.17.8:test
[INFO] +- org.awaitility:awaitility:jar:4.2.2:test
[INFO] +- org.hamcrest:hamcrest:jar:3.0:test
[INFO] +- org.junit.jupiter:junit-jupiter:jar:5.12.2:test
[INFO] | +- org.junit.jupiter:junit-jupiter-api:jar:5.12.2:test
[INFO] | | +- org.opentest4j:opentest4j:jar:1.3.0:test
[INFO] | | +- org.junit.platform:junit-platform-commons:jar:1.12.2:test
[INFO] | | \- org.apiguardian:apiguardian-api:jar:1.1.2:test
[INFO] | +- org.junit.jupiter:junit-jupiter-params:jar:5.12.2:test
[INFO] | \- org.junit.jupiter:junit-jupiter-engine:jar:5.12.2:test
[INFO] | \- org.junit.platform:junit-platform-engine:jar:1.12.2:test
[INFO] +- org.mockito:mockito-core:jar:5.17.0:test
[INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.17.8:test
[INFO] | \- org.objenesis:objenesis:jar:3.3:test
[INFO] +- org.mockito:mockito-junit-jupiter:jar:5.17.0:test
[INFO] +- org.skyscreamer:jsonassert:jar:1.5.3:test
[INFO] | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] +- org.springframework:spring-core:jar:6.2.19:provided
[INFO] | \- org.springframework:spring-jcl:jar:6.2.19:provided
[INFO] +- org.springframework:spring-test:jar:6.2.19:test
[INFO] \- org.xmlunit:xmlunit-core:jar:2.10.4:test
Code Examples
https://github.tools.sap/sb-bnb/usage-record-management-client/pull/660
Stack Trace
java.lang.IllegalAccessException: class com.sap.cloud.sdk.datamodel.odatav4.adapter.GsonVdmEntityAdapter cannot access a member of class com.sap.ngom.urm.client.vdm.namespaces.usagerecords2s.UsageRecordAggregationRequest with modifiers "private"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Unknown Source)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(Unknown Source)
at java.base/java.lang.reflect.Field.checkAccess(Unknown Source)
at java.base/java.lang.reflect.Field.get(Unknown Source)
at com.sap.cloud.sdk.datamodel.odatav4.adapter.GsonVdmEntityAdapter.getEntityAsJsonObject(GsonVdmEntityAdapter.java:309)
at com.sap.cloud.sdk.datamodel.odatav4.adapter.GsonVdmEntityAdapter.write(GsonVdmEntityAdapter.java:277)
at com.sap.cloud.sdk.datamodel.odatav4.adapter.GsonVdmEntityAdapter.write(GsonVdmEntityAdapter.java:41)
at com.google.gson.TypeAdapter$NullSafeTypeAdapter.write(TypeAdapter.java:304)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:73)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:100)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:64)
at com.google.gson.Gson.toJson(Gson.java:943)
at com.google.gson.Gson.toJsonTree(Gson.java:801)
at com.google.gson.Gson.toJsonTree(Gson.java:778)
at com.sap.cloud.sdk.datamodel.odatav4.core.ActionRequestBuilder.serialize(ActionRequestBuilder.java:116)
at com.sap.cloud.sdk.datamodel.odatav4.core.ActionRequestBuilder.lambda$serializeParameters$0(ActionRequestBuilder.java:146)
at java.base/java.util.HashMap.forEach(Unknown Source)
at com.sap.cloud.sdk.datamodel.odatav4.core.ActionRequestBuilder.serializeParameters(ActionRequestBuilder.java:146)
at com.sap.cloud.sdk.datamodel.odatav4.core.ActionRequestBuilder.toRequest(ActionRequestBuilder.java:138)
at com.sap.cloud.sdk.datamodel.odatav4.core.CollectionValueActionRequestBuilder.execute(CollectionValueActionRequestBuilder.java:101)
at com.sap.cloud.sdk.datamodel.odatav4.core.CollectionValueActionRequestBuilder.execute(CollectionValueActionRequestBuilder.java:25)
at com.sap.ngom.urm.client.service.impl.UsageRecordClientImpl.runUsageRecordAggregation(UsageRecordClientImpl.java:76)
Log File
Log file
...Affected Development Phase
Production
Impact
Impaired
Timeline
No response
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Abre GsonVdmEntityAdapter e inspecciona getEntityAsJsonObject alrededor de la línea 309, centrándote en el acceso al entityProperties Field compartido y en la restauración de la accesibilidad descritos en el informe. Reproduce la prueba de serialización concurrente proporcionada con UsageRecordAggregationRequest y verifica que las ejecuciones concurrentes no produzcan logs de IllegalAccessException.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- java
- Área
- api
- Tipo de issue
- Error
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Estado de actividad
- Tranquilo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 55/100