⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abstractinstantiator.java

📁 spring struts hibernate
💻 JAVA
字号:
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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -