Bytebuddy - proxy private annotated method - java

I am proxying my objects with ByteBuddy and all works fine. When i annotate a method with #Test then they should be proxied another way. So i decided to separate my InvocationHandler into two. So far so good.
But now, when i want to add private, #Test-annotated methods they wont get proxied/intercepted. Only public methods will be intercepted. Any ideas why?
// return created proxy instance
#SuppressWarnings("unchecked")
Class<T> proxy = (Class<T>) byteBuddy
.subclass(clazz)
.implement(Proxy.class)
.defineField("_origin", Object.class, Visibility.PRIVATE)
.defineConstructor(Visibility.PUBLIC)
.withParameter(Object.class)
.intercept(MethodCall.invoke(clazz.getDeclaredConstructor()).andThen(FieldAccessor.ofField("_origin").setsArgumentAt(0)))
.name(clazz.getSimpleName() + "Proxy")
.method(ElementMatchers.isAnnotatedWith(Test.class))
.intercept(InvocationHandlerAdapter.of(testInvocationHandler))
.method(ElementMatchers.isDeclaredBy(AdditionalTest.class))
.intercept(InvocationHandlerAdapter.of(testInvocationHandler.getAdditionalTestInvocationHandler()))
.method(ElementMatchers.isDeclaredBy(Proxy.class)).intercept(InvocationHandlerAdapter.of(testInvocationHandler.getAdditionalTestInvocationHandler())).make()
.load(clazz.getClassLoader()).getLoaded();

If you define custom methods, your matchers will not be applied to those. You would need to specify the Implementation to also apply these matchers. Alternatively, you can create a class with the additional methods and then intercept this type by creating another proxy.

Related

ByteBuddy - creating proxy, but with original object as field

I'am trying to create a proxy with ByteBuddy. Is it possible to use the InvocationHandlerAdapter but to adapt it that the original object can be hold as field too? Actually i am using it like this:
Class<T> proxy = (Class<T>) byteBuddy
.subclass(clazz)
.name(clazz.getSimpleName() + "Implementing" + TaskOps.class.getSimpleName() + "Proxy")
.method(ElementMatchers.isAnnotatedWith(Task.class))
.intercept(InvocationHandlerAdapter.of(taskInvocationHandler))
.method(ElementMatchers.isDeclaredBy(TaskOps.class))
.intercept(InvocationHandlerAdapter.of(taskInvocationHandler.getTaskOpsInvocationHandler())).make()
.load(clazz.getClassLoader()).getLoaded();
Everything works fine. But i want to keep the proxied object as field "original" in the created proxy (or in the invocation handler). Is that possible?
Any help is appreciated.
Yes, this is of course possible using the adapter's toField method where the fields must be of type InvocationHandler. You can define the field on the proxy and it's your responsibility to set an instance before taking a proxy into use.

Using reflection in method of spring service

I have registered a service in my spring application. I have some methods with almost same nomenclature. So I am using reflection for invoking them to avoid using if else. Below is the similar scenario.
#Service
public class MyService {
public List<String> getEmployee(String type) {
Class myServiceClass = Class.forName("MyService");
Class partypes[] = new Class[1];
partypes[0] = String.class;
Method meth = myServiceClass.getDeclaredMethod("getEmpBy"+type, partypes);
Object arglist[] = new Object[1];
arglist[0] = type;
meth.invoke(this, arglist);
}
}
Now I have methods with nomenclature as getEmpByName, getEmpByAddress, getEmpByQualification. To avoid if else I want to use reflection but the above code is giving not able to load MyService at runtime.
TLDR
This design is terrible.
Use an interface instead of reflection.
More Info
You are using Spring.
Spring is happy to inject dependencies into your controllers.
Spring is almost certainly guaranteed to do a better job injecting your dependencies than you are at performing reflection.
The calling interface of your service is fixed
(notice that you hard-coded both the parameter types and the parameter order)
which, interestingly enough, is the same as with an interface.

The meaning of bindings annotation with provider methods

Now I'm reading Guice's official document and I saw this code.
#Provides #PayPal
CreditCardProcessor providePayPalCreditCardProcessor(
#Named("PayPal API key") String apiKey) {
PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
processor.setApiKey(apiKey);
return processor;
}
In above code, what does #PayPal mean?
In the page of the document, I understand the meaning of original binding annotations. We can customize it. But the usage is like this.
#Inject
public RealBillingService(#PayPal CreditCardProcessor processor,
TransactionLog transactionLog)
In the code, #PayPal means this parameter processor should be injected the instance indicated by the annotation.
So, what exactly does it mean in the first code?
In the first code, it means "when you find CreditCardProcessor annotated with #Paypal, use this method as provider".
Concretely, the first one is used to define the binding, the second one is used to request the binding.
The first one, could be rewritten as a rule in the configure() method:
protected void configure() {
PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
processor.setApiKey(apiKey);
bind(CreditCardProcessor.class).annotatedWith(PayPal.class).toInstance(processor);
}
But... you actually can't because then you'd have a singleton. Never it was written that you wanted a singleton.
So the provide methods are the nice tool to allow you making new instances and initializing them before passing them around.
Think of the annotation as part of the method's return type. The #Provides method you listed does not simply provide a CreditCardProcessor, it provides a #PayPal CreditCardProcessor. Thus, the method is written #Provides #PayPal CreditCardProcessor.
You can then request #PayPal CreditCardProcessor as in your second usage, by annotating a parameter in an #Inject-annotated method or constructor, or by adding the annotation to an #Inject-annotated field. (You can also request it directly from an Injector instance by creating a Key.)

