All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snapscript.cglib.proxy.ConcreteClassGenerator Maven / Gradle / Ivy

There is a newer version: 1.4.6
Show newest version
/*
 * Copyright 2003 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.snapscript.cglib.proxy;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.snapscript.asm.ClassVisitor;
import org.snapscript.asm.Type;
import org.snapscript.cglib.core.AbstractClassGenerator;
import org.snapscript.cglib.core.ClassEmitter;
import org.snapscript.cglib.core.CodeEmitter;
import org.snapscript.cglib.core.CollectionUtils;
import org.snapscript.cglib.core.Constants;
import org.snapscript.cglib.core.DuplicatesPredicate;
import org.snapscript.cglib.core.EmitUtils;
import org.snapscript.cglib.core.KeyFactory;
import org.snapscript.cglib.core.MethodInfo;
import org.snapscript.cglib.core.MethodInfoTransformer;
import org.snapscript.cglib.core.MethodWrapper;
import org.snapscript.cglib.core.Predicate;
import org.snapscript.cglib.core.ReflectUtils;
import org.snapscript.cglib.core.RejectModifierPredicate;
import org.snapscript.cglib.core.Signature;
import org.snapscript.cglib.core.Transformer;
import org.snapscript.cglib.core.TypeUtils;
import org.snapscript.cglib.core.VisibilityPredicate;

/**
 * @author Juozas Baliuka, Chris Nokleberg
 */
public class ConcreteClassGenerator extends AbstractClassGenerator
{
    private static final Source SOURCE = new Source(ConcreteClassGenerator.class.getName());
    private static final ConcreteClassGeneratorKey KEY_FACTORY =
      (ConcreteClassGeneratorKey)KeyFactory.create(ConcreteClassGeneratorKey.class);
    
    interface ConcreteClassGeneratorKey {
        public Object newInstance(String superclass, String[] interfaces);
    }

    private Class[] interfaces;
    private Class superclass;
    private boolean classOnly;

    public ConcreteClassGenerator() {
        super(SOURCE);
    }

    /**
     * Set the class which the generated class will extend. The class
     * must not be declared as final, and must have a non-private
     * no-argument constructor.
     * @param superclass class to extend, or null to extend Object
     */
    public void setSuperclass(Class superclass) {
        if (superclass != null && superclass.equals(Object.class)) {
            superclass = null;
        }
        this.superclass = superclass;
    }
    
    /**
     * Set the interfaces to implement. The Factory interface will
     * always be implemented regardless of what is specified here.
     * @param interfaces array of interfaces to implement, or null
     * @see Factory
     */
    public void setInterfaces(Class... interfaces) {
        this.interfaces = interfaces;
    }

    protected ClassLoader getDefaultClassLoader() {
        if (superclass != null) {
            return superclass.getClassLoader();
        } else {
            return null;
        }
    }

    protected ProtectionDomain getProtectionDomain() {
        return ReflectUtils.getProtectionDomain(superclass);
    }

    public Class createClass() {
        classOnly = true;
        return createHelper();
    }

    private Class createHelper() {
        if (superclass != null) {
            setNamePrefix(superclass.getName());
        }
        String superName = (superclass != null) ? superclass.getName() : "java.lang.Object";
        Object key = KEY_FACTORY.newInstance(superName, ReflectUtils.getNames(interfaces));
        return (Class)super.create(key);
    }

    public void generateClass(ClassVisitor v) throws Exception {
       Class sc = (superclass == null) ? Object.class : superclass;

       if (TypeUtils.isFinal(sc.getModifiers()))
           throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
       List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
       Enhancer.filterConstructors(sc, constructors);
       
       // Order is very important: must add superclass, then
       // its superclass chain, then each interface and
       // its superinterfaces.
       List actualMethods = new ArrayList();
       List interfaceMethods = new ArrayList();
       final Set forcePublic = new HashSet();
       getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic);
       
       List methods = CollectionUtils.transform(actualMethods, new Transformer() {
          public Object transform(Object value) {
              Method method = (Method)value;
              int modifiers = Constants.ACC_FINAL
                  | (method.getModifiers()
                     & ~Constants.ACC_ABSTRACT
                     & ~Constants.ACC_NATIVE
                     & ~Constants.ACC_SYNCHRONIZED);
              if (forcePublic.contains(MethodWrapper.create(method))) {
                  modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;
              }
              return ReflectUtils.getMethodInfo(method, modifiers);
          }
       });
       ClassEmitter ce = new ClassEmitter(v);
       ce.begin_class(Constants.V1_2,
             Constants.ACC_PUBLIC,
             getClassName(),
             Type.getType(sc),
             TypeUtils.getTypes(interfaces),
             Constants.SOURCE_FILE);
       List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
       emitConstructors(ce, constructorInfo);
       Iterator iterator = methods.iterator();
       
       while(iterator.hasNext()) {
          MethodInfo methodInfo = (MethodInfo)iterator.next();
          CodeEmitter emitter = EmitUtils.begin_method(ce, methodInfo);
          emitter.throw_exception(Type.getType(UnsupportedOperationException.class), "Method not implemented");
          emitter.end_method();
       }
       ce.end_class();
    }
    
    private void emitConstructors(ClassEmitter ce, List constructors) {
       boolean seenNull = false;
       for (Iterator it = constructors.iterator(); it.hasNext();) {
           MethodInfo constructor = (MethodInfo)it.next();
           CodeEmitter e = EmitUtils.begin_method(ce, constructor, Constants.ACC_PUBLIC);
           e.load_this();
           e.dup();
           e.load_args();
           Signature sig = constructor.getSignature();
           seenNull = seenNull || sig.getDescriptor().equals("()V");
           e.super_invoke_constructor(sig);
           e.return_value();
           e.end_method();
       }
   }
    
    public static void getMethods(Class superclass, Class[] interfaces, List methods, List interfaceMethods, Set forcePublic)
    {
        ReflectUtils.addAllMethods(superclass, methods);
        List target = (interfaceMethods != null) ? interfaceMethods : methods;
        if (interfaces != null) {
            for (int i = 0; i < interfaces.length; i++) {
                if (interfaces[i] != Factory.class) {
                    ReflectUtils.addAllMethods(interfaces[i], target);
                }
            }
        }
        if (interfaceMethods != null) {
            if (forcePublic != null) {
                forcePublic.addAll(MethodWrapper.createSet(interfaceMethods));
            }
            methods.addAll(interfaceMethods);
        }
        CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_STATIC));
        CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true));
        CollectionUtils.filter(methods, new DuplicatesPredicate());
        CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_FINAL));
        CollectionUtils.filter(methods, new Predicate() {
           public boolean evaluate(Object name) {
               Method method = (Method)name;
               int modifiers = method.getModifiers();
               return Modifier.isAbstract(modifiers);
           }
        });
    }

    protected Object firstInstance(Class type) {
        if (classOnly) {
            return type;
        } else {
            return ReflectUtils.newInstance(type);
        }
    }

    protected Object nextInstance(Object instance) {
        Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass();
        if (classOnly) {
            return protoclass;
        } else {
            return ReflectUtils.newInstance(protoclass);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy