Category: Troubleshouting

Always use interfaces for dependency injection

I working on a big legacy project that uses Spring IoC. And when it started I see in console warning messages like:

WARN  org.springframework.aop.framework.Cglib2AopProxy - Unable to proxy method [public final javax.sql.DataSource org.springframework.jdbc.core.support.JdbcDaoSupport.getDataSource()] because it is final: All calls to this method via a proxy will be routed directly to the proxy.

Here a sample code:

@Service
@Transactional
public class UserServiceImpl implements UserService {

}

@Controller
public class UserController {

    @Autowired
    UserServiceImpl  userService; // Here a problem: we declared field as concrete class UserServiceImpl  instead of interface UserService

}

As I found it happens when fields autowired as concrete class instead of injection by interface.

According to Spring AOP documentation:

Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice).
If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created.

Thus since userService injected by concrete class UserServiceImpl instead of interface UserService, so Spriong IoC tries to create a proxy class via CGLIB bytecode magic that shows this error message.

Also this CGLIB magic proxying may be disabled by configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <ehcache:annotation-driven cache-manager="genericCacheManager" proxy-target-class="false"/>
    <tx:annotation-driven proxy-target-class="false"/>
    <aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>

In this case this exception will be thrown during runtime:


Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy56 implementing com.eample.services.UserService,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.eample.services.UserServiceImpl] for property ‘userService’: no matching editors or conversion strategy found


To fix this we just need to use autowiring by interface and this is in common simple refactoring.

Please vote for this feature request to make IntellijIdea helpful in this New inspection: Use dependency injection by interface instead of concrete class

See also:
Spring: Why do we autowire the interface and not the implemented class?
Why always have single implementaion interfaces in service and dao layers?

Performance differences

Реклама

@EqualsAndHashCode on Grails domains

I found a strange bug\behavior in Grails.

How to grasefully check domains for equality?
For example, we we have User comain class and we want to check in code equality of its two instances:

class User {
}

currentUser == article.author

In this case equals will be by reference.
But this objects may have different references: one was get from DB another was from session. And equals operator will return false.
So, we need to check them for equality by id field:

currentUser.id == article.author.id

But, you can forget about this and still compare by references, so lets generate equals() and hashCode() methods. In IntelliJ we should set cursor on class name and press Alt+Insert.
1. In the dialog we must check option «Accept subclasses» becouse Hibernate inside Grails always creates a proxy subclass of our User class.
2. We should uncheck all fields and leave only one id field

class User {
boolean equals(o) {
if (this.is(o)) return true
if (!(o instanceof User)) return false
User user = (User) o
if (id != user.id) return false
return true
}

int hashCode() {
return id.hashCode()
}
}

But in Groovy 2 we have a cool annotation EqualsAndHashCode

@EqualsAndHashCode(includes = 'id')
class User {
}

But! In this case, condition currentUser == article.author is always return true! Always, when they equal or not. I can understood why always true.
It costs me a few hours of deep debug of transformator EqualsAndHashCodeASTTransformation until I understood a root of problem.
The field id is not exists in class User — it’s wired dynamicly by Grails (i.e GORM).
So, this annotation becomes redundant — it doesn’t make any equals checking on id.
You can write any non existent field in includes and transformer will not fail compilation:

@EqualsAndHashCode(includes = ['id', 'ololo', 'trololo'])
class User {
}

I will rise an issue in bugtracker with asking a developers to make transformer more strictly.

Thus solution to fix is simple: you just need to declare id field explicitly like this:

@EqualsAndHashCode(includes = 'id')
class User {
long id
}

Now all should be fine. Also I remember that had the similar problem with implicit id field with @ToString annotation.
Also the same problem I found with fields like belongsTo:

@EqualsAndHashCode(includes = 'author')
class Article {
static belongsTo = [author: User]
}

This will not work. Again, explicitly declare field:

@EqualsAndHashCode(includes = 'author')
class Article {
User author
static belongsTo = [author: User]
}

This will work as expected with equals.

So rule is simple: always declare field explicitly!

Have a nice coding!