stormpath-sdk-java
stormpath-sdk-java copied to clipboard
Auto-configuration should have a dedicated exception type and failure analyzer for known scenario
I am creating an empty Spring Boot app with the default stormpath starter. When I run the application, I get the following:
2017-01-31 08:26:30.943 ERROR 13032 --- [ main] o.s.boot.SpringApplication : Application startup failed
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:137) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:536) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at com.example.DemoApplication.main(DemoApplication.java:10) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_112]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_112]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_112]
at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:527) [spring-boot-maven-plugin-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_112]
Caused by: org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.initialize(TomcatEmbeddedServletContainer.java:117) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.<init>(TomcatEmbeddedServletContainer.java:84) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getTomcatEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:537) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:179) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:164) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:134) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
... 14 common frames omitted
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.stormpath.spring.boot.autoconfigure.StormpathWebMvcAutoConfiguration': Unsatisfied dependency expressed through field 'client'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stormpathClient' defined in class path resource [com/stormpath/spring/boot/autoconfigure/StormpathAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.stormpath.sdk.client.Client]: Factory method 'stormpathClient' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stormpathClientApiKey' defined in class path resource [com/stormpath/spring/boot/autoconfigure/StormpathAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.stormpath.sdk.api.ApiKey]: Factory method 'stormpathClientApiKey' threw exception; nested exception is java.lang.IllegalStateException: Unable to find an API Key 'id', either from explicit configuration (for example, ApiKeyBuilder.setApiKeyId) or from fallback locations:
1) system property stormpath.client.apiKey.id
2) resource file path or URL specified by system property stormpath.client.apiKey.file
3) resource file path or URL specified by environment variable STORMPATH_API_KEY_FILE
4) environment variable STORMPATH_API_KEY_ID
5) default apiKey.properties file location /Users/snicoll/.stormpath/apiKey.properties.
Please ensure you manually configure an API Key ID or ensure that it exists in one of these fallback locations.
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
That exception is happening at a weird place, which makes the tomcat starter log it at error level. The IllegalStateException
is then thrown and wrapped in the container-specific exception type. And logged again...
Two things:
- Can you please rework the logic where this exception is thrown so that it happens sooner? Validating the configuration can be enough. That way the exception happens sooner and isn't logged by the embedded container
- Please provide a dedicated exception type (that contains additional information maybe?) and provide a
FailureAnalyzer
for it. That way, that huge exception will be replaced with a very concise message at the bottom of the logs that the user will see immediately. You can easily create your ownFailureAnalyzer
Another way to deal with this issue is to back-off until you get the data that you need. You could move all that logic in a custom condition and disable the auto-configuration if that information isn't available. But I guess the current code is failing on purpose...
Thanks for the feedback @snicoll. We are reviewing the issue.