2

I have edited this as I realised I had misdiagnosed the cause of the error. The error is caused because I have an async method in the abstract class which is being instantiated by the bean. I've added this method to the abstract class below. If I comment out the @Async annotation the code builds and 'runs'. This gives me somewhere to look now but I'll leave the question up in case anyone can help and get me up & running a bit more quickly!

I am trying to refactor a java/spring application which used xml configuration to use SpringBoot and code configuration. This is a far old learning curve for me.

I have hit an error which I think is reasonably well documented but I can't get my head around the documentation. Essentially One bean is created and then used in the constructor of another bean. The error I am getting when moving this to code config is ...

Failed to instantiate [com.app.data.dataTransformer]: 
    Factory method 'dataTransformerObj' threw exception; nested exception is java.lang.IllegalStateException: 
    @Bean method AsyncConfiguration.dataWriteBean called as a bean reference for type 
        [com.app.data.dataWriteBean] but overridden by non-compatible bean instance of type [com.sun.proxy.$Proxy118]. 

From some googling I think this is to do with the mechanics of passing one bean into another and thus this bean becoming a proxy bean.

So the xml config was like this...

<beans:bean id="dataReader" class="AsyncAccountReader"/>
<beans:bean id="dataWriter" class="AsyncAccountWriter"/>
<beans:bean class="DataTransformer">
    <beans:qualifier value="dataTransformerObj"/>
    <beans:constructor-arg index="0" value="Account"/>
    <beans:constructor-arg index="1" ref="dataReader"/>
    <beans:constructor-arg index="2" ref="dataWriter"/>
    <beans:constructor-arg index="3" ref="threadPoolTaskExecutor"/>
    <beans:constructor-arg index="4" value="10"/>
    <beans:property name="displayOrder" value="4"/>
</beans:bean>

This worked fine (Spring 4 MVC java 8 (upgraded from 7 with minimal code conversion).

The code config so far looks like this

    @Configuration
    @EnableAsync
    public class AsyncConfiguration {

    @Bean
    public ThreadPoolTaskExecutor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(30);
        executor.setQueueCapacity(15);
        executor.setThreadNamePrefix("threadPoolTaskExecutor-");
        executor.initialize();
        return executor;
    }

    @Bean
    public AsyncAccountReader dataReader() throws Exception {
        return new AsyncAccountReader();
    }

    @Bean
    public AsyncAccountWriter dataWriter() throws Exception {
        return new AsyncAccountWriter();
    }

    @Bean
    public AsyncDataTransformer esProjectTransformer() throws Exception {
        return new AsyncDataTransformer("Account", dataReader(), dataWriter());   
    }

AsyncAccountReader is not causing any problems The error (above) comes when I include the writer which is a class based on an abstract class so along these lines

Interface

public interface TransformWriter<T> {
    void writePage(int page, List<T> pageItems, TransformCompleteCallback callback);
}

Abstract Class

public abstract class AbstractTransformWriter<T> implements TransformWriter<T> {

    @Async
    @Override
    public void writePage(int page, List<T> pageItems, TransformCompleteCallback callback) {
        try {
            asyncWritePage(page, pageItems);
        } catch (Exception e) {
            LOGGER.error("Failed to run async writePage", e);
        } finally {
            callback.callback();
        }
    }

    public abstract void asyncWritePage(int page, List<T> pageItems);
}

Concrete Class

public class AsyncAccountWriter extends AbstractTransformWriter<Account> {

    @Autowired
    public void setDbService(DBService dbService) {
        this.dbService= dbService;
    }

    @Override
    public void asyncWritePage(int page, List<Account> accounts) {
        ...

So apologies if I've included too much or cut back too much in an attempt to point to what is pertinent.

The point is I think if I remove the @Async annotation the code builds and runs if not I get the error above. Can anyone tell me why this is an issue and point me in the write direction to implementing a solution ?

gringogordo
  • 1,990
  • 6
  • 24
  • 60
  • For now I seem to have fixed this (too early to tell whether it is fixed or just not breaking on start up any more) by changing the config annotation to @EnableAsync(proxyTargetClass=true. I'll keep googling but all the answers pertinent to this seem to taking a lot of knowledge for granted. If anyone can explain or point me in a direction which will really explain what is going on under the hood with these proxy creation errors I'd really appreciate it (& accept that as the answer...) – gringogordo Oct 05 '17 at 08:04
  • I haven't fully digested it yet but I think the underlying issues are well explained here https://stackoverflow.com/questions/10664182/what-is-the-difference-between-jdk-dynamic-proxy-and-cglib. I'm considering adding these 2 as an answer in case it helps anyone else but am happy to delete the question if this is against protocol. Will wait anyway in case anyone contributes anything else. – gringogordo Oct 05 '17 at 08:11

0 Answers0