Hi,
Here is my configuration: Version 3.1.1 of Springboot (reactive), native generation, MacOS ARM-M1, OpenJDK Runtime Environment GraalVM 17.0.7+8.1
Everything works fine when compiled with gradle bootJar
When I compile using native mode (gradle nativeCompile), and run the app, I get the following stack trace.
Full source code is available here: https://github.com/operrin/native-hateoas
Thanks
2023-06-24T11:38:49.087+02:00 ERROR 36501 --- [ctor-http-nio-2] a.w.r.e.AbstractErrorWebExceptionHandler : [7d988f12-1] 500 Server Error for HTTP GET "/intervenants"
org.springframework.core.codec.EncodingException: JSON encoding error: Error creating bean with name 'org.springframework.hateoas.EntityModel$MapSuppressingUnwrappingSerializer': Failed to instantiate [org.springframework.hateoas.EntityModel$MapSuppressingUnwrappingSerializer]: No default constructor found
at org.springframework.http.codec.json.AbstractJackson2Encoder.encodeValue(AbstractJackson2Encoder.java:259) ~[intervenant-service:6.0.10]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ Handler org.miage.intervenantservice.boundary.IntervenantRouter$$Lambda$33f6ea66eb22970ddf524a223f0b6a228e9aeae3@2155835a [DispatcherHandler]
*__checkpoint ⇢ HTTP GET "/intervenants" [ExceptionHandlingWebHandler]
Original Stack Trace:
at org.springframework.http.codec.json.AbstractJackson2Encoder.encodeValue(AbstractJackson2Encoder.java:259) ~[intervenant-service:6.0.10]
at org.springframework.http.codec.json.AbstractJackson2Encoder.lambda$encode$0(AbstractJackson2Encoder.java:158) ~[intervenant-service:6.0.10]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:113) ~[na:na]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:245) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:305) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[na:na]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[na:na]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onSubscribe(MonoFlatMap.java:291) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96) ~[na:na]
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2071) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:118) ~[na:na]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:847) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:609) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:589) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onComplete(FluxFlatMap.java:466) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.deferredComplete(FluxUsingWhen.java:392) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxUsingWhen$CommitInner.onComplete(FluxUsingWhen.java:527) ~[na:na]
at reactor.core.publisher.Operators.complete(Operators.java:137) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:46) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.onComplete(FluxUsingWhen.java:384) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onComplete(FluxConcatMapNoPrefetch.java:240) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2205) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.deferredComplete(FluxUsingWhen.java:392) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxUsingWhen$CommitInner.onComplete(FluxUsingWhen.java:527) ~[na:na]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2205) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[na:na]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2205) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:209) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:209) ~[intervenant-service:3.5.7]
at reactor.pool.SimpleDequePool.maybeRecycleAndDrain(SimpleDequePool.java:531) ~[intervenant-service:1.0.0]
at reactor.pool.SimpleDequePool$QueuePoolRecyclerInner.onComplete(SimpleDequePool.java:761) ~[intervenant-service:1.0.0]
at reactor.core.publisher.Operators.complete(Operators.java:137) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:46) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[intervenant-service:3.5.7]
at reactor.pool.SimpleDequePool$QueuePoolRecyclerMono.subscribe(SimpleDequePool.java:873) ~[na:na]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[na:na]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:240) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[na:na]
at reactor.core.publisher.Operators.complete(Operators.java:137) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:46) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[na:na]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[na:na]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:240) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onComplete(MonoIgnoreElements.java:89) ~[na:na]
at reactor.core.publisher.FluxHandle$HandleSubscriber.onComplete(FluxHandle.java:223) ~[na:na]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:85) ~[na:na]
at reactor.core.publisher.MonoCallable$MonoCallableSubscription.request(MonoCallable.java:159) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2215) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoCallable.subscribe(MonoCallable.java:48) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[na:na]
at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onError(MonoIgnoreElements.java:84) ~[na:na]
at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:134) ~[na:na]
at reactor.core.publisher.FluxFilter$FilterSubscriber.onError(FluxFilter.java:157) ~[na:na]
at reactor.core.publisher.FluxFilter$FilterConditionalSubscriber.onError(FluxFilter.java:291) ~[na:na]
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onError(FluxMap.java:265) ~[na:na]
at reactor.core.publisher.Operators.error(Operators.java:198) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoError.subscribe(MonoError.java:53) ~[na:na]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.onComplete(FluxUsingWhen.java:384) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:847) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:609) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:589) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onComplete(FluxFlatMap.java:466) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[na:na]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:152) ~[na:na]
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:357) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:294) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[na:na]
at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164) ~[na:na]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:371) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92) ~[na:na]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96) ~[na:na]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:201) ~[na:na]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:83) ~[na:na]
at reactor.core.publisher.Flux.subscribe(Flux.java:8773) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:200) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFlatMap.subscribeOrReturn(FluxFlatMap.java:93) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Flux.subscribe(Flux.java:8759) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxUsingWhen$ResourceSubscriber.onNext(FluxUsingWhen.java:195) ~[na:na]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122) ~[na:na]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[na:na]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[na:na]
at reactor.core.publisher.FluxRetry$RetrySubscriber.onNext(FluxRetry.java:87) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:245) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:305) ~[intervenant-service:3.5.7]
at io.r2dbc.pool.MonoDiscardOnCancel$MonoDiscardOnCancelSubscriber.onNext(MonoDiscardOnCancel.java:92) ~[na:na]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[na:na]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.complete(MonoIgnoreThen.java:292) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onNext(MonoIgnoreThen.java:187) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:236) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onComplete(MonoIgnoreElements.java:89) ~[na:na]
at reactor.core.publisher.FluxHandle$HandleSubscriber.onComplete(FluxHandle.java:223) ~[na:na]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:85) ~[na:na]
at reactor.core.publisher.MonoCallable$MonoCallableSubscription.request(MonoCallable.java:159) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2215) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoCallable.subscribe(MonoCallable.java:48) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[intervenant-service:3.5.7]
at io.r2dbc.pool.MonoDiscardOnCancel.subscribe(MonoDiscardOnCancel.java:50) ~[na:na]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[intervenant-service:3.5.7]
at reactor.pool.AbstractPool$Borrower.deliver(AbstractPool.java:467) ~[intervenant-service:1.0.0]
at reactor.pool.SimpleDequePool.lambda$drainLoop$8(SimpleDequePool.java:368) ~[intervenant-service:1.0.0]
at reactor.core.scheduler.ImmediateScheduler.schedule(ImmediateScheduler.java:52) ~[na:na]
at reactor.pool.SimpleDequePool.drainLoop(SimpleDequePool.java:368) ~[intervenant-service:1.0.0]
at reactor.pool.SimpleDequePool.pendingOffer(SimpleDequePool.java:598) ~[intervenant-service:1.0.0]
at reactor.pool.SimpleDequePool.doAcquire(SimpleDequePool.java:294) ~[intervenant-service:1.0.0]
at reactor.pool.AbstractPool$Borrower.request(AbstractPool.java:430) ~[intervenant-service:1.0.0]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2215) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117) ~[intervenant-service:3.5.7]
at reactor.pool.SimpleDequePool$QueueBorrowerMono.subscribe(SimpleDequePool.java:716) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[na:na]
at reactor.core.publisher.FluxRetry$RetrySubscriber.resubscribe(FluxRetry.java:117) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoRetry.subscribeOrReturn(MonoRetry.java:50) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4480) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[na:na]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:180) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:134) ~[na:na]
at reactor.core.publisher.Operators.error(Operators.java:198) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoError.subscribe(MonoError.java:53) ~[na:na]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:104) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Flux.subscribe(Flux.java:8773) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:94) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxFromMonoOperator.subscribe(FluxFromMonoOperator.java:83) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxDeferContextual.subscribe(FluxDeferContextual.java:57) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[na:na]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[na:na]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[na:na]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[na:na]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onSubscribe(MonoFlatMap.java:291) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96) ~[na:na]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96) ~[na:na]
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[na:na]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) ~[na:na]
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:258) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863) ~[na:na]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122) ~[na:na]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200) ~[na:na]
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onNext(FluxConcatArray.java:201) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.request(FluxConcatArray.java:276) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:138) ~[na:na]
at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164) ~[na:na]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2305) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:338) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341) ~[intervenant-service:3.5.7]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2215) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoNext$NextSubscriber.onSubscribe(MonoNext.java:70) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onSubscribe(FluxConcatMapNoPrefetch.java:164) ~[intervenant-service:3.5.7]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:201) ~[na:na]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:83) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[na:na]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[intervenant-service:3.5.7]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[na:na]
at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:1006) ~[na:na]
at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:710) ~[na:na]
at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:481) ~[na:na]
at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:621) ~[intervenant-service:1.1.8]
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:113) ~[intervenant-service:1.1.8]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[intervenant-service:4.1.94.Final]
at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:230) ~[intervenant-service:1.1.8]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[intervenant-service:4.1.94.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) ~[intervenant-service:4.1.94.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[intervenant-service:4.1.94.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) ~[na:na]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) ~[na:na]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) ~[na:na]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[na:na]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[na:na]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[na:na]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[na:na]
at java.base@17.0.7/java.lang.Thread.run(Thread.java:833) ~[intervenant-service:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:807) ~[intervenant-service:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:210) ~[na:na]
Comment From: wilkinsona
Your use of WebFlux.Fn means that no information is available in method signatures about the types that will be serialised to JSON. You can use [@RegisterReflectionForBinding](https://docs.spring.io/spring-framework/reference/core/aot.html#aot.hints.register-reflection-for-binding) to provide information about the types that need to be serialised to json. For example, adding@RegisterReflectionForBinding(EntityModel.class)togetIntervenantById` should fix the problem:
$ http :8082/intervenants
HTTP/1.1 200 OK
Content-Length: 175
Content-Type: application/json
{
"content": [
{
"id": "de7d9052-4961-4b4f-938a-3cd12cbe1f82",
"links": [
{}
],
"nom": "Marchal"
},
{
"id": "425e7701-02c6-4de3-9333-a2459eece1c8",
"links": [
{}
],
"nom": "Dubois"
}
],
"links": [
{}
]
}
$ http :8082/intervenants/de7d9052-4961-4b4f-938a-3cd12cbe1f82
HTTP/1.1 200 OK
Content-Length: 77
Content-Type: application/json
{
"id": "de7d9052-4961-4b4f-938a-3cd12cbe1f82",
"links": [
{},
{}
],
"nom": "Marchal"
}
Comment From: odrotbohm
This will be fixed in Spring HATEOAS 2.0.5, 2.1.1 and 2.2 M1. I.e., it will be included in the next Spring Boot 3.x bug fix releases. Fix verified to make the original reproducer work.
Comment From: operrin
Thanks.
To be fully correct, I had to add the following annotation:
@RegisterReflectionForBinding({Link.class, EntityModel.class})
The EntityModel.classto avoid the MapSuppressingUnwrappingSerializer exception.
And the Link.classto get the correct values for the links (otherwise, they are empty)
Comment From: odrotbohm
What request do I have to issue on your sample project to trigger the missing metadata for Link? HypermediaTypeAotProcessor should actually already add that metadata, and we have AOT smoke tests that show links being rendered properly in native images. 🤔
Comment From: operrin
When compiled with gradle bootJar, I issue the request http :8082/intervenants and I get:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 538
{
"content": [
{
"id": "de7d9052-4961-4b4f-938a-3cd12cbe1f82",
"nom": "Marchal",
"prenom": "Thomas",
"commune": "Nancy",
"codepostal": "54000",
"links": [
{
"rel": "self",
"href": "http://localhost:8082/intervenants/de7d9052-4961-4b4f-938a-3cd12cbe1f82"
}
]
},
{
"id": "425e7701-02c6-4de3-9333-a2459eece1c8",
"nom": "Dubois",
"prenom": "Anne",
"commune": "Grenoble",
"codepostal": "38000",
"links": [
{
"rel": "self",
"href": "http://localhost:8082/intervenants/425e7701-02c6-4de3-9333-a2459eece1c8"
}
]
}
],
"links": [
{
"rel": "collection",
"href": "http://localhost:8082/intervenants"
}
]
}
Links are correct.
Using @RegisterReflectionForBinding(EntityModel.class), when compiled with gradle nativeCompile, I get:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 290
{
"content": [
{
"id": "de7d9052-4961-4b4f-938a-3cd12cbe1f82",
"nom": "Marchal",
"prenom": "Thomas",
"commune": "Nancy",
"codepostal": "54000",
"links": [
{}
]
},
{
"id": "425e7701-02c6-4de3-9333-a2459eece1c8",
"nom": "Dubois",
"prenom": "Anne",
"commune": "Grenoble",
"codepostal": "38000",
"links": [
{}
]
}
],
"links": [
{}
]
}
Links are empty.
Using @RegisterReflectionForBinding({Link.class,EntityModel.class}), when compiled with gradle nativeCompile, Links are correct.
Comment From: odrotbohm
Thanks, I'll have a look.
Comment From: odrotbohm
Ar you sure it's Link, not Links (trailing s)? It looks like the problem is a combination of Links not registered for reflection and your project not using a proper hypermedia media type but only application/json. That will cause EntityModel rendered as-is, and thus the custom Jackson directives we have in place for official hypermedia media types like HAL kick in. I can only recommend switching to one of those, as rendering anything but that is not supported officially.
I'll go ahead and augment the reflection registration for Links in the context of spring-projects/spring-hateoas#1981 (and corresponding back ports). But then again, you should see this work if you rather return application/hal+json or any other supported and properly specified hypermedia type.
Comment From: operrin
Thanks.
It works with Link.class.
Regarding the MediaType, I just try the following modification:
@RegisterReflectionForBinding(EntityModel.class)
public Mono<ServerResponse> getIntervenantById(ServerRequest request) {
var collectionLink = Link.of(deleteIdInUri(request.uri().toString(), request.pathVariable("id")))
.withRel("collection");
var selfLink = Link.of(request.uri().toString()).withSelfRel();
return this.is.getIntervenant(request.pathVariable("id"))
.flatMap(r -> Mono.just(EntityModel.of(r, selfLink, collectionLink)))
.flatMap(r -> ServerResponse.ok().contentType(MediaTypes.HAL_JSON).bodyValue(r))
.switchIfEmpty(ServerResponse.notFound().build());
}
The result is empty links.
Comment From: operrin
Sorry, I carefully read your message, and I added a configuration class and used
the @EnableHypermediaSupport annotation, and links are correctly rendered.
My apologies
Comment From: odrotbohm
No need to apologize. This is tremendously helpful. I just realized that the Spring HATEOAS auto-configuration is not activated in a Web.fn scenario. I wonder if that should be fixed by using a trigger type located in the WebFlux artifact? /cc @wilkinsona
Comment From: wilkinsona
https://github.com/spring-projects/spring-boot/issues/16020 is tracking some auto-configuration of HATEOAS with WebFlux. Perhaps we can get it moving again.
Comment From: odrotbohm
After re-reading the conversation in #16020, I think I'll go ahead and separate the AOT reflection hint generation for the fundamental Spring HATEOAS types from the one that covers the Jackson model types producing individual media types. That way, we get HATEOAS working on GraalVM out of the box, even if a user doesn't want to use a proper, supported hypermedia type. Even if we don't recommend that, I think it's better to reasonably work than partially fail.
I'll also mention the need to explicitly use @EnableHypermediaSupport with WebFlux / Web.fn setups in the reference docs.
Comment From: odrotbohm
To close this off for this ticket, I've updated the fix for spring-projects/spring-hateoas#1981 to make sure that all fundamental HATEOAS types are registered for reflection. That said, I still couldn't get proper HAL rendering working for your Web.fn setup. I'll have to investigate separately.