dd-trace-java icon indicating copy to clipboard operation
dd-trace-java copied to clipboard

🐞🐛 Serialization issue when IAST enabled with spring boot + kotlinx serialization

Open Chuckame opened this issue 1 year ago • 4 comments

Currently

Given a spring boot application using kotlinx serialization and the dd-java-agent with IAST enabled When we call the endpoint, answering in json Then we get the following error:

500 Server Error for HTTP GET "/bug"

kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Unresolved class: class me.chosante.SerializableByKotlinX$$serializer
		at kotlin.reflect.jvm.internal.KClassImpl.reportUnresolvedClass(KClassImpl.kt:329) ~[kotlin-reflect-1.5.32.jar!/:1.5.32-release-578(1.5.32)]
		at kotlin.reflect.jvm.internal.KClassImpl.access$reportUnresolvedClass(KClassImpl.kt:44) ~[kotlin-reflect-1.5.32.jar!/:1.5.32-release-578(1.5.32)]
		at kotlin.reflect.jvm.internal.KClassImpl$Data$descriptor$2.invoke(KClassImpl.kt:56) ~[kotlin-reflect-1.5.32.jar!/:1.5.32-release-578(1.5.32)]
		at kotlin.reflect.jvm.internal.KClassImpl$Data$descriptor$2.invoke(KClassImpl.kt:47) ~[kotlin-reflect-1.5.32.jar!/:1.5.32-release-578(1.5.32)]
		at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:92) ~[kotlin-reflect-1.5.32.jar!/:1.5.32-release-578(1.5.32)]
		at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31) ~[kotlin-reflect-1.5.32.jar!/:1.5.32-release-578(1.5.32)]
		at kotlin.reflect.jvm.internal.KClassImpl$Data.getDescriptor(KClassImpl.kt) ~[kotlin-reflect-1.5.32.jar!/:1.5.32-release-578(1.5.32)]
		at kotlin.reflect.jvm.internal.KClassImpl.getDescriptor(KClassImpl.kt:182) ~[kotlin-reflect-1.5.32.jar!/:1.5.32-release-578(1.5.32)]
		at kotlin.reflect.full.KClasses.getCompanionObject(KClasses.kt:52) ~[kotlin-reflect-1.5.32.jar!/:1.5.32-release-578(1.5.32)]
		at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector.hasCreatorAnnotation(KotlinNamesAnnotationIntrospector.kt:85) ~[jackson-module-kotlin-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector.access$hasCreatorAnnotation(KotlinNamesAnnotationIntrospector.kt:30) ~[jackson-module-kotlin-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector$hasCreatorAnnotation$2.invoke(KotlinNamesAnnotationIntrospector.kt:97) ~[jackson-module-kotlin-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector$hasCreatorAnnotation$2.invoke(KotlinNamesAnnotationIntrospector.kt:97) ~[jackson-module-kotlin-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.module.kotlin.ReflectionCache.checkConstructorIsCreatorAnnotated(ReflectionCache.kt:99) ~[jackson-module-kotlin-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector.hasCreatorAnnotation(KotlinNamesAnnotationIntrospector.kt:97) ~[jackson-module-kotlin-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.AnnotationIntrospector.findCreatorAnnotation(AnnotationIntrospector.java:1413) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findCreatorAnnotation(AnnotationIntrospectorPair.java:786) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findCreatorAnnotation(AnnotationIntrospectorPair.java:786) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreatorParam(POJOPropertiesCollector.java:722) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreatorParam(POJOPropertiesCollector.java:695) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:644) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:451) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getJsonValueAccessor(POJOPropertiesCollector.java:286) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findJsonValueAccessor(BasicBeanDescription.java:258) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.findSerializerByAnnotations(BasicSerializerFactory.java:393) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:225) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:174) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1503) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1451) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.SerializerProvider._findExplicitUntypedSerializer(SerializerProvider.java:1420) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.hasSerializerFor(DefaultSerializerProvider.java:259) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at com.fasterxml.jackson.databind.ObjectMapper.canSerialize(ObjectMapper.java:3563) ~[jackson-databind-2.15.3.jar!/:2.15.3]
		at org.springframework.http.codec.json.AbstractJackson2Encoder.canEncode(AbstractJackson2Encoder.java:131) ~[spring-web-6.0.16.jar!/:6.0.16]
		at org.springframework.http.codec.EncoderHttpMessageWriter.canWrite(EncoderHttpMessageWriter.java:114) ~[spring-web-6.0.16.jar!/:6.0.16]
		at org.springframework.web.reactive.result.method.annotation.AbstractMessageWriterResultHandler.getMediaTypesFor(AbstractMessageWriterResultHandler.java:228) ~[spring-webflux-6.0.16.jar!/:6.0.16]
		at org.springframework.web.reactive.result.method.annotation.AbstractMessageWriterResultHandler.lambda$writeBody$0(AbstractMessageWriterResultHandler.java:164) ~[spring-webflux-6.0.16.jar!/:6.0.16]
		at org.springframework.web.reactive.result.HandlerResultHandlerSupport.getProducibleTypes(HandlerResultHandlerSupport.java:190) ~[spring-webflux-6.0.16.jar!/:6.0.16]
		at org.springframework.web.reactive.result.HandlerResultHandlerSupport.selectMediaType(HandlerResultHandlerSupport.java:141) ~[spring-webflux-6.0.16.jar!/:6.0.16]
		at org.springframework.web.reactive.result.HandlerResultHandlerSupport.selectMediaType(HandlerResultHandlerSupport.java:121) ~[spring-webflux-6.0.16.jar!/:6.0.16]
		at org.springframework.web.reactive.result.method.annotation.AbstractMessageWriterResultHandler.writeBody(AbstractMessageWriterResultHandler.java:164) ~[spring-webflux-6.0.16.jar!/:6.0.16]
		at org.springframework.web.reactive.result.method.annotation.ResponseEntityResultHandler.lambda$handleResult$1(ResponseEntityResultHandler.java:190) ~[spring-webflux-6.0.16.jar!/:6.0.16]
		at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:152) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoFlatMap.subscribeOrReturn(MonoFlatMap.java:53) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:57) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at datadog.trace.instrumentation.springwebflux.server.AdviceUtils$SpanSubscriber.onNext(AdviceUtils.java:89) ~[na:na]
		at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.complete(MonoIgnoreThen.java:292) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onNext(MonoIgnoreThen.java:187) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onSubscribe(MonoIgnoreThen.java:134) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:192) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoFlatMap.subscribeOrReturn(MonoFlatMap.java:53) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:57) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:240) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:189) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.Operators.complete(Operators.java:137) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:121) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:258) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:139) ~[reactor-core-3.5.14.jar!/:3.5.14]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[reactor-core-3.5.14.jar!/:3.5.14]
