micronaut-projects / micronaut-core

Micronaut Application Framework
http://micronaut.io
Apache License 2.0
6.07k stars 1.07k forks source link

Request deserializer doesn't respect `jackson.property-naming-strategy` #4669

Closed tandel-pratik closed 3 years ago

tandel-pratik commented 3 years ago

Thanks for reporting an issue, please review the task list below before submitting the issue. Your issue report will be closed if the issue is incomplete and the below tasks not completed.

NOTE: If you are unsure about something and the issue is more of a question a better place to ask questions is on Stack Overflow (https://stackoverflow.com/tags/micronaut) or Gitter (https://gitter.im/micronautfw/). DO NOT use the issue tracker to ask questions.

Task List

Steps to Reproduce

Define an application.yml file with this config

  property-naming-strategy: SNAKE_CASE

Define a request data class like

data class Applicant(firstName: String, lastName: String)
data class MyRequest(applicant: Applicant)

send a request with snake-case JSON values {"first_name": "Jill", "last_name": "Doe"}

Stacktrace:

17:12:34.870 [default-nioEventLoopGroup-5-3] DEBUG i.m.http.server.netty.RoutingInBoundHandler - Encoding emitted response object [ /request - Failed to convert argument [request] for value [null] due to: Missing required creator property 'lastName' (index 0)
 at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: MyRequest["applicant"])] using codec: io.micronaut.jackson.codec.JsonMediaTypeCodec@60012a5f

Note: Setting JsonProperty on the data class field names works as expected but is clearly a tedious and error prone workaround.

Expected Behaviour

Actual Behaviour

Environment Information

Example Application

jameskleeh commented 3 years ago

Is MyRequest annotated with @Introspected?

tandel-pratik commented 3 years ago

Is MyRequest annotated with @Introspected?

Yes it's annotated with @Introspected and the controller annotates it's method with @Body @Valid

jameskleeh commented 3 years ago

@pratik-brex An example app would make it more likely that this gets attention sooner

tandel-pratik commented 3 years ago

@pratik-brex An example app would make it more likely that this gets attention sooner

Here's a repro: https://github.com/pratik-brex/micronaut-demo/tree/main/mndemo and this test fails: https://github.com/pratik-brex/micronaut-demo/blob/main/mndemo/src/test/kotlin/mndemo/HelloControllerTest.kt with this stack trace

io.micronaut.http.client.exceptions.HttpClientResponseException: Failed to convert argument [applicant] for value [null] due to: Missing required creator property 'firstName' (index 0)
 at [Source: UNKNOWN; line: -1, column: -1]
    at io.micronaut.http.client.netty.DefaultHttpClient$12.channelRead0(DefaultHttpClient.java:2116)
    at io.micronaut.http.client.netty.DefaultHttpClient$12.channelRead0(DefaultHttpClient.java:2031)
    at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:193)
    at io.micronaut.http.netty.stream.HttpStreamsClientHandler.channelRead(HttpStreamsClientHandler.java:183)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:832)
ikarsokolov commented 3 years ago

Same issues happens with declarative HTTP client parameters binding.

jackson:
  property-naming-strategy: SNAKE_CASE
@Client
interface SampleApiClient {
    @Post("/events")
    fun create(parentId: String? = null, name: String? = null, stateId: String? = null): Mono<Result>
}
02:54:15.425 [default-nioEventLoopGroup-1-5] TRACE i.m.h.client.netty.DefaultHttpClient - Request Body
02:54:15.425 [default-nioEventLoopGroup-1-5] TRACE i.m.h.client.netty.DefaultHttpClient - ----
02:54:15.425 [default-nioEventLoopGroup-1-5] TRACE i.m.h.client.netty.DefaultHttpClient - {"parentId":"5cb8214a2660ff7f5ad07ffc","name":"c1/i10","stateId":"abc"}
02:54:15.425 [default-nioEventLoopGroup-1-5] TRACE i.m.h.client.netty.DefaultHttpClient - ----

Note that parentId and stateId property names are in LOWER_CAMEL_CASE.

Customizing ObjectMapper with BeanCreatedEventListener<ObjectMapper> makes no difference.

mattmoss commented 3 years ago

This has been fixed already in Micronaut v2.3.3.

surajchhetry commented 2 years ago

I am having the same problem with Micronauts 3.3.1 and JDK 17