Application context initialization errors with an UnsatisfiedDependencyException when an inner class configured bean is encountered while using Kotlin and Spring Boot. The reported cause is a BeanCreationException due to an ArrayIndexOutOfBoundsException.
Below is the stack trace:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
Oct 29, 2019 10:14:43 PM org.springframework.boot.SpringApplication reportFailure
SEVERE: Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myBeanName': Unsatisfied dependency expressed through field 'restAuthenticationEntryPoint'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myBeanName': Unexpected exception during bean creation; nested exception is java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
at io.github.kwahome.SampleKotlinApplicationKt.main(SampleKotlinApplication.kt:13)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myBeanName': Unexpected exception during bean creation; nested exception is java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:528)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1251)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1171)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
... 24 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:705)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
... 32 more
Reproducer:
import java.time.OffsetDateTime
import javax.servlet.ServletException
import java.io.IOException
import javax.servlet.http.HttpServletResponse
import javax.servlet.http.HttpServletRequest
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.security.servlet.WebSecurityEnablerConfiguration
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpStatus
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter
import org.springframework.stereotype.Component
@Configuration
@EnableWebSecurity
class ApiSecurityConfig : WebSecurityEnablerConfiguration() {
@Value("\${http.auth-token-header-name}")
private val principalRequestHeader: String? = null
@Value("#{'\${http.auth-token}'.split(',')}")
private val principalRequestValues: List<String>? = null
@Autowired
private val restAuthenticationEntryPoint: RestAuthenticationEntryPoint? = null
fun apiAuthenticationFilter(): ApiKeyAuthFilter? {
val filter = principalRequestHeader?.let { ApiKeyAuthFilter(it) }
filter?.setAuthenticationManager { authentication ->
val principal = authentication.principal as String
val validPrincipal = principalRequestValues!!.stream()
.anyMatch { principalRequestValue -> principalRequestValue.trim { it <= ' ' } == principal }
if (!validPrincipal) {
// not made a constant as this value gets converted by to a message that adheres to API standards
// in the RestAuthenticationEntryPoint below.
throw BadCredentialsException("Invalid API Key received.")
}
authentication.isAuthenticated = true
authentication
}
return filter
}
@Throws(Exception::class)
fun configure(httpSecurity: HttpSecurity) {
httpSecurity.cors()
httpSecurity
.antMatcher("**")
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().addFilter(apiAuthenticationFilter()).authorizeRequests()
.anyRequest().authenticated().and()
.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint)
}
@Component
inner class RestAuthenticationEntryPoint : AuthenticationEntryPoint {
@Autowired
private val objectMapper: ObjectMapper? = null
@Throws(IOException::class, ServletException::class)
override fun commence(
httpServletRequest: HttpServletRequest,
httpServletResponse: HttpServletResponse,
exception: AuthenticationException
) {
val response = "Unauthorized"
httpServletResponse.contentType = "application/json"
httpServletResponse.status = HttpStatus.UNAUTHORIZED.value()
val out = httpServletResponse.outputStream
objectMapper!!.writeValue(out, response)
out.flush()
}
}
inner class ApiKeyAuthFilter(private val principalRequestHeader: String) :
AbstractPreAuthenticatedProcessingFilter() {
override fun getPreAuthenticatedPrincipal(request: HttpServletRequest): Any {
return request.getHeader(principalRequestHeader).orEmpty()
}
override fun getPreAuthenticatedCredentials(request: HttpServletRequest): Any {
return "N/A"
}
}
}
Comment From: mbhave
The code in question is in Spring Framework. There is an existing Spring Framework issue related to this.
Comment From: fast-reflexes
How come @Configuration
works on inner classes but not @Component
? I thought a @Configuration
was also a @Component
: https://stackoverflow.com/questions/39174669/what-is-the-difference-between-configuration-and-component-in-spring
Comment From: wilkinsona
@fast-reflexes It doesn't work with @Component
as it's a feature that is specific to @Configuration
classes. If you have any further questions, please follow up on Stack Overflow or Gitter. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.