๐Ÿ”ด The Error You're Seeing

Confirm this matches your console output. If it does, you're in the right place.

ERROR LOGjava.lang.ClassCastException: class com.sun.proxy.$Proxy123 cannot be cast to class com.devinhyderabad.service.MyServiceImpl at com.devinhyderabad.controller.MyController.handleRequest(MyController.java:20)

โšก Quick Fix Works 80% of the time

Inject the interface, not the concrete class, or enforce CGLIB proxies.

// Bad: Injecting concrete class @Autowired private MyServiceImpl myService; // Good: Injecting interface @Autowired private MyService myService;

๐Ÿง  Why this Happens

Tap to expand the deep technical explanation

Spring uses AOP proxies to apply aspects like @Transactional or @Async. By default, it uses JDK Dynamic Proxies, which implement the interface but don't extend the concrete class. When you try to cast the proxy to your concrete implementation, Java throws a ClassCastException.

The HITEC City Parking Spot Analogy:

Imagine a stunt double (Proxy) for an actor. The stunt double can do the action scenes (Interface methods), but if the director tries to interview the stunt double as if they are the actual actor (Concrete Class), the director is making a mistake.

๐Ÿ” How to Reproduce Confirm this is your error

Inject the concrete implementation class (MyServiceImpl) instead of its interface into a controller while Spring AOP proxies the bean. Casting $Proxy to the class throws ClassCastException.

๐Ÿ› ๏ธ Solutions (3 Ways to Fix)

Solution 1โœ“ Most common cause

Inject the Interface, not the Implementation

๐Ÿ‘‰ Use this when your class implements an interface.

By default, Spring uses JDK Dynamic Proxies, which create a proxy that implements the interface, but does NOT extend the concrete class. You must inject the interface type.

@Service public class MyServiceImpl implements MyService { ... } @RestController public class MyController { @Autowired private MyService myService; // Inject interface, not MyServiceImpl }
Solution 2

Enable CGLIB Proxies

๐Ÿ‘‰ Use this if you must inject the concrete class.

CGLIB creates a proxy by subclassing the concrete class, allowing you to cast to the implementation.

# application.properties # Spring Boot 2.x: spring.aop.proxy-target-class=true # Spring Boot 3.x (enabled by default, but if disabled): spring.aop.proxy-target-class=true
Solution 3

Avoid self-invocation

๐Ÿ‘‰ Use this if you are calling a method on 'this' instead of the proxy.

If you call this.method(), you bypass the proxy entirely. If you try to cast 'this' to a proxied interface, it fails.

// Inject the bean into itself to call via proxy @Autowired @Lazy private MyService self; public void doWork() { self.otherMethod(); // Calls proxy }

๐Ÿ“‹ Version Notes

Spring Boot 2.x

JDK proxies by default unless proxy-target-class=true.

Spring Boot 3.x

CGLIB proxies are the default. But JDK proxies are used if an interface is present and CGLIB is disabled.

๐Ÿ›ก๏ธ How to Prevent This Next Time

Always program to interfaces. Inject interfaces, not concrete implementations. This makes your code decoupled and proxy-safe.

Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase