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

📄 abstractinstantiator.java

📁 Thinking in Java 3 中文版,经典java入门必看教程,最流行的java学习用书.
💻 JAVA
字号:
//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.

package org.apache.tapestry.test;

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.
 */
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 + -