Search code examples
javaspringjava-8java-bytecode-asm

ArrayOutOfBoundsException: asm.ClassReader.readClass(Unknown Source)


I have a hierarchy with the following dependencies:

Base(Timer timer)

    Timer(PublisherService service, BaseDao userDao, DataProcessor processor)

There are additional dependencies within DataProcessor but I will not go that far because it seems my error occurs a lot earlier. In correspondence with that dependency graph, I have the following Spring configuration:

<bean id="base" class="com.apps.consumer.Base">
    <constructor-arg name="timer" ref="consumerTimerTask"/>
</bean>

<bean id="consumerTimerTask" class="com.apps.consumer.ConsumerTimerTask">
    <constructor-arg name="service" ref="tradePublisherService"/>
    <constructor-arg name="userDao" ref="userDao"/>
    <constructor-arg name="consumerDataProcessor" ref="consumerDataProcessor"/>
</bean>

<bean id="tradePublisherService" class="com.apps.consumer.common.TradePublisherService"/>

<bean id="userDao" class="com.apps.dao.UserDao"/>

<bean id="consumerDataProcessor" class="com.apps.consumer.ConsumerDataProcessor">
    <!-- Additional constructor-args here for this guy -->
</bean>

At the top level of my application, I will run:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-configuration.xml");

Base consumerBase = context.getBean("base", Base.class);

As I follow the debugging I find that the Timer is initialized successfully. . .somewhat. Before the Timer is fully resolved and injected into the Base I get back the following:

java.lang.ArrayIndexOutOfBoundsException: 3145
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.visitConstructor(LocalVariableTableParameterNameDiscoverer.java:123)
at org.springframework.core.LocalVariableTableParameterNameDiscoverer.getParameterNames(LocalVariableTableParameterNameDiscoverer.java:89)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:984)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:886)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:287)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:600)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:140)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:984)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:886)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:287)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:557)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:842)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:416)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.apps.Main.contextInitialized(Main.java:39)

I'm tracing it back as far as Main which is the only class in the stack trace that is mine.

Removing all three constructor parameters in both Java and XML resolves the issue however introducing any one of the 3 constructor arguments brings it back. The dependency graph does go a little deeper for DataProcessor for example, but even if I just use BaseDao as the constructor args, which itself has no dependencies, I will get this error.

Any idea what is going on here? I have tried various permutations of constructor args, creating new interface implementations in case something in my existing ones was causing the issue to bubble up, pretty much everything shy of just rewriting this from scratch more carefully.

EDIT:

public class Base {
    private TimerTask consumerTimerTask;

    private static Logger logger = LoggerFactory.getLogger(Base.class);

    public Base(TimerTask timer) {
        this.consumerTimerTask = timer;
    }

    /**
     * Initialize the timer.
     * @throws Exception
     */
    public void initialize() throws Exception {
        final int updateFrequency = 10000;

        // Once all fields have been generated and prefs read, initialize the update process every number of seconds.
        final Timer updateTimer = new Timer();

        updateTimer.scheduleAtFixedRate(this.consumerTimerTask, 0, updateFrequency);

        logger.info("Base initialized successfully!");
    }
}

Solution

  • Being that the code was inherited, I overlooked the version of the following dependency:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    

    Setting <spring.version>4.2.4.RELEASE</spring.version> fixed the issue.