[...]

Expectation

Without IAST enabled, it just works (e.g. no error).

How to reproduce

Here is a minimal project including the instructions to reproduce it (3 command lines): https://github.com/CharlyRien/repro-dd-iast-enabled-bug.git

Chuckame avatar Feb 22 '24 16:02 Chuckame

Hello @Chuckame, many thanks for reporting the issue and the and the repo reproducing the issue. We are investigating the issue.

manuel-alvarez-alvarez avatar Feb 22 '24 17:02 manuel-alvarez-alvarez

To add more context about the bug comprehension, the jackson serializer tries to serialize the Companion static field, that have the failing $$serializer class. Before, this companion field was just skipped.

Chuckame avatar Feb 22 '24 17:02 Chuckame

To add more context about the bug comprehension, the jackson serializer tries to serialize the Companion static field, that have the failing $$serializer class. Before, this companion field was just skipped.

Hello @Chuckame I've created a PR for byte-buddy that should solve the issue, we'll come back to you as soon as we have an updated agent.

Thanks for your patience.

manuel-alvarez-alvarez avatar Feb 22 '24 19:02 manuel-alvarez-alvarez

Hello @manuel-alvarez-alvarez many thanks for the reactivity 🚀

Chuckame avatar Feb 22 '24 22:02 Chuckame

Hello @Chuckame,

We've just released the version 1.32.0 that solves the issue you found when enabling IAST with Kotlin serialization.

Many thanks for your patience!

manuel-alvarez-alvarez avatar Apr 04 '24 15:04 manuel-alvarez-alvarez