This blog is about Java (advanced Java topics like Reflection, Byte Code transformation, Code Generation), Maven, Web technologies, Raspberry Pi and IT in general.

Sonntag, 29. Juni 2014

Explanation how CGLIB proxies work

 In my lastblog entry I explained how proxy based mock frameworks work and created my own demo mock framework based on CGLIB. Now I will explain how exactly the CGLIB proxy works. Because then you will understand why these things doesn't work with a proxy:
  • intercept static method calls
  • intercept private method calls
  • intercept final method calls
  • build a proxy for a final class


CGLIB is based on ASM. ASM is a library to create class files, on bytecode level, on the fly. So it's very low level and you need a good understanding of the bytecode to use it. But it abstracts the bytecode and is much more comfortable to generate bytecode with ASM than writing the bytecode itself. Because it takes care of the common structures like classes, constructors, method definitions and so on. One of the most helpful features is that it takes care about the constant pool. Because the constant pool holds many elements and you need to adapt it if you change anything. E.g. if a new method is added than you have to add the needed elements to the constant pool and increase the constant pool size. Or the labels in ASM are quite nice, too. Or that there are constants for the opcodes. After the complete class is generated, you have the bytecode of the class. This bytecode is passed into the ClassLoader which will load the class and then the class can be used.

How the generated CGLIB looks

Now you know how the generation of the proxy works. The question is how the generated proxy looks like. Actually it's quite simple. The proxy class extends the original class. All classes which should be intercepted by the proxy will be overridden. These methods will call the MethodInterceptor:: intercept method with the corresponding parameters. If the proxy callback is null than the super method will be called. Here is the code snippet for a simple echo(String) method:
public class at.rseiler.concept.mock.Foo$$EnhancerByCGLIB$$c0699eac
  extends at.rseiler.concept.mock.Foo
  implements org.mockito.cglib.proxy.Factory
  private static final org.mockito.cglib.proxy.MethodProxy CGLIB$echo$1$Proxy;
  private static final java.lang.reflect.Method CGLIB$echo$1$Method;
  // ...
  private org.mockito.cglib.proxy.MethodInterceptor CGLIB$CALLBACK_0;
  // ...

