マジックメソッド

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);
		}
	}
}