ByteBuddy: Use new defined field in intercept during construction of class

I am looking at some ByteBuddy code from someone else. He uses ByteBuddy to generate runtime subclasses which are used as proxies to implement some management code of his runtime into specific objects.
Class<? extends T> newSubClass = new ByteBuddy(ClassFileVersion.ofThisVm())
.subclass(classType)
.defineField("_core", Object.class, Visibility.PUBLIC) //<---
.method(ElementMatchers.isDeclaredBy(classType))
.intercept(InvocationHandlerAdapter.of((proxy, method, m_args) -> {
//TODO: Need to replace core with _core as core is a function argument and will make it bound
return proxyHandler(core, method, m_args); //<--
}))
.make()
.load(roleType.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
T proxy = ReflectionHelper.newInstance(newSubClass, args);
newSubClass.getField("_core").set(proxy, core);
In order to not bind the core object directly into the lambda I want to use the new defined field _coreso I can reuse the generated class (and not regenerate it for every call of the function).
Is there a way to achieve this?
Thanks in advance.
You can define custom constructors just as you define methods. One important point for defining a constructor is that you require another constructor call as its first instruction. You can invoke a constructor using MethodCall::invoke which you can combine with FieldAccessor::ofField.
This way, you can define your class similar to the following:
new ByteBuddy(ClassFileVersion.ofThisVm())
.subclass(classType, ConstructorStrategy.Default.NO_CONSTRUCTORS)
.defineConstructor(Visibility.PUBLIC)
.withParameter(InvocationHandler.class)
.intercept(MethodCall.invoke(classType.getDeclaredConstructor())
.andThen(FieldAccessor.ofField("_core").setsArgumentAt(0)))
.defineField("_core", InvocationHandler.class, Visibility.PUBLIC)
.method(ElementMatchers.isDeclaredBy(classType))
.intercept(InvocationHandlerAdapter.toField("_core"))
.make();
This way, you can set a custom InvocationHandler per instance. If you want to only store the state in the _core field and access this field from your interceptor, have a look at MethodDelegation:
new ByteBuddy(ClassFileVersion.ofThisVm())
.subclass(classType, ConstructorStrategy.Default.NO_CONSTRUCTORS)
.defineConstructor(Visibility.PUBLIC)
.withParameter(Object.class)
.intercept(MethodCall.invoke(classType.getDeclaredConstructor())
.andThen(FieldAccessor.ofField("_core").setsArgumentAt(0)))
.defineField("_core", Object.class, Visibility.PUBLIC)
.method(ElementMatchers.isDeclaredBy(classType))
.intercept(MethodDelegation.to(MyHandler.class))
.make();
public class MyHandler {
#RuntimeType
public static Object intercept(#FieldValue("_core") Object value) { ... }
}
Other annotations you might need are #This, #AllArguments, #Origin and #SuperCall. The less you need, the more efficient your proxy will be. Especially #AllArguments is expensive due to its allocation requirements.
Note that in this case, your field is only set after the super constructor call. Also, you assume that there is a default constructor in the super type. Alternatively, you can implement a custom ConstructorStrategy.
As for caching, have a look at Byte Buddy's TypeCache.

Retrieving an instance using a string literal with Google Guice

I have multiple modules with service interfaces binding to their corresponding types and I am able to get an instance by using
injector.getInstance(MyServiceInterface.class)
I would like to retrieve the instance using
injector.getInstance("MyServiceInterface")
i.e. a string literal instead of the class type
How can I achieve this ?
To elaborate my question further - I can retrieve the Class object from the string literal using a Class.forName(literal) call and then use it to retrieve the instance with a injector.getInstance(clsInstance) .
After retrieving the instance which I receive in my base service type interface I need to use reflection to invoke the method of the service object.
so Service serv = injector.getInstance(MyCustomService.class)
Now I need to invoke myCustomMethod() present in MyCustomService through reflection since this invoker is generic and is intended to work with multiple services without being aware of their actual type.
I will also need the Method interceptors configured on the service interfaces to be invoked transparently when I invoke the method on this instance reflectively.
While I'm not certain if there's functionality for that built into Guice itself, you could try getting the relevant Class<?> object yourself.
Something along the lines of:
Class<?> myServiceInterfaceClass = Class.forName("path.to.MyServiceInterface");
injector.getInstance(myServiceInterfaceClass);
This does however require that the current Classloader can access that specific class, etc.
This can't be done within Guice... because it can't be done, period! Think about it, let's say you have two of the same class name in different packages. Which class would you instantiate?
So at the very least the String would have to have the fully qualified class name, e.g. instead of Integer, it would have java.lang.Integer.
However, if you know which classes you want to support in advance, you can use a MapBinder.
Tweaking their example to match your use case:
public class ServiceModule extends AbstractModule {
protected void configure() {
MapBinder<String, MyServiceInterface> mapbinder
= MapBinder.newMapBinder(binder(), String.class, MyServiceInterface.class);
mapbinder.addBinding("MyServiceInterface").to(MyServiceImpl.class);
bind(MyServiceInterface.class).to(MyServiceImpl.class);
}
}
Now you can inject like this:
class ServiceManager {
#Inject
public ServiceManager(Map<String, MyServiceInterface> services) {
MyServiceInterface service = stacks.get("MyServiceInterface");
// etc.
}
}
Please note when you call inj.getInstance() you do have to know the return type of the Object you're trying to create, unless you are planning on doing:
Object foo = inj.getInstance(myString);

Categories

Resources