In Java, how do you get the original class object and/or class name of a Java EE (CDI) proxy?
When using getName() on a proxy instance, the name returned is something like
com.company.employeemgmt.EmployeeManager$Proxy$_$$_WeldSubclass
Is there some functionaliy in Java SE (7) or EE (6) that will return either the original, unproxied class instance or its name?
I need:
com.company.employeemgmt.EmployeeManager
Of course, I could simply use string manipulation, but I would like to know if such functionality is already Java-(EE)-inbuilt.
I already found java.reflect.Proxy, which I could use to detect proxies:
public static void doSomething( Class<? implements Serializable> managerClass )
{
if ( Proxy.isProxyClass( managerClass ) )
{
// unproxy how?
managerClass = managerClass.getUnproxiedClass();
}
// delegate
doSomething( managerClass.getName() );
}
public static void doSomething( String prefix )
{
// do real work
...
}
..., but how would you dereference the original class?
Update:
The trick would be to access MyUtil.doSomething( EmployeeManager.class ) (or MyUtil.doSomething( EmployeeManager.class.getName() )), but I would like to use/pass MyUtil.doSomething( this.getClass() ) (or MyUtil.doSomething( this.getClass().getName() )) from all clients as this code can be copied around without manual changes.
Since the proxy class inherits from the original class, I think that you can obtain the original class by getting the proxy superclass.
It depends. You can get the InvocationHandler for a proxy using Proxy.getInvocationHandler(manager). Alas, InvocationHandler is an interface with only one invoke method and with no feature that lets you get a target class; it all depends on the implementation.
As an example the CXF web servcie framework has a Client and uses a ClientProxy as an associated invocation handler, you can get the Client as such:
ClientProxy handler = (ClientProxy)Proxy.getInvocationHandler(proxiedObject);
Client client = handler.getClient();
To add insult to injury, it seems that the WeldInvocationHandler that you are probably using simply delegates the call to a org.jboss.wsf.spi.invocation.InvocationHandler that that it stores its delegate in a private field. So you need to do quite some magic with reflection to find out the actual class of the target object.
Since proxy implements interfaces it proxies, you can use Class<?>[] Class.getInterfaces()
to find out proxied class(es).
private Class<?> findProxiedClass(Object proxiedObject) {
Class<?> proxiedClass = proxiedObject.getClass();
if (proxiedObject instanceof Proxy) {
Class<?>[] ifaces = proxiedClass.getInterfaces();
if (ifaces.length == 1) {
proxiedClass = ifaces[0];
} else {
// We need some selection strategy here
// or return all of them
proxiedClass = ifaces[ifaces.length - 1];
}
}
return proxiedClass;
}
Test it with
#Test
public void testProxies() {
InvocationHandler handler = new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
};
RandomAccess proxiedIface = (RandomAccess) Proxy.newProxyInstance(
RandomAccess.class.getClassLoader(),
new Class[] { RandomAccess.class },
handler);
Assert.assertEquals(RandomAccess.class, findProxiedClass(proxiedIface));
Assert.assertEquals(Object.class, findProxiedClass(new Object()));
}
Related
im dealing with a codebase that has builds MBeans (for export to jmx).
the original code simply builds an MBeanInfo instance:
#Override
public MBeanInfo getMBeanInfo() {
MBeanAttributeInfo[] attrs = //SLOW TO BUILD
return new MBeanInfo(...attrs...);
}
since the mbean attributes are expensive to build, and this method get called rather frequently (even with no jmx clients attached), i've tried creating a subclass of MBeanInto that lazily calculates those attributes:
public class LazyMBeanInfo extends MBeanInfo implements Externalizable {
private transient AttributeCallback callback = null;
private volatile MBeanAttributeInfo[] lazyAttrs = null;
public LazyMBeanInfo(...AttributeCallback callback...) throws IllegalArgumentException {
super(className, description, null, constructors, operations, notifications);
this.callback = callback;
}
#Override
public MBeanAttributeInfo[] getAttributes() {
MBeanAttributeInfo[] val = lazyAttrs;
if (val != null) {
return val.clone(); //match upstream behaviour
}
if (callback == null) {
throw new IllegalStateException("BUG");
}
val = callback.buildAttributes();
if (val == null) {
val = new MBeanAttributeInfo[0];
}
lazyAttrs = val;
return val.clone();
}
public interface AttributeCallback {
MBeanAttributeInfo[] buildAttributes();
}
}
the problem is that JMX (over RMI) serializes the MBeanInfo object, and then in jconsole (or jvisualVM) i get an error:
so - can i somehow implement Externalizable and serialize myself as an instance of the parent class? ideally i'd like this to work:
public class LazyMBeanInfo extends MBeanInfo implements Externalizable {
//same as before, plus:
#Override
public void writeExternal(ObjectOutput out) throws IOException {
MBeanInfo vanilla = new MBeanInfo(...);
out.writeObject(vanilla);
}
}
but it doesnt.
is this possible somehow ?
Unless you are using [highly dynamic] DynamicMBeans, I don't see why the MBeanInfo needs to be rebuilt for every call to getMBeanInfo(), but ....
Your LazyMBeanInfo can be made to work (though I have not tested this specific case). MBeanInfo already implements Serializable, so what you want is for the serialization process to write out an MBeanInfo, not a LazyMBeanInfo, since the client probably doesn't have that class in its classpath. However, LazyMBeanInfo can implement this method:
Object writeReplace() throws ObjectStreamException;
at which point you write out the underlying MBeanInfo. See the Serializable JavaDoc, specifically:
Serializable classes that need to designate an alternative object to
be used when writing an object to the stream should implement this
special method with the exact signature:
ANY-ACCESS-MODIFIER Object writeReplace() throws
ObjectStreamException;
In that way, the actual object can be an instance of LazyMBeanInfo, but what you write out can be an actual MBeanInfo, built from your cached lazyAttrs.
Having said that, rather than implementing a build-on-first-call approach, I would implement a build-before-first-use by simply building the full MBeanInfo when the MBean is first created, or when the MBean is registered. Then just return the pre-built MBeanInfo on each getMBeanInfo() call.
To do this at MBean registration time, implement the MBeanRegistration interface, and build the cached MBeanInfo in the postRegister method.
I have a public abstract class java.nio.ByteBuffer instance which is actually an instance of private class java.nio.HeapByteBuffer and I need to make a proxy object which would call some invocation method handler to check access permissions and then call the invoked method on the actual instance.
The problem is that the java.nio.ByteBuffer class has only private constructors and also has some final methods, thus I can not create proxy instances with javassist.util.proxy.ProxyFactory class.
So, how can I make a proxy object to control the invocation of a java.nio.ByteBuffer instance including those final methods invocation?
Please be aware that I am presenting a solution based on my own (FOSS) framework Byte Buddy which is however already mentioned as a potential solution in one of the comments.
Here is a simple proxy approach which creates a subclass. First, we introduce a type for creating proxies for ByteBuffers:
interface ByteBufferProxy {
ByteBuffer getOriginal();
void setOriginal(ByteBuffer byteBuffer);
}
Furthermore, we need to introduce an interceptor to use with a MethodDelegation:
class Interceptor {
#RuntimeType
public static Object intercept(#Origin(cacheMethod = true) Method method,
#This ByteBufferProxy proxy,
#AllArguments Object[] arguments)
throws Exception {
// Do stuff here such as:
System.out.println("Calling " + method + " on " + proxy.getOriginal());
return method.invoke(proxy.getOriginal(), arguments);
}
}
This interceptor is capable of intercepting any method as the #RuntimeType casts the return type in case that it does not fit the Object signature. As you are merely delegating, you are safe. Plase read the documentation for details. As you can see from the annotations, this interceptor is only applicable for instances of ByteBufferProxy. Bases on this assumption, we want to:
Create a subclass of ByteBuffer.
Add a field to store the original (proxied) instance.
Implement ByteBufferProxy and implement the interface methods to access the field for the stored instance.
Override all other methods to call the interceptor that we defined above.
This we can do as follows:
#Test
public void testProxyExample() throws Exception {
// Create proxy type.
Class<? extends ByteBuffer> proxyType = new ByteBuddy()
.subclass(ByteBuffer.class)
.method(any()).intercept(MethodDelegation.to(Interceptor.class))
.defineField("original", ByteBuffer.class, Visibility.PRIVATE)
.implement(ByteBufferProxy.class).intercept(FieldAccessor.ofBeanProperty())
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
// Create fake constructor, works only on HotSpot. (Use Objenesis!)
Constructor<? extends ByteBufferProxy> constructor = ReflectionFactory
.getReflectionFactory()
.newConstructorForSerialization(proxyType,
Object.class.getDeclaredConstructor());
// Create a random instance which we want to proxy.
ByteBuffer byteBuffer = ByteBuffer.allocate(42);
// Create a proxy and set its proxied instance.
ByteBufferProxy proxy = constructor.newInstance();
proxy.setOriginal(byteBuffer);
// Example: demonstrates interception.
((ByteBuffer) proxy).get();
}
final methods are obviously not intercepted. However as the final methods in ByteBuffer only serve as convenience methods (e.g. put(byte[]) calls put(byte[],int,int) with the additional arguments 0 and the array length), you are still able to intercept any method invocation eventually as these "most general" methods are still overridable. You could even trace the original invocation via Thread.currentCallStack().
Byte Buddy normally copies all constructors of its super class if you do not specify another ConstructorStrategy. With no accessible constructor, it simply creates a class without constructors what is perfectly legal in the Java class file format. You cannot define a constructor because, by definition, this constructor would need to call another constructor what is impossible. If you defined a constructor without this property, you would get a VerifierError as long as you do not disable the verifier altogether (what is a terrible solution as it makes Java intrinsically unsafe to run).
Instead, for instantiation, we call a popular trick that is used by many mocking frameworks but which requires an internal call into the JVM. Note that you should probably use a library such as Objenesis instead of directly using the ReflectionFactory because Objenesis is more robust when code is run on a different JVM than HotSpot. Also, rather use this in non-prduction code. Do however not worry about performance. When using a reflective Method that can be cached by Byte Buddy for you (via cacheMethod = true), the just-in-time compiler takes care of the rest and there is basically no performance overhead (see the benchmark on bytebuddy.net for details.) While reflective lookup is expensive, reflective invocation is not.
I just released Byte Buddy version 0.3 and I am currently working on documentation. In Byte Buddy 0.4, I plan to introduce an agent builder which allows you to redefine classes during load-time without knowing a thing about agents or byte code.
I can suggest you 2 solutions.
First, simple, not universal, but probably useful for you.
As far as I can see ByteBuffer has several package-private constructors that allow its subclassing and the following final methods:
public final ByteBuffer put(byte[] src) {
public final boolean hasArray() {
public final byte[] array() {
public final int arrayOffset() {
public final ByteOrder order() {
ByteBuffer extends Buffer that declares some of these methods:
public final boolean hasArray() {
public final Object array() {
public final int arrayOffset() {
As you can see, put() and order() are absent here, return type of array() is a little bit confusing, but still can be used.
So, if you use only these 3 methods you can subclass Buffer and create universal wrapper that wraps any other Buffer including ByteBuffers. If you want you can use javaassist's proxy although IMHO it is not necessarily here.
Second, more universal but more tricky solution. You can create agent that removes final modifiers from speicific class (ByteBuffer in your case) during class loading. Then you can create javassist proxy.
Variation of second solution is following. Copy ByteBuffer soruce code to separate project. Remove final modifiers and compile it. Then push it into bootstrap classpath. This solutions is probably easier than second.
Good luck anyway.
Thanks to #raphw I have managed to make a proxy object construction class which makes a proxy for java.nio.ByteBuffer but that class has final methods which I can not overcome and they are extensively used in the required code, those final methods are Buffer.remaining() and Buffer.hasRemaining(), thus they just can not be proxy mapped.
But I would like to share the classes I have made, just as a report.
public final class CacheReusableCheckerUtils {
private static ByteBuddy buddy = new ByteBuddy();
private static Objenesis objenesis = new ObjenesisStd();
public static <T> T createChecker(T object) {
return createChecker(new CacheReusableCheckerInterceptor<>(object));
}
public static <T> T createChecker(CacheReusableCheckerInterceptor<T> interceptor) {
return objenesis.getInstantiatorOf(createCheckerClass(interceptor)).newInstance();
}
private static <T> Class<? extends T> createCheckerClass(CacheReusableCheckerInterceptor<T> interceptor) {
Class<T> objectClass = interceptor.getObjectClass();
Builder<? extends T> builder = buddy.subclass(objectClass);
builder = builder.implement(CacheReusableChecker.class).intercept(StubMethod.INSTANCE);
builder = builder.method(MethodMatchers.any()).intercept(MethodDelegation.to(interceptor));
return builder.make().load(getClassLoader(objectClass, interceptor), Default.WRAPPER).getLoaded();
}
private static <T> ClassLoader getClassLoader(Class<T> objectClass, CacheReusableCheckerInterceptor<T> interceptor) {
ClassLoader classLoader = objectClass.getClassLoader();
if (classLoader == null) {
return interceptor.getClass().getClassLoader();
} else {
return classLoader;
}
}
}
public class CacheReusableCheckerInterceptor<T> {
private T object;
private boolean allowAccess;
private Throwable denyThrowable;
public CacheReusableCheckerInterceptor(#NotNull T object) {
this.object = object;
}
#SuppressWarnings("unchecked")
public Class<T> getObjectClass() {
return (Class<T>) object.getClass();
}
#RuntimeType
public final Object intercept(#Origin(cacheMethod = true) Method method, #This T proxy, #AllArguments Object[] arguments) {
try {
switch (method.getName()) {
case "allowAccess":
allowAccess();
return null;
case "denyAccess":
denyAccess();
return null;
default:
return invokeMethod(method, arguments);
}
} catch (Exception e) {
throw new CacheReusableCheckerException(method, object, proxy, e);
}
}
private Object invokeMethod(Method method, Object[] arguments) throws IllegalAccessException, InvocationTargetException {
checkMethodAccess(method.getName());
return method.invoke(object, arguments);
}
private void allowAccess() {
if (allowAccess) {
error("double use");
}
allowAccess = true;
onAccessAllowedAfter(object);
}
private void denyAccess() {
if (!allowAccess) {
error("double free");
}
onAccessDeniedBefore(object);
allowAccess = false;
denyThrowable = new Throwable();
}
private void checkMethodAccess(String name) {
if (!allowAccess) {
switch (name) {
case "hash":
case "equals":
case "toString":
case "finalize":
break;
default:
error("use after free");
}
}
}
private void error(String message) {
throw new CacheReusableCheckerException(message, denyThrowable);
}
protected void onAccessAllowedAfter(T object) {
}
protected void onAccessDeniedBefore(T object) {
}
}
public interface CacheReusableChecker {
void allowAccess();
void denyAccess();
}
I am new to writing API's and did some research and realize to accomplish what I want I would need to do it using Dependency Injection. I am writing an android application that haves two data source. One is expose by web services and the other is SQLlite. The SQLlite is used as backup when no data connection is available (Only interested for the webservice portion of the API for the time being will refactor). I want to write a API that provides a layer of abstraction to this that calls the right data access class based on the model required. Therefore, I have a interface that describes methods that the api should implement, called IDataAccess (Only interested in getAll for the purpose of figuring out what to do).
public interface IDataAccess {
public <T> List <T> getAll ();
public <T> T getById (int id);
}//end IDataAccess
I am using Guice for dependency injection. The guice module is:
public class Data extends AbstractModule {
public void configure () {
bind (IDataAccess.class).to(UserData.class);
}
}
and a Implementation of IDataAccess is (Note I am using Jersey Client API):
public class UserData extends DataAccessManager implements IDataAccess {
#SuppressWarnings("unchecked")
public List <User> getAll () {
WebResource webResource = client.resource (WebResourceURL.URL_USER_ALL);
ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
if (response.getStatus () == 200)
return response.getEntity(new GenericType <List <User>> () {}) ;
else
return null;
}//end getAllUsers method
}
I have a class that loads and instantiates any resource needed. It also returns a instance of a DataManager called DataAccessFactory.
public class DataAccessFactory {
private Client client;
private static DataAccessFactory instance;
private DataAccessFactory() {
client = Client.create();
}
public static DataAccessFactory getInstance() {
/*
* check if instance variable is instantiated.
* if it is not then instantiated it and returns
* created instance.
*/
if (instance == null) {
instance = new DataAccessFactory();
return instance;
} else
return instance;
}//end getInstance method
public DataAccessManager createDataAccessManager() {
return new DataAccessManager(client);
}//end createDataAccessManager method
}
Then I have the actual DataAccessManager class:
public class DataAccessManager {
protected Client client;
protected DataAccessManager (Client client)n{
this.client = client;
}//end constructor
public <T> List <Object> getAll(T t) {
Data module = new Data ();
Injector injector = Guice.createInjector(module);
IDataAccess data = (IDataAccess) injector.getInstance(t.getClass());
return (List<Object>) data;
}//end fetchAllUser method
}
To call the user model on this class I would do something like this:
#Test
public void fetchUser () {
DataAccessManager m = DataAccessFactory.getInstance().createDataAccessManager();
List<User> user = (List<User>) m.getAll(new Userdata ());
if (user == null)
assertEquals(1, 2);
else
assertEquals(1, 1);
}
Ideally what I want this to do now is, call the UserData to get all the User objects or the OrderData (When implementation is written) class to get all the order objects etc.
The problem is that this is giving a error:
Cannot cast from List to List
.How can I fix this problem or restructure this so that it makes sense?
1) You are creating an injector (Guice.createInjector) per request. Injector creation is expensive and should normally be done during application loading. You should see DI as a bootstrap mechanism and keep it simple.
2) You don't need the DataAccessFactory. First there is no need for a factory as the createDataAccessManager instantiation does not require any logic and secondly Guice could also take care of the factory pattern.
I would personally keep it simple and inject with Guice directly the UserData instance into each service that needs it, without using the rather complicated Abstraction approach showed here. Still, it does not solve the problem of dealing with network issues. My guess is that each data access class will have to deal with connectivity in a specific way, so the logic should be directly here.
For the list casting problem, see http://docs.oracle.com/javase/tutorial/java/generics/subtyping.html
If you will continue that way, I would recommend to read about erasure also.
It's a common problem you fall for. We'd expect that as String is-a Object, List<String> is-a List<Object> is true too. But it isn't. This is why this class cast won't work:
#Test
public void fetchUser () {
//...
List<User> user = (List<User>) m.getAll(new Userdata ());
//..
}
I suggest to rewrite the DataAccessManager.getAll() method to return the right kind of list.
For the record, I found a typo in DataAccessManager.getAll() method. I think when you wrote return (List<Object>) data; then you rather wanted to write return List<Object> data.getAll(); Otherwise you just cannot cast IDataAccess to List.
To escape from this casting hell I suggest to add a type to the IDataAccess interface and to its implementations:
public interface IDataAccess<T> {
public List <T> getAll ();
public T getById (int id);
}//end IDataAccess
public class UserData extends DataAccessManager<User> implements IDataAccess<User> {
// your implementation
}
I'd also clarify DataAccesManager itself:
public class DataAccessManager<T> {
//fields and constructors
public List<T> getAll(IDataAccess<T> access) { //this is how the test suggests you want to use this method
Data module = new Data ();
Injector injector = Guice.createInjector(module);
IDataAccess<T> data = (IDataAccess<T>) injector.getInstance(access.getClass()); //why is this line important? why don't you use the access parameter instead?
return data.getAll();
}
}
I'd like to access the classname of the underlying class which is an instance of java.lang.reflect.Proxy.
Is this possible?
You can get the InvocationHandler with which the proxy was created, by calling Proxy.getInvocationHandler(proxy)
Note that in the case of java.lang.reflect.Proxy there is no underlying class per se. The proxy is defined by:
interface(s)
invocation handler
And the wrapped class is usually passed to the concrete invocation handler.
I found a good solution on this site (now archived):
#SuppressWarnings({"unchecked"})
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
if (AopUtils.isJdkDynamicProxy(proxy)) {
return (T) ((Advised)proxy).getTargetSource().getTarget();
} else {
return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
}
}
Usage
#Override
protected void onSetUp() throws Exception {
getTargetObject(fooBean, FooBeanImpl.class).setBarRepository(new MyStubBarRepository());
}
Well a Proxy instance won't be an instance of java.lang.reflect.Proxy per se. Rather, it will be an instance of a subclass of java.lang.reflect.Proxy.
Anyway, the way to get the actual proxy classes name is:
Proxy proxy = ...
System.err.println("Proxy class name is " + proxy.getClass().getCanonicalName());
However, you cannot get the name of the class that the Proxy is a proxy for, because:
you proxy interfaces not classes, and
a Proxy can be a proxy for multiple interfaces
However, from looking at the source code of the ProxyGenerator class, it seems that the interfaces are recorded in the generated proxy class as the interfaces of the class. So you should be able to get them at runtime via the proxy classes Class object; e.g.
Class<?>[] classes = proxy.getClass().getInterfaces();
(Note: I've not tried this ...)
Simple and robust:
AopUtils.getTargetClass(object).getName();
Will also work for CGLIB proxies and non-proxy objects.
Here was the solution we used with my team (we need the name of the class behind the proxy) :
if (getTargetName(yourBean) ... ) {
}
With this little helper :
private String getTargetName(final Object target) {
if (target == null) {
return "";
}
if (targetClassIsProxied(target)) {
Advised advised = (Advised) target;
try {
return advised.getTargetSource().getTarget().getClass().getCanonicalName();
} catch (Exception e) {
return "";
}
}
return target.getClass().getCanonicalName();
}
private boolean targetClassIsProxied(final Object target) {
return target.getClass().getCanonicalName().contains("$Proxy");
}
Hope it helps!
You can use the following code for retrieve the info (ArrayUtils is from Apache commons lang) about invocation handler and the interfaces of the current proxy:
String.format("[ProxyInvocationHandler: %s, Interfaces: %s]",
Proxy.getInvocationHandler(proxy).getClass().getSimpleName(),
ArrayUtils.toString(proxy.getClass().getInterfaces()));
Example result:
[ProxyInvocationHandler: ExecuteProxyChain, Interfaces: {interface com.example.api.CustomerApi}]}
I found the perfect solution for me in org.springframework.aop.framework.AopProxyUtils:
AopProxyUtils.ultimateTargetClass(object).getCanonicalName()
First of all, java.lang.reflect.Proxy works only on interfaces. The framework creates a descendant class that implements the interface(s) but extends java.lang.reflect.Proxy rather than an application class that may be of interest to you. There is no inheritance of multiple classes in modern (2016) Java.
In my case, the debugger shows that the object of interest is in the obj field in the invocation handler of the proxy object.
Object handler = Proxy.getInvocationHandler(somethingProxied);
Class handlerClass = handler.getClass();
Field objField = handlerClass.getDeclaredField("obj");
objField.setAccessible(true);
Object behindProxy = objField.get(handler);
You will have to catch() two exceptions: NoSuchFieldException and IllegalAccessException.
I found it useful to print the list of fields of declared fields from the catch() clause:
...
} catch (NoSuchFieldException nsfe) {
nsfe.printStackTrace();
Object handler = Proxy.getInvocationHandler(somethingProxied);
Class handlerClass = handler.getClass();
for (Field f : handlerClass.getDeclaredFields()) {
f.setAccessible(true);
String classAndValue = null;
try {
Object v = f.get(handler);
classAndValue= "" + (v == null ? "" : v.getClass()) + " : " + v;
} catch (IllegalAccessException iae) {
iae.printStackTrace();
}
System.out.println(" field: " + f.getName() + " = " + classAndValue+ ";");
}
...
}
Note that different frameworks use different proxies and even different techniques of proxying. The solution that worked for me may be not applicable in your case. (It definitely will not work for Javassist or Hibernate proxies.)
Static Hibernate.getClass() might be useful in this scenario.
Get the true, underlying class of a proxied persistent class
public static Class getClass(Object proxy) {
if ( proxy instanceof HibernateProxy ) {
return ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer()
.getImplementation()
.getClass();
}
else {
return proxy.getClass();
}
}
Is there any technique available in Java for intercepting messages (method calls) like the method_missing technique in Ruby? This would allow coding decorators and proxies very
easily, like in Ruby:
:Client p:Proxy im:Implementation
------- ---------- -----------------
p.foo() -------> method_missing()
do_something
im.foo() ------------------> do_foo
p.bar() --------> method_missing()
do_something_more
im.bar() -------------------> do_bar
(Note: Proxy only has one method: method_missing())
As others have correctly said already, use a DynamicProxy. Here's an example.
This class uses a DynamicProxy to intercept invocations of methods declared in the "HammerListener" interface. It does some logging and then delegates to the "real" HammerListener implementation (yes, the same thing can be done with AOP).
See the newInstance method for proxy instantiation (note that you need to pass in the interface(s) the proxy should implement - a proxy can implement multiple interface).
All method invocations on interfaces that the proxy implements will end up as calls to the "invoke" method, which is declared in the "InvocationHandler" interface. All proxy handlers must implement this interface.
import java.lang.reflect.*;
/**
* Decorates a HammerListener instance, adding BEFORE/AFTER
* log messages around all methods exposed in the HammerListener interface.
*/
public class HammerListenerDecorator implements InvocationHandler {
private final HammerListener delegate;
static HammerListener newInstance(HammerListener delegate) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return (HammerListener)Proxy.newProxyInstance(cl, new Class[]{HammerListener.class},
new HammerListenerDecorator(delegate));
}
private HammerListenerDecorator(HammerListener delegate) {
this.delegate = delegate;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
logger.info("BEFORE " + method.getName() + " {{{" + argsToString(args) + "}}}");
Object rtn = method.invoke(delegate, args);
logger.info("AFTER " + method.getName());
return rtn;
}
private String argsToString(Object[] args) {
StringBuilder sb = new StringBuilder();
for (Object o : args) {
sb.append(String.valueOf(o)).append(" ");
}
return sb.toString();
}
}
java.lang.reflect.Proxy is the starting point for generating runtime proxies for interfaces you specify at runtime. It allows you to specify the interface to be proxied, as well as the object that handles the "real" invocation which, if you choose, can of course simply call something else.
The output of the Proxy class is an object that you can cast to your desired interface type, and use and invoke like any other object.
It's not going to be as easy as with a dynamic language like Ruby, but you pay a price for a strongly static language like Java.
See java.lang.reflect.Proxy and java.lang.reflect.InvocationHandler or Aspect-oriented programming in general (AspectJ for instance).
Not exactly. The closest equivalent is a Dynamic Proxy object, but that has some limitations (ie, it can only be called through reflection).