abstractinstantiator.java
来自「this is for appfuse1.8 source using stru」· Java 代码 · 共 313 行
JAVA
313 行
package org.appfuse.webapp.action;//Copyright 2004 The Apache Software Foundation////Licensed under the Apache License, Version 2.0 (the "License");//you may not use this file except in compliance with the License.//You may obtain a copy of the License at//// http://www.apache.org/licenses/LICENSE-2.0////Unless required by applicable law or agreed to in writing, software//distributed under the License is distributed on an "AS IS" BASIS,//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.//See the License for the specific language governing permissions and//limitations under the License.import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.HashMap;import java.util.Map;import javassist.CannotCompileException;import javassist.ClassPath;import javassist.ClassPool;import javassist.CtClass;import javassist.CtField;import javassist.CtMethod;import javassist.LoaderClassPath;import javassist.NotFoundException;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.apache.tapestry.ApplicationRuntimeException;import org.apache.tapestry.IResourceResolver;import org.apache.tapestry.util.DefaultResourceResolver;/** * Used to instantiate an instance of an otherwise abstract class. * Analyzes the class and builds a sub-class where all abstract properties * have real implementations. * * Found at http://howardlewisship.com/blog/2004/05/tapestry-test-assist.html */public class AbstractInstantiator { private static final Log LOG = LogFactory.getLog(AbstractInstantiator.class); private static class InstantiatorClassLoader extends ClassLoader { public InstantiatorClassLoader(ClassLoader parent) { super(parent); } public Class loadClass(String name, byte[] bytecodes) { Class result = defineClass(name, bytecodes, 0, bytecodes.length); resolveClass(result); return result; } } private ClassPool _classPool; /** * Map keyed on abstract Class, value is an enhanced Class. */ private Map _enhancedClasses = new HashMap(); private InstantiatorClassLoader _loader; private Map _primitives = new HashMap(); private IResourceResolver _resolver; private int _uid = 0; { _primitives.put(boolean.class, "boolean"); _primitives.put(short.class, "short"); _primitives.put(byte.class, "byte"); _primitives.put(char.class, "char"); _primitives.put(int.class, "int"); _primitives.put(long.class, "long"); _primitives.put(float.class, "float"); _primitives.put(double.class, "double"); } public AbstractInstantiator() { this(new DefaultResourceResolver()); } public AbstractInstantiator(IResourceResolver resolver) { _resolver = resolver; ClassLoader parentLoader = _resolver.getClassLoader(); _loader = new InstantiatorClassLoader(parentLoader); _classPool = new ClassPool(null); ClassPath path = new LoaderClassPath(parentLoader); _classPool.appendClassPath(path); } private void addAccessorMethod(CtClass ctClass, PropertyDescriptor pd, String attributeName) { String methodName = getMethodName(pd.getReadMethod(), "get", pd.getName()); CtClass returnType = getCtClass(pd.getPropertyType()); CtMethod method = new CtMethod(returnType, methodName, new CtClass[0], ctClass); try { method.setBody("{ return " + attributeName + "; }"); method.setModifiers(Modifier.PUBLIC); ctClass.addMethod(method); } catch (CannotCompileException ex) { throw new ApplicationRuntimeException(ex); } } private void addDefaultConstructor(CtClass ctClass) { } private void addField(CtClass ctClass, String fieldName, Class fieldType) { CtClass ctType = getCtClass(fieldType); try { CtField field = new CtField(ctType, fieldName, ctClass); field.setModifiers(Modifier.PRIVATE); ctClass.addField(field); } catch (CannotCompileException ex) { throw new ApplicationRuntimeException(ex); } } private void addMissingProperties(CtClass ctClass, BeanInfo info) { PropertyDescriptor[] pd = info.getPropertyDescriptors(); for (int i = 0; i < pd.length; i++) { addMissingProperty(ctClass, pd[i]); } } private void addMissingProperty(CtClass ctClass, PropertyDescriptor pd) { Method readMethod = pd.getReadMethod(); Method writeMethod = pd.getWriteMethod(); boolean abstractRead = isAbstract(readMethod); boolean abstractWrite = isAbstract(writeMethod); if (!(abstractRead || abstractWrite)) { return; } String attributeName = "_$" + pd.getName(); Class propertyType = pd.getPropertyType(); addField(ctClass, attributeName, propertyType); if (abstractRead) { addAccessorMethod(ctClass, pd, attributeName); } if (abstractWrite) { addMutatorMethod(ctClass, pd, attributeName); } } private void addMutatorMethod(CtClass ctClass, PropertyDescriptor pd, String attributeName) { String methodName = getMethodName(pd.getWriteMethod(), "set", pd.getName()); CtClass parameterType = getCtClass(pd.getPropertyType()); CtMethod method = new CtMethod(CtClass.voidType, methodName, new CtClass[] { parameterType }, ctClass); try { method.setBody("{ " + attributeName + " = $1; }"); method.setModifiers(Modifier.PUBLIC); ctClass.addMethod(method); } catch (CannotCompileException ex) { throw new ApplicationRuntimeException(ex); } } private String constructNewClassName(Class inputClass) { return inputClass.getName() + "$enhance_" + _uid++; } private Class createEnhancedClass(Class inputClass) { if (inputClass.isInterface()) { throw new IllegalArgumentException("Can not create instance of interface " + inputClass.getName() + "."); } if (!Modifier.isAbstract(inputClass.getModifiers())) { LOG.error("Class " + inputClass.getName() + " is not abstract."); return inputClass; } BeanInfo info = null; try { info = Introspector.getBeanInfo(inputClass, Object.class); } catch (IntrospectionException ex) { throw new ApplicationRuntimeException("Unable to introspect class " + inputClass.getName() + ": " + ex.getMessage(), ex); } String newName = constructNewClassName(inputClass); CtClass newClass = _classPool.makeClass(newName, getCtClass(inputClass)); addMissingProperties(newClass, info); addDefaultConstructor(newClass); try { // newClass.writeFile(); byte[] bytecode = _classPool.write(newName); return _loader.loadClass(newName, bytecode); } catch (Exception ex) { throw new ApplicationRuntimeException("Unable to instantiate enhanced subclass " + newClass.getName() + ": " + ex.getMessage(), ex); } } private CtClass getCtClass(Class inputClass) { String name = getCtName(inputClass); try { return _classPool.get(name); } catch (NotFoundException ex) { throw new ApplicationRuntimeException(ex); } } private String getCtName(Class inputClass) { if (inputClass.isArray()) { return getCtName(inputClass.getComponentType()) + "[]"; } if (inputClass.isPrimitive()) { return (String) _primitives.get(inputClass); } return inputClass.getName(); } public Class getEnhancedClass(Class inputClass) { Class result = (Class) _enhancedClasses.get(inputClass); if (result == null) { result = createEnhancedClass(inputClass); _enhancedClasses.put(inputClass, result); } return result; } /** * Given a particular abstract class; will create an instance of that class. A subclass * is created with all abstract properties filled in with ordinary implementations. */ public Object getInstance(Class abstractClass) { Class enhancedClass = getEnhancedClass(abstractClass); try { return enhancedClass.newInstance(); } catch (Exception ex) { throw new ApplicationRuntimeException("Unable to instantiate instance of " + enhancedClass.getName() + ": " + ex.getMessage(), ex); } } private String getMethodName(Method m, String prefix, String propertyName) { if (m != null) { return m.getName(); } StringBuffer buffer = new StringBuffer(prefix); buffer.append(propertyName.substring(0, 1).toUpperCase()); buffer.append(propertyName.substring(1)); return buffer.toString(); } private boolean isAbstract(Method m) { return (m == null) || Modifier.isAbstract(m.getModifiers()); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?