вторник, 30 августа 2016 г.

BeanCurrentlyInCreationException due to bug in spring boot

Run into a problem:
If project is built on Windows machine, it works perfectly.
If project is built on TeamCity CI Linux-agent, than on application startup I get the following exception:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'someBeanName': Requested bean is currently in creation: Is there an unresolvable circular reference?

It turned out that there is a bug in spring boot, which leads to this error - if using @ComponentScan on a large scope (e.g. main package of the project).

I had a @SpringBootApplication annotation on my main spring boot class, which also includes the @ComponentScan. Bug was gone after overriding it with specifying concrete packages:

@ComponentScan({"ru.thecop.config",
        "ru.thecop.service",
        "ru.thecop.controller"})

It seems that the order of packages in this annotation is important - if you still experiencing problems with startup/bean creations, a possible solution is to change order of packages in @ComponentScan.

Additional info on this problem can be found on Spring Boot Github and Jira Ticket.

среда, 17 августа 2016 г.

Non-compatible bean instance of type $Proxy123

Situation: I have a @Configuration class, with a @Bean method, which return type is a concrete class, not an interface. And this class is @Transactional.
Ran into an exception:

java.lang.IllegalStateException: @Bean method SomeConfig.beanCreateMethod called as a bean reference for type [com.example.BeanType] but overridden by non-compatible bean instance of type [com.sun.proxy.$Proxy123]. Overriding bean of same name declared in: com.example.SomeConfig

According to this thread (it is old even now; but still useful):

The problem is that you use spring aop at your application (either directly or indirectly via using spring transactions).

Spring aop is proxy-based. It uses jdk proxies by default.

Jdk proxies can be casted only to the target interfaces. If you try to cast a proxy to the concrete class you get ClassCastException.

Bean named 'timedUserSync' is processed by spring aop and every time you try to use it at the application, you use jdk proxy instead. That produces the problem when the framework tries to use the bean as an object of concrete class.

Solution is to setup cglib usage for your aop infrastructure - set 'proxy-target-class="true''' for all used <aop:config>, <aop:aspectj-autoproxy> or <tx:annotation-driven> elements. Also you must be sure that cglib binaries are available at classpath.

Corresponding reference sections:
So adding proxyTargetClass = true to the @EnableTransactionManagement annotation solved the problem.

вторник, 16 августа 2016 г.

Strange: autowiring and spring boot resource reading

Strange things:
1. Spring bean autowiring might not work as expected, the beans your bean depends on are not instantinated and turn out to be null. As in this case:
@Autowired
private SomeBean someBean;

@Bean
public OtherBean otherBean() {
    OtherBean b = new OtherBean();
 b.setSome(someBean); // someBean here can be null!
    return b;
} 

So you can try to pass the someBean through parameter, this worked for me once:

@Bean
public OtherBean otherBean(SomeBean someBean) {
    OtherBean b = new OtherBean();
 b.setSome(someBean); // someBean will be instantinated
    return b;
}

2. If you want to read some resource from spring boot jar, you may run into FileNotFoundException, even if actually file will be on the specified path. Reading the resource as InputStream should help:

try (BufferedReader buffer = new BufferedReader(
new InputStreamReader(cpr.getInputStream()))) 
{
    List<String> lines = buffer.lines().collect(Collectors.toList());
    lines.forEach(System.out::println);
}