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 ?