public final String echo(String arg0) {
    if(CGLIB$CALLBACK_0 == null) {

    if(CGLIB$CALLBACK_0 != null) {
      // MethodInterceptor::intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
      Object obj = CGLIB$CALLBACK_0.intercept(this, GLIB$echo$0$Method, new Object[] {arg0}, CGLIB$echo$0$Proxy);

      if(!(obj instanceOf String)) {
        throw new ClassCastException();

      return obj;

    return super.echo(arg0);
  private static final void CGLIB$BIND_CALLBACKS(java.lang.Object object) {
    /* compiled code */

  // ...

Now you should understand the limits of the proxy (see above). The limits caused because the proxy is a subclass of the original class. Therefore it's not possible to extend a final class or final methods and so on. That's just basic Java limitations.
With code generation it's not possible to work around these limits. Sure it would be possible to generate a proxy class without the relationship to the original class. Than it would be possible to copy the whole class and insert the MethodInterceptor::intercept calls. This new class could remove all final keywords and make private methods public. The problem is that you can't call any method of this class without reflection. Because you don't have the type information of the "proxy" class at  compile time - clearly because the class is generated at runtime. Further you can't pass the "proxy" object to any constructor or any method because it's not a subclass.
The only way to break this limits is to do bytecode transformations of the original class before the ClassLoader loads the class. Before the class is loaded replace all private keywords with public keywords and to remove all final keywords. To do so you need to create your own ClassLoader which will performs the bytecode transformation. I don't know the code of PowerMock, but it must work like this.
At last the with javap --verbose decompiled bytecode of the echo(String) method from which I created the Java code above:
public final java.lang.String echo(java.lang.String);

stack=7, locals=2, args_size=2
0: aload_0
1: getfield      #37                 // Field CGLIB$CALLBACK_0:Lorg/mockito/cglib/proxy/MethodInterceptor;
4: dup
5: ifnonnull     17
8: pop
9: aload_0
10: invokestatic  #41                 // Method CGLIB$BIND_CALLBACKS:(Ljava/lang/Object;)V
13: aload_0
14: getfield      #37                 // Field CGLIB$CALLBACK_0:Lorg/mockito/cglib/proxy/MethodInterceptor;
17: dup
18: ifnull        45
21: aload_0
22: getstatic     #64                 // Field CGLIB$echo$1$Method:Ljava/lang/reflect/Method;
25: iconst_1
26: anewarray     #66                 // class java/lang/Object
29: dup
30: iconst_0
31: aload_1
32: aastore
33: getstatic     #68                 // Field CGLIB$echo$1$Proxy:Lorg/mockito/cglib/proxy/MethodProxy;
36: invokeinterface #53,  5           // InterfaceMethod org/mockito/cglib/proxy/MethodInterceptor.intercept:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lorg/mockito/cglib/proxy/MethodProxy;)Ljava/lang/Object;
41: checkcast     #55                 // class java/lang/String
44: areturn
45: aload_0
46: aload_1
47: invokespecial #62                 // Method at/rseiler/concept/mock/Foo.echo:(Ljava/lang/String;)Ljava/lang/String;
50: areturn


  1. Danke fur die Information! This really helps with a project I'm working on... tightly integrated 3rd party library which was not built with any useful interfaces!

  2. I have read your blog its very attractive and impressive. I like it your blog.

    Java Training in Chennai Java Training in Chennai

  3. Great Article… I love to read your articles because your writing style is too good, its is very very helpful for all of us and I never get bored while reading your article because, they are becomes a more and more interesting from the starting lines until the end.

    rpa training in bangalore
    best rpa training in bangalore
    RPA training in bangalore
    RPA courses in bangalore


  4. Very nice post here and thanks for it .I always like and such a super contents of these post.
    Excellent and very cool idea and great content of different kinds of the valuable information's.
    Java training in Chennai

    Java training in Bangalore

    Java online training

    Java training in Pune

  5. I appreciate your efforts because it conveys the message of what you are trying to say. It's a great skill to make even the person who doesn't know about the subject could able to understand the subject . Your blogs are understandable and also elaborately described. I hope to read more and more interesting articles from your blog. All the best.
    python Online training in chennai
    python Online training in bangalore
    python interview question and answers

  6. Hmm, it seems like your site ate my first comment (it was extremely long) so I guess I’ll just sum it up what I had written and say, I’m thoroughly enjoying your blog. I as well as an aspiring blog writer, but I’m still new to the whole thing. Do you have any recommendations for newbie blog writers? I’d appreciate it.
    AWS Training in Bangalore with Placements | AWS Training in Bangalore Cost
    AWS Training in Pune With Placement | AWS Devops Training in Pune
    AWS Online Training | AWS Online Training Cost
    AWS Training in Bangalore cost| Aws training in Bangalore Besant Technologies

  7. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
    Best Devops online Training
    Online DevOps Certification Course - Gangboard

  8. A week ago, I had nothing to do and went to this site whole real cash online casino and decided to take a risk. We only live once to play in a casino. And did not regret

  9. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
    AWS Training in Electronic City

  10. Great post and informative was awesome to read, thanks for sharing this great content to my vision.
    Good discussion.
    Java Training in Chennai
    Java Training in Coimbatore
    Java Training in Bangalore

  11. Dieser Kommentar wurde vom Autor entfernt.

  12. Thanks For sharing a nice post about Informatica Training Course.It is very helpful and Informatica useful for us.Informatica Training in Bangalore

  13. After signing up, you can hit the "Teaching" button. The "Create a course" button will show up that you can press to create a course and become a tutor. cursos de ti online

  14. It's a wonderful post and very helpful, thanks for all this information about Java. You are including better information regarding this topic in an effective way.Thank you so much.
    Java training in chennai | Java training in annanagar | Java training in omr | Java training in porur | Java training in tambaram | Java training in velachery

  15. Thank you a lot for providing individuals with a very spectacular possibility to read critical reviews from this site.
    AWS training in chennai | AWS training in annanagar | AWS training in omr | AWS training in porur | AWS training in tambaram | AWS training in velachery