Quantcast
Channel: How efficiently create Java proxy object using CGLib (or any other reflection/byte-code library) - Stack Overflow
Viewing all articles
Browse latest Browse all 2

How efficiently create Java proxy object using CGLib (or any other reflection/byte-code library)

$
0
0

Objective: (as the question title says): to efficiently create proxy (domain) objects using CGLib or any other reflection library (e.g. ByetBuddy?)

Having our domain class (please note Lombok annotations):

@Getter@Setter@RequiredArgsConstructorpublic class DomainFoo {    @NonNull    private final Integer id;    // some other fields, final or otherwise!    public void doSomething() {        // do something here!    }}

I'm trying to create a proxy object of type DomainFoo which responds only to getId method with the given ID (see below), otherwise (calling any other method) it throws an UnsupportedOperationException.

I managed to do this using GCLib (Spring version if it matters):

public static final ObjenesisStd OBJENESIS = new ObjenesisStd();public static Factory newFoo(Integer id) {    val enhancer = new Enhancer();    enhancer.setSuperclass(domainClass);    enhancer.setCallbackType(MethodInterceptor.class);    val proxyClass = enhancer.createClass();    // Since there's no default constructor in domains:    val instantiator = OBJENESIS.getInstantiatorOf(proxyClass);    val proxyInstance = instantiator.newInstance();    val factory = (Factory) proxyInstance;    factory.setCallbacks(new Callback[]{new DomainProxyInterceptor(id)});    return factory; // see below for why it's called factory!}

where DomainProxyInterceptor is:

@RequiredArgsConstructorprivate class DomainProxyInterceptor implements MethodInterceptor {    @NonNull    private final Integer id;    @Override    public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {        if (method.getDeclaringClass() != Object.class && method.getName().equals("getId")) {            return id;        } else {            throw new NotSupportedException(method.getName());        }    }}

Everything works just fine. Now to make it efficient, I'm trying to cache factory and actually use it a factory:

// newFooFactory is the above method rename!private static final Factor FOO_FACTORY = newFooFactory(0);public static DomainFoo newFoo(Integer id) {    val callbacks = new Callback[]{new DomainProxyInterceptor(id)};    return (DomainFoo) FOO_FACTORY.newInstance(callbacks);}

But calling the above method throws a NoSuchMethodError:

Exception in thread "main" java.lang.NoSuchMethodError: com/example/demo/DomainFoo$$EnhancerByCGLIB$$8423c3c4.<init>()V (loaded from file:/Users/rad/works/demo/target/classes/ by jdk.internal.loader.ClassLoaders$AppClassLoader@85a856f6) called from class com.example.demo.DomainFoo$$EnhancerByCGLIB$$8423c3c4 (loaded from file:/Users/rad/works/demo/target/classes/ by jdk.internal.loader.ClassLoaders$AppClassLoader@85a856f6).    at com.example.demo.DomainFoo$$EnhancerByCGLIB$$8423c3c4.newInstance(<generated>)    at com.example.demo.DomainFactory.proxyFoo(DomainFactory.java:28)    at com.example.demo.DemoApplication.main(DemoApplication.java:6)

Which presumably is because Factory.newInstance tries to use the normal constructor but it's not there (because we created the object using Objenesis?).I also tried ReflectionFactory to create the factory instance, but it has the same issue.

Questions (they're kinda related):

  1. Do I need to worry about efficiency at all? (Those objects are normal domains, so there's usually too many of them.)
  2. Is there a better way to do the above? In terms of efficiency or otherwise? Specifically what's the right way to instantiate using GCLib when there's no default constructor?
  3. Is there a way to fix the above issue? Resolving NoSuchMethodError failure?
  4. Any other library or solution I could try?

Thanks.


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images