Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow HTTP message converters to be auto-configured in a native image that is not a web app #31528

Closed
mhalbritter opened this issue Jun 24, 2022 · 6 comments
Assignees
Labels
theme: aot An issue related to Ahead-of-time processing type: enhancement A general enhancement
Milestone

Comments

@mhalbritter
Copy link
Contributor

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.

@mhalbritter mhalbritter added type: bug A general bug theme: aot An issue related to Ahead-of-time processing labels Jun 24, 2022
@mhalbritter mhalbritter added this to the 3.0.x milestone Jun 24, 2022
@wilkinsona
Copy link
Member

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?

@mhalbritter
Copy link
Contributor Author

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

@wilkinsona wilkinsona changed the title native-image: Failed to bind server.servlet.encoding Failed to bind server.servlet.encoding when running a native image Jun 27, 2022
@mhalbritter mhalbritter changed the title Failed to bind server.servlet.encoding when running a native image Add native-image support for StringHttpMessageConverterConfiguration Jun 28, 2022
@mhalbritter mhalbritter added type: enhancement A general enhancement and removed type: bug A general bug labels Jun 28, 2022
@wilkinsona wilkinsona added the for: team-meeting An issue we'd like to discuss as a team to make progress label Jun 28, 2022
@wilkinsona
Copy link
Member

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.

@mbhave
Copy link
Contributor

mbhave commented Jun 29, 2022

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.

@mbhave mbhave removed the for: team-meeting An issue we'd like to discuss as a team to make progress label Jun 29, 2022
@wilkinsona
Copy link
Member

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.

@wilkinsona wilkinsona changed the title Add native-image support for StringHttpMessageConverterConfiguration Allow HTTP message converters to be auto-configured in a native image that is not a web app Jun 29, 2022
@sdeleuze
Copy link
Contributor

Impact Spring Cloud Config as well.

@mhalbritter mhalbritter self-assigned this Jul 19, 2022
@mhalbritter mhalbritter modified the milestones: 3.0.x, 3.0.0-M4 Jul 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme: aot An issue related to Ahead-of-time processing type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants