I found a bug recently when using Spring 3.0.5, which appears to be fixed in 4.0.5. Here are the details.
If you have a class that has a parameterized constructor and also has a method that uses a lambda expression (introduced in Java 8), then a ArrayIndexOutOfException occurs when creating a bean for that class.
Here is the stack trace:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 17676
at org.springframework.asm.ClassReader.readClass(Unknown Source)
at org.springframework.asm.ClassReader.accept(Unknown Source)
at org.springframework.asm.ClassReader.accept(Unknown Source)
at org.springframework.core.LocalVariableTableParameterNameDiscoverer.inspectClass(LocalVariableTableParameterNameDiscoverer.java:114)
at org.springframework.core.LocalVariableTableParameterNameDiscoverer.getParameterNames(LocalVariableTableParameterNameDiscoverer.java:86)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:193)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1003)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:907)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at LambdaSpringTest.main(LambdaSpringTest.java:9)
Here are the reproduction steps:
1. A sample class
import java.util.List;
public class LambdaSpring
{
public LambdaSpring(){}
public LambdaSpring(String arg1, String arg2){}
public void method(List<Object> list)
{
list.stream().forEach(t -> System.out.println(t));
}
}
2. Spring Bean configuration
<bean id="lambdaspring" class="LambdaSpring">
<constructor-arg value="blabla"></constructor-arg>
<constructor-arg value="blabla2"></constructor-arg>
</bean>
3. Running this main method will result in ArrayIndexOutOfException
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class LambdaSpringTest
{
public static void main(String[] args)
{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("lamdaspring.xml");
LambdaSpring tmp = (LambdaSpring) context.getBean("lambdaspring");
}
}
This issue appears to be fixed in Spring 4.0.5 (possibly earlier as well), but if you can't upgrade for some reasons, here are some workarounds:
I found that if you don't use the parameterized constructor, then you don't get this exception. Also, if you replace the lambda expression with the equivalent boilerplate code (i.e., implement Consumer interface), then you don't get this exception.
If you have a class that has a parameterized constructor and also has a method that uses a lambda expression (introduced in Java 8), then a ArrayIndexOutOfException occurs when creating a bean for that class.
Here is the stack trace:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 17676
at org.springframework.asm.ClassReader.readClass(Unknown Source)
at org.springframework.asm.ClassReader.accept(Unknown Source)
at org.springframework.asm.ClassReader.accept(Unknown Source)
at org.springframework.core.LocalVariableTableParameterNameDiscoverer.inspectClass(LocalVariableTableParameterNameDiscoverer.java:114)
at org.springframework.core.LocalVariableTableParameterNameDiscoverer.getParameterNames(LocalVariableTableParameterNameDiscoverer.java:86)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:193)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1003)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:907)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at LambdaSpringTest.main(LambdaSpringTest.java:9)
Here are the reproduction steps:
1. A sample class
import java.util.List;
public class LambdaSpring
{
public LambdaSpring(){}
public LambdaSpring(String arg1, String arg2){}
public void method(List<Object> list)
{
list.stream().forEach(t -> System.out.println(t));
}
}
2. Spring Bean configuration
<bean id="lambdaspring" class="LambdaSpring">
<constructor-arg value="blabla"></constructor-arg>
<constructor-arg value="blabla2"></constructor-arg>
</bean>
3. Running this main method will result in ArrayIndexOutOfException
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class LambdaSpringTest
{
public static void main(String[] args)
{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("lamdaspring.xml");
LambdaSpring tmp = (LambdaSpring) context.getBean("lambdaspring");
}
}
This issue appears to be fixed in Spring 4.0.5 (possibly earlier as well), but if you can't upgrade for some reasons, here are some workarounds:
I found that if you don't use the parameterized constructor, then you don't get this exception. Also, if you replace the lambda expression with the equivalent boilerplate code (i.e., implement Consumer interface), then you don't get this exception.
Thank you. The defect has been addressed here:
ReplyDeletehttps://jira.spring.io/browse/SPR-11719
=Duc
Use - 3.2.13.RELEASE
ReplyDeleteUse - 3.2.13.RELEASE
ReplyDeleteThanks. Saved me a lot of time.
ReplyDelete