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.
Related
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.
I made a switch to Realm last week.
Now, I've got this issue when using reflection:
Normally I'd use reflection to fetch field, which when available I'd use to replace url params in our API url f/e:
blog/{blogId}/comments <- not an actual url but an example.
The code would check if there is a field called blogId, if yes it'll invoke the getter (getBlogId) and replace the value in the path. Now with realm I get a "BlogRealmProxy" which does not contain the properties I was expecting on my RealmObject, it has fields like INDEX_BLOGID (or alike).
Any idea how to use reflection still? I need this to have generic functions available.
Update:
Well I found a way, by doing something quite silly, any better options?:
Class clazz = obj.getClass();
if (clazz.getName().endsWith("Proxy")) {
clazz = clazz.getSuperclass();
}
I'm 100% sure objects will never end with Proxy ;)
Well I found a way, by doing something quite silly, any better options?:
Class clazz = obj.getClass();
if (clazz.getName().endsWith("Proxy")) {
clazz = clazz.getSuperclass();
}
I'm 100% sure objects will never end with Proxy ;) in my app.
I have been trying to develop an application. A bean script will be written as per requirement which in turn will call methods (defined in the application) in various order as per requirement. The application code (apart for bean script) would not be changed.
Also, the application uses external jars which provide large number of methods - of which some are implemented in the application. However, I would like to have the possibility to use the other methods (ones that are not yet implemented) without making changes to application should the requirement arise. For this, I would like to use the Java reflection API. The user should be able to call any method present in the external jars by passing the method name and corresponding parameters (using the the external jar documentation).
I'm a java newbie so I have some code that tries to achieve it (may not be syntactically correct):
public void callExternalJarMethod(String methodName, Class[] methodParameterTypes, Object[] methodParameters)
throws NoSuchMethodException {
String className = "SampleClassName";
Class classObject = Class.forName(className);
Method methodObject;
if (methodParameterTypes.length == 0) {
methodObject = classObject.getMethod(methodName, null);
} else {
methodObject = classObject.getMethod(methodName, methodParameterTypes);
}
// Not handling calling of static methods in which case "null" would be passed instead of methodObject to the invoke method
Object returnValue = methodObject.invoke(methodObject, methodParameters);
}
I'm trying to find a way I can get the Class[] methodParameterTypes, and Object[] methodParameters populated with the relevant values. I would have the parameter types and parameter values as string. Also, any pointers towards useful utils would be appreciated.
Thanks in advance.
You are not passing an instance of SampleClassName to the Method.invoke() call here...
Object returnValue = methodObject.invoke(methodObject, methodParameters);
If the method you are going to invoke is static, you can do this...
Object returnValue = methodObject.invoke(null, methodParameters);
Otherwise (non-static), you need to create an instance of SampleClassName to execute the method on.
If the class does not need any constructor arguments, you could use...
Object returnValue = methodObject.invoke(classObject.newInstance(), methodParameters);
(Obviously there will be a load of Exceptions that you need to handle by doing "newInstance" and "invoke"...)
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);
How we can manually inject an object without using the facility of containers. I did something similar through reflection as follows.
Class actionClass = Class.forName("SampleClass");
Object actionObject = actionClass.newInstance();
Method reqMethod = actionClass.getMethod("setRequest", HttpServletRequest.class);
reqMethod.invoke(actionObject,request);
is it the right way to do DI?
My intention is to pass request object to different controller classes dynamically from a dispatcher filter,where we get request and response objects.
I am fearing about the performace of reflection.Is there any replacement for doing DI?
Dependency injection is nothing more than providing a class with its dependencies, rather than have it find them itself (via singletons/lookups etc.). So you can do it in code trivially thus:
DatabaseConnection dc = new DatabaseConnection();
MyDAO dao = new MyDAO(dc);
(pseudocode). Here the MyDAO is being injected with a database connection. If that database connection implements an interface you can easily mock this out during testing.
Well, when you set one object into another object using setter method or through a constructor it also is the dependency injection. Dependency injection only means creating relationship(dependency) in objects.
Using reflection as you did is just another form of it.
Why would you use reflection? Why not simply:
SampleClass action = new SampleClass();
action.setRequest(request);
That does the same thing, but is more readable, allows the compiler to check that the types and methods actually exist, provides you with Javadoc for the Method invoked, enables your IDE to assist in refactorings, ...
And it still is dependency injection, because the action doesn't go looking for its request, but receives the request during initialization.
Edit: Thorbjørn requested I show how that action would be used. It would itself be injected (using a setter) into whatever component uses the action. The component would then use the injected action object.
SampleClass action = new SampleClass();
action.setRequest(request);
Servlet servlet = new ActionBasedServlet();
servlet.setAction(action);
If servlet is intended to live longer than action, i.e. it should use a fresh Action each time it needs one, one can instead setter-inject an ActionFactory into servlet.
In this concrete case, I'd question whether the action really needs to keep a request as part of its state, or can be immutable and simply act on the request passed by the Servlet as method parameter. In that case, the boot-time initialization would do:
SampleClass action = new SampleClass();
Servlet servlet = new ActionBasedServlet();
servlet.setAction(action);
and ActionBasedServlet would define
public void serve(Request req, Response resp) {
foo();
action.act(req, resp);
bar();
}
Dependency Injection implies you get properly initialized references appearing "by magic".
You call the setRequest() method with the request object, but DI frequently also allows for setting the fields without invoking methods.
Guice does not as such require a container, but uses class loader magic started in the main method. Would that be useable for you?
Spring framework is one of the most popular DI implementations. It is also opensource.
You can check out the class org.springframeowrk.beans.BeanUtils, specifically the methods copyProperties (all 4 of them) for examples on how to do this.
For more info you can also see the class hierarchy of org.springframework.beans.factory.BeanFactory for different strategies.