マジックメソッド
S2DAO的な何かを自分なりに作ろうかと思って
色々考えてたら、PHPで言う所のマジックメソッドになった。
pythonで言えば__getattribute__を使ってごにょごにょしたり
とか
public interface TestDao { void hogehoge(String hoge); void fugafuga(String fuga); }
みたいなインターフェースの実態を
public interface MagicCommand { Object execute(final String methodName,final Object ... arguments); }
こんなインタフェースを実装して行う
返り値の型の取得を如何するか悩み中
んでソレのソースが↓
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtField; import javassist.CtMethod; import javassist.NotFoundException; /** * implement class * @author Aileron * */ public class MagicMethodImplementFactory { /** * Interface の 実体 を 生成し instance を 生成します * @param <T> * @param interfaceClass * @return * @throws Exception */ @SuppressWarnings("unchecked") public <T> T createImplementInstance( final MagicCommand command, final Class<T> interfaceClass) throws Exception { final String className = interfaceClass.getName(); final CtClass targetClass = setConstruct(newClass(className)); for(final CtMethod method: targetClass.getMethods()) { if(!methodName.containsKey(method.getName())) { setMethod(targetClass, method); } } return (T) newInstance( targetClass.toClass( interfaceClass.getClassLoader() ) , command); } /** * new instance * @param interfaceClass * @param command * @return * @throws NoSuchMethodException * @throws InstantiationException * @throws InvocationTargetException * @throws IllegalAccessException */ private Object newInstance( final Class<?> interfaceClass, final MagicCommand command) throws NoSuchMethodException ,InstantiationException ,InvocationTargetException ,IllegalAccessException { final Constructor<?> constructor = interfaceClass.getConstructor(MagicCommand.class); final Object result = constructor.newInstance(new Object[]{ command }); return result; } /** * method の 設定 * @param targetClass * @param intarfaceMethod * @throws NotFoundException * @throws CannotCompileException */ private void setMethod(final CtClass targetClass, final CtMethod intarfaceMethod) throws NotFoundException,CannotCompileException { final CtMethod targetMethod = new CtMethod( intarfaceMethod.getReturnType(), intarfaceMethod.getName(), intarfaceMethod.getParameterTypes(), targetClass); final String quote = "\""; final String methodName = quote + intarfaceMethod.getName() + quote; final String method = intarfaceMethod.getParameterTypes().length==0 ? "this.command.execute("+methodName+",null);" : "this.command.execute("+methodName+",$args);"; if( intarfaceMethod.getReturnType() == CtClass.voidType ) { targetMethod.setBody("{"+method+"}"); } else { targetMethod.setBody("{"+"return ($r) "+method+"}"); } targetClass.addMethod(targetMethod); } /** * intarface を実装した class を返します * @param className * @return * @throws NotFoundException */ private CtClass newClass(final String className) throws NotFoundException { final CtClass targetClass = pool.makeClass(className+"Impl"); targetClass.addInterface( pool.get(className) ); return targetClass; } /** * コンストラクタを設定します * @param targetClass * @throws CannotCompileException */ private CtClass setConstruct(final CtClass targetClass) throws CannotCompileException,NotFoundException { setField(targetClass); final CtConstructor constructor = new CtConstructor(CONSTRUCT_ARGS, targetClass); constructor.setBody("this.command = $1;"); targetClass.addConstructor(constructor); return targetClass; } /** * field の追加 * @param targetClass * @return * @throws NotFoundException * @throws CannotCompileException */ private CtClass setField(final CtClass targetClass) throws NotFoundException,CannotCompileException { final CtField ctField = new CtField(CLASS_COMMAND,CLASS_COMMAND_NAME, targetClass); targetClass.addField(ctField); return targetClass; } /** * pool */ private static final ClassPool pool = ClassPool.getDefault(); /** * command name */ private static final String CLASS_COMMAND_NAME = "command"; /** * magicCommand class */ private static final CtClass CLASS_COMMAND; static { CtClass ctClass = null; try { ctClass = pool.get(MagicCommand.class.getName()); } catch(NotFoundException e){} CLASS_COMMAND = ctClass; } /** * construct args */ private static final CtClass[] CONSTRUCT_ARGS = { CLASS_COMMAND }; /** * object.class の method 名 一覧 */ private static final HashMap<String,Void> methodName = new HashMap<String, Void>(); static { for(final Method method : Object.class.getMethods()) { methodName.put(method.getName(), null); } } }