Java Chatter and Random Nagging

Thursday, September 20, 2007

Wrestling with Spring Proxies

Today, I was wrestling with Spring 2 proxies for my pet project.
I wanted to switch back from AspectJ Transaction support to Spring AOP support and although it seemed easy, I stumbled on the following exception :

Caused by: org.springframework.aop.framework.AopConfigException: Couldn't generate CGLIB subclass of class [class hrutil.service.LoginApplicationService]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
Caused by: java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given

The following code generated problems:

public class LoginApplicationService {
private UserRepository userRepository;
public LoginApplicationService(UserRepository userRepository) {
this.userRepository = userRepository;
}
...}

and

<bean id="loginApplicationService" class="hrutil.service.LoginApplicationService">
<constructor-arg ref="userRepository"/>
</bean>

It left me paralyzed for a moment, since I did define constructor arguments. Googling my problem finally brought the solution.
Spring can use two different techniques for creating proxies at runtime: CGLIB or JDK dynamic proxies. If the target class implements one or more interfaces, then Spring will create a JDK dynamic proxy that implements every interface. If the target class implements no interfaces, Spring will use CGLIB to create a new class on the fly that is a subclass ("extends") the target class. This leads to one important difference: a JDK dynamic proxy cannot be casted to the original target class because it's simply a dynamic proxy that happens to implement the same interface(s) as the target.

Another important difference (and the one that caused the exception) : CGLIB proxies cannot be used with constructor-arguments.

Thus, the problem can be solved in two ways:
  1. Create interfaces for the services you want to proxy (never a bad habit and easily produced with your IDE's Extract Interface Refactoring).
  2. Do not use Spring constructor arguments when CGLIB is selected.

Labels: , ,

1 Comments:

At 9:43 pm, Blogger Ed Brannin said...

Thank you! I was just trying to figure out the same problem.

Sadly, I'm trying to proxy a third-party class without the right interfaces, but it looks like I can make an interface for the methods I want to advise, then "implement" them with an empty subclass. It won't be as clean as I'd like it to be, but at least I won't have to repeat code.

 

Post a Comment

<< Home