package org.hivedb.util.classgen; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import org.hivedb.util.Mapper; import org.hivedb.util.PropertyAccessor; import org.hivedb.util.classgen.ReflectionTools; import java.util.Map; public class GeneratedClassFactory { private static MethodInterceptor getDefaultInterceptor(Class clazz) { return new GeneratedInstanceInterceptor(clazz); } public static<T> Class<? extends T> getGeneratedClass(final Class<T> clazz, MethodInterceptor interceptor) { // Only generate for interfaces. // Implementations can add whatever functionality they need, and so don't warrant a generated class if (!clazz.isInterface()) if (ReflectionTools.doesImplementOrExtend(clazz, GeneratedImplementation.class)) // clazz is a generated class then retrieve the underlying interface and regenerate the class. This gives us a fresh interceptor try { return GeneratedClassFactory.getGeneratedClass(((GeneratedImplementation)clazz.newInstance()).retrieveUnderlyingInterface(), interceptor); } catch (Exception e) { throw new RuntimeException(e); } else // clazz is normal class, don't generate return clazz; Enhancer e = new Enhancer(); e.setCallbackType(interceptor.getClass()); e.setNamingPolicy(new ImplNamer(clazz)); e.setSuperclass(Mapper.class); e.setInterfaces(new Class[] {clazz, PropertyAccessor.class, GeneratedImplementation.class}); Class<? extends T> generatedClass = e.createClass(); Enhancer.registerCallbacks(generatedClass, new Callback[] {interceptor}); return generatedClass; } public static<T> Class<? extends T> getGeneratedClass(final Class<T> clazz) { return getGeneratedClass(clazz, getDefaultInterceptor(clazz)); } public static<T> T newInstance( Class<T> clazz, MethodInterceptor interceptor ){ try{ return getGeneratedClass(clazz, interceptor).newInstance(); }catch( Throwable e ){ e.printStackTrace(); throw new RuntimeException(e.getMessage(), e); } } public static<T> T newInstance( Class<T> clazz ){ return newInstance(clazz, getDefaultInterceptor(clazz)); } public static<T> T newInstance( Class<T> clazz, MethodInterceptor interceptor, Map<String, Object> prototype ){ PropertyAccessor instance = (PropertyAccessor) newInstance(clazz, interceptor); for (String propertyName : ReflectionTools.getPropertiesOfGetters((Class<?>)clazz)) instance.set(propertyName, prototype.get(propertyName)); return (T) instance; } public static<T> T newInstance( Class<T> clazz, Map<String, Object> prototype ){ return newInstance(clazz, getDefaultInterceptor(clazz), prototype); } }