When running the native-image from the spring-native rsocket sample in this branch, it fails with this exception:

org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'server.servlet.encoding' to org.springframework.boot.web.servlet.server.Encoding
    at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:387) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:347) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:332) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.context.properties.bind.Binder.bindOrCreate(Binder.java:324) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.context.properties.bind.Binder.bindOrCreate(Binder.java:293) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.context.properties.bind.Binder.bindOrCreate(Binder.java:278) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration.stringHttpMessageConverter(HttpMessageConvertersAutoConfiguration.java:80) ~[rsocket:3.0.0-SNAPSHOT]
    at java.lang.reflect.Method.invoke(Method.java:568) ~[rsocket:na]
    at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:281) ~[na:na]
    at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.instantiate(AutowiredInstantiationArgumentsResolver.java:360) ~[na:na]
    at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.instantiate(AutowiredInstantiationArgumentsResolver.java:332) ~[na:na]
    at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.resolveAndInstantiate(AutowiredInstantiationArgumentsResolver.java:195) ~[na:na]
    at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.resolveAndInstantiate(AutowiredInstantiationArgumentsResolver.java:177) ~[na:na]
    at org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration_StringHttpMessageConverterConfiguration__BeanDefinitions.getStringHttpMessageConverterInstance(HttpMessageConvertersAutoConfiguration_StringHttpMessageConverterConfiguration__BeanDefinitions.java:52) ~[na:na]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1223) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1209) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1156) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:566) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:526) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:930) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:926) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:592) ~[rsocket:6.0.0-SNAPSHOT]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:735) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:431) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1307) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1296) ~[rsocket:3.0.0-SNAPSHOT]
    at com.example.rsocket.RSocketApplication.main(RSocketApplication.java:12) ~[rsocket:0.0.1-SNAPSHOT]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.server.Encoding]: No default constructor found
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:146) ~[na:na]
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.create(JavaBeanBinder.java:67) ~[na:na]
    at org.springframework.boot.context.properties.bind.Binder.create(Binder.java:369) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.context.properties.bind.Binder.handleBindResult(Binder.java:358) ~[rsocket:3.0.0-SNAPSHOT]
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:344) ~[rsocket:3.0.0-SNAPSHOT]
    ... 30 common frames omitted
Caused by: java.lang.NoSuchMethodException: org.springframework.boot.web.servlet.server.Encoding.<init>()
    at java.lang.Class.getConstructor0(DynamicHub.java:3585) ~[rsocket:na]
    at java.lang.Class.getDeclaredConstructor(DynamicHub.java:2754) ~[rsocket:na]
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141) ~[na:na]
    ... 34 common frames omitted

Seems there are some hints for the binding missing.

Comment From: wilkinsona

In an app with a ServerProperties bean, I don't think this will occur as we'll already have hints for binding ServerProperties.

Two questions come to mind:

  • Why are we using the binder directly rather than @EnableConfigurationProperties(ServerProperties.class)?
  • Why is HttpMessageConvertersAutoConfiguration active in a pure RSocket app?

Comment From: mhalbritter

To answer the 2nd question:

   HttpMessageConvertersAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.http.converter.HttpMessageConverter' (OnClassCondition)
      - NoneNestedConditions 0 matched 1 did not; NestedCondition on HttpMessageConvertersAutoConfiguration.NotReactiveWebApplicationCondition.ReactiveWebApplication did not find reactive web application classes (HttpMessageConvertersAutoConfiguration.NotReactiveWebApplicationCondition)

org.springframework.boot:spring-boot-starter-rsocket uses org.springframework.boot:spring-boot-starter-json, which in turn uses org.springframework:spring-web

Comment From: wilkinsona

I'd like to discuss this with the team. I'm wondering about both tightening up the conditions and possibly switching to using ServerProperties rather than calling the binder manually.

Comment From: mbhave

We discussed this on the team call. We don't use ServerProperties directly due to this issue. Given that, we'd need to add hints for Encoding.

Comment From: wilkinsona

The current conditions also seemed reasonable. In such an app we suspect we will have also configured RestTemplate (which only requires spring-web) and it uses HTTP message converters.

In short, we need to configure a hint specifically for server.servlet.encoding for situations where StringHttpMessageConverterConfiguration is active without a ServerProperties bean.

Comment From: sdeleuze

Impact Spring Cloud Config as well.