package org.cyclopsgroup.jmxterm.utils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; import javax.naming.OperationNotSupportedException; import org.apache.commons.lang.Validate; /** * Utility that cast object into given interface(s) even though class doesn't implement interface(s) * * @author <a href="mailto:jiaqi.guo@gmail.com">Jiaqi Guo</a> */ public final class WeakCastUtils { /** * Cast object into multiple interfaces * * @param from Object to cast * @param interfaces Interfaces to cast to * @param classLoader ClassLoader to load methods for invocation * @return Result that implements given interfaces * @throws SecurityException * @throws NoSuchMethodException */ public static Object cast( final Object from, final Class<?>[] interfaces, ClassLoader classLoader ) throws SecurityException, NoSuchMethodException { Validate.notNull( from, "Invocation target can't be NULL" ); Validate.notNull( interfaces, "Interfaces can't be NULL" ); Validate.notNull( classLoader, "ClassLoader can't be NULL" ); final Map<Method, Method> methodMap = new HashMap<Method, Method>(); for ( Class<?> interfase : interfaces ) { Validate.isTrue( interfase.isInterface(), interfase + " is not an interface" ); for ( Method fromMethod : interfase.getMethods() ) { Method toMethod = from.getClass().getMethod( fromMethod.getName(), fromMethod.getParameterTypes() ); methodMap.put( fromMethod, toMethod ); } } return Proxy.newProxyInstance( classLoader, interfaces, new InvocationHandler() { public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable { Method toMethod = methodMap.get( method ); if ( toMethod == null ) { throw new OperationNotSupportedException( "Method " + method + " isn't implemented in " + from.getClass() ); } try { if ( ( toMethod.getModifiers() & Modifier.STATIC ) == 0 ) { return toMethod.invoke( from, args ); } return toMethod.invoke( null, args ); } catch ( InvocationTargetException e ) { throw e.getCause(); } } } ); } /** * Cast object to one given interface using ClassLoader of interface * * @param <T> Type of interface * @param from Object to cast * @param interfase Interface to cast to * @return Result that implements interface * @throws SecurityException * @throws NoSuchMethodException */ public static <T> T cast( Object from, Class<T> interfase ) throws SecurityException, NoSuchMethodException { return cast( from, interfase, interfase.getClassLoader() ); } /** * Cast object to one given interface * * @param <T> Type of interface * @param from Object to cast * @param interfase Interface to cast to * @param classLoader Class loader to load invocation methods * @return Result that implements interface * @throws SecurityException * @throws NoSuchMethodException */ @SuppressWarnings( "unchecked" ) public static <T> T cast( Object from, Class<T> interfase, ClassLoader classLoader ) throws SecurityException, NoSuchMethodException { Validate.notNull( interfase, "Interface can't be NULL" ); return (T) cast( from, new Class<?>[] { interfase }, classLoader ); } /** * Cast static methods of a class to given interfaces * * @param from From class * @param interfaces To interfaces * @param classLoader Class loader * @return Casted result * @throws SecurityException * @throws NoSuchMethodException */ public static Object staticCast( final Class<?> from, final Class<?>[] interfaces, ClassLoader classLoader ) throws SecurityException, NoSuchMethodException { Validate.notNull( from, "Invocation target type can't be NULL" ); Validate.notNull( interfaces, "Interfaces can't be NULL" ); Validate.notNull( classLoader, "ClassLoader can't be NULL" ); final Map<Method, Method> methodMap = new HashMap<Method, Method>(); for ( Class<?> interfase : interfaces ) { Validate.isTrue( interfase.isInterface(), interfase + " is not an interface" ); for ( Method fromMethod : interfase.getMethods() ) { Method toMethod = from.getMethod( fromMethod.getName(), fromMethod.getParameterTypes() ); if ( ( toMethod.getModifiers() & Modifier.STATIC ) == 0 ) { throw new NoSuchMethodException( "Method " + toMethod + " isn't static" ); } methodMap.put( fromMethod, toMethod ); } } return Proxy.newProxyInstance( classLoader, interfaces, new InvocationHandler() { public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable { Method toMethod = methodMap.get( method ); if ( toMethod == null ) { throw new OperationNotSupportedException( "Method " + method + " isn't implemented in " + from.getClass() ); } try { return toMethod.invoke( null, args ); } catch ( InvocationTargetException e ) { throw e.getCause(); } } } ); } /** * Cast static class to one given interface * * @param <T> Type of interface to casts to * @param from Type of static class to casts from * @param interfase Interface to cast to * @return Result that implements interface * @throws SecurityException * @throws NoSuchMethodException */ public static <T> T staticCast( Class<?> from, Class<T> interfase ) throws SecurityException, NoSuchMethodException { return staticCast( from, interfase, interfase.getClassLoader() ); } /** * Cast static class to one given interface * * @param <T> Type of interface to casts to * @param from Type of static class to casts from * @param interfase Interface to cast to * @param classLoader Class loader to load result * @return Result that implements interface * @throws SecurityException * @throws NoSuchMethodException */ @SuppressWarnings( "unchecked" ) public static <T> T staticCast( Class<?> from, Class<T> interfase, ClassLoader classLoader ) throws SecurityException, NoSuchMethodException { return (T) staticCast( from, new Class<?>[] { interfase }, classLoader ); } private WeakCastUtils() { } }