How To

Stas Maksimov edited this page Jan 17, 2015 · 3 revisions
Clone this wiki locally

CGLIB and Java Security

Java security protects system resources from unauthorized access by untrusted code. Code can be identified by signer and code base url (jar or class file) it can be local or downloaded from network. Classes generated by CGLIB do not exist at configuration and JVM startup time (generated at runtime), but all generated classes have the same protection domain (signer and codebase) as cglib itself and can be used in WS or by RMI application with security manager. To grant permissions for generated classes grant permissions for cglib binaries. Default security configuration is in java.policy file. This is example policy file, it grants all permissions for cglib and generated code.

    grant codeBase "file:${user.dir}/jars/cglib.jar"{
        permission java.security.AllPermission; 
    };

CGLIB and Java Serialization

Java objects can be serialized to binary streams, it is used to implement RMI too. Serialization needs to load class before to deserialize object data. It is possible there is no generated class on client or server for unmarshalled object, but serialization lets to replace objects in stream (writeReplace/readResolve contract). To add "writeReplace" method to proxy class declare this method in interface with exact signature specified by Java serialization. Implement writeReplace in interceptor. Proxy object can be replaced by handle, object stream invokes "readResolve" before to deserialize handle. Generate or find proxy class in "readResolve" method before to deserialize handle and return proxy instance.

Access the generated byte[] array directly

Here is an example of just capturing the byte array:

   Enhancer e = new Enhancer();
   e.setSuperclass(...);
   // etc.
   e.setStrategy(new DefaultGeneratorStrategy() {
     protected byte[] transform(byte[] b) {
     // do something with bytes here
   }});
   Object obj = e.create();

You can also easily hook in a ClassTransformer to affect the resulting class without having to re-parse the byte array, for example:

  e.setStrategy(new DefaultGeneratorStrategy() {
    protected ClassGenerator transform(ClassGenerator cg) {
      return new TransformingGenerator(cg,
        new AddPropertyTransformer(new String[]{ "foo" },
                                   new Class[]{ Integer.TYPE }));
    }});

Set "cglib.debugLocation" system property to write generated classes and pseudo ASM code to file system. NamingPolicy can be used to generate more meaningfull names.

Avoiding StackOverflowError

Common mistake is to cause recursion in MethodInterceptor implementation:

  Object intercept(Object proxy, Method method,
                   MethodProxy fastMethod, Object args[]) throws Throwable {
    //ERROR 
    System.out.println(proxy.toString());
    //ERROR 
    return fastMethod.invoke(proxy,args);     
  }

invokeSuper method must be used to invoke super class method. It will throw AbstractMethodError if super method is abstract. See trace sample how to solve recursion problem caused by "this" parameter in "args[]" array.

Optimizing Proxies

Filter unused methods with CallbackFilter and use light Callback version if possible. It can help to avoid hash lookup on method object if you use per method interceptors too.