Save This Page
Home » cglib-src-2.2 » net.sf.cglib.core » [javadoc | source]
    1   /*
    2    * Copyright 2003 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    *  Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   package net.sf.cglib.core;
   17   
   18   import java.io;
   19   import java.util;
   20   import org.objectweb.asm;
   21   
   22   /**
   23    * @author Juozas Baliuka, Chris Nokleberg
   24    */
   25   public class ClassEmitter extends ClassAdapter {
   26       private ClassInfo classInfo;
   27       private Map fieldInfo;
   28   
   29       private static int hookCounter;
   30       private MethodVisitor rawStaticInit;
   31       private CodeEmitter staticInit;
   32       private CodeEmitter staticHook;
   33       private Signature staticHookSig;
   34   
   35       public ClassEmitter(ClassVisitor cv) {
   36           super(null);
   37           setTarget(cv);
   38       }
   39   
   40       public ClassEmitter() {
   41           super(null);
   42       }
   43   
   44       public void setTarget(ClassVisitor cv) {
   45           this.cv = cv;
   46           fieldInfo = new HashMap();
   47   
   48           // just to be safe
   49           staticInit = staticHook = null;
   50           staticHookSig = null;
   51       }
   52   
   53       synchronized private static int getNextHook() {
   54           return ++hookCounter;
   55       }
   56   
   57       public ClassInfo getClassInfo() {
   58           return classInfo;
   59       }
   60   
   61       public void begin_class(int version, final int access, String className, final Type superType, final Type[] interfaces, String source) {
   62           final Type classType = Type.getType("L" + className.replace('.', '/') + ";");
   63           classInfo = new ClassInfo() {
   64               public Type getType() {
   65                   return classType;
   66               }
   67               public Type getSuperType() {
   68                   return (superType != null) ? superType : Constants.TYPE_OBJECT;
   69               }
   70               public Type[] getInterfaces() {
   71                   return interfaces;
   72               }
   73               public int getModifiers() {
   74                   return access;
   75               }
   76           };
   77           cv.visit(version,
   78                    access,
   79                    classInfo.getType().getInternalName(),
   80                    null,
   81                    classInfo.getSuperType().getInternalName(),
   82                    TypeUtils.toInternalNames(interfaces));
   83           if (source != null)
   84               cv.visitSource(source, null);
   85           init();
   86       }
   87   
   88       public CodeEmitter getStaticHook() {
   89            if (TypeUtils.isInterface(getAccess())) {
   90                throw new IllegalStateException("static hook is invalid for this class");
   91            }
   92            if (staticHook == null) {
   93                staticHookSig = new Signature("CGLIB$STATICHOOK" + getNextHook(), "()V");
   94                staticHook = begin_method(Constants.ACC_STATIC,
   95                                          staticHookSig,
   96                                          null);
   97                if (staticInit != null) {
   98                    staticInit.invoke_static_this(staticHookSig);
   99                }
  100            }
  101            return staticHook;
  102       }
  103   
  104       protected void init() {
  105       }
  106   
  107       public int getAccess() {
  108           return classInfo.getModifiers();
  109       }
  110   
  111       public Type getClassType() {
  112           return classInfo.getType();
  113       }
  114   
  115       public Type getSuperType() {
  116           return classInfo.getSuperType();
  117       }
  118   
  119       public void end_class() {
  120           if (staticHook != null && staticInit == null) {
  121               // force creation of static init
  122               begin_static();
  123           }
  124           if (staticInit != null) {
  125               staticHook.return_value();
  126               staticHook.end_method();
  127               rawStaticInit.visitInsn(Constants.RETURN);
  128               rawStaticInit.visitMaxs(0, 0);
  129               staticInit = staticHook = null;
  130               staticHookSig = null;
  131           }
  132           cv.visitEnd();
  133       }
  134   
  135       public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
  136           if (classInfo == null)
  137               throw new IllegalStateException("classInfo is null! " + this);
  138           MethodVisitor v = cv.visitMethod(access,
  139                                            sig.getName(),
  140                                            sig.getDescriptor(),
  141                                            null,
  142                                            TypeUtils.toInternalNames(exceptions));
  143           if (sig.equals(Constants.SIG_STATIC) && !TypeUtils.isInterface(getAccess())) {
  144               rawStaticInit = v;
  145               MethodVisitor wrapped = new MethodAdapter(v) {
  146                   public void visitMaxs(int maxStack, int maxLocals) {
  147                       // ignore
  148                   }
  149                   public void visitInsn(int insn) {
  150                       if (insn != Constants.RETURN) {
  151                           super.visitInsn(insn);
  152                       }
  153                   }
  154               };
  155               staticInit = new CodeEmitter(this, wrapped, access, sig, exceptions);
  156               if (staticHook == null) {
  157                   // force static hook creation
  158                   getStaticHook();
  159               } else {
  160                   staticInit.invoke_static_this(staticHookSig);
  161               }
  162               return staticInit;
  163           } else if (sig.equals(staticHookSig)) {
  164               return new CodeEmitter(this, v, access, sig, exceptions) {
  165                   public boolean isStaticHook() {
  166                       return true;
  167                   }
  168               };
  169           } else {
  170               return new CodeEmitter(this, v, access, sig, exceptions);
  171           }
  172       }
  173   
  174       public CodeEmitter begin_static() {
  175           return begin_method(Constants.ACC_STATIC, Constants.SIG_STATIC, null);
  176       }
  177   
  178       public void declare_field(int access, String name, Type type, Object value) {
  179           FieldInfo existing = (FieldInfo)fieldInfo.get(name);
  180           FieldInfo info = new FieldInfo(access, name, type, value);
  181           if (existing != null) {
  182               if (!info.equals(existing)) {
  183                   throw new IllegalArgumentException("Field \"" + name + "\" has been declared differently");
  184               }
  185           } else {
  186               fieldInfo.put(name, info);
  187               cv.visitField(access, name, type.getDescriptor(), null, value);
  188           }
  189       }
  190   
  191       // TODO: make public?
  192       boolean isFieldDeclared(String name) {
  193           return fieldInfo.get(name) != null;
  194       }
  195   
  196       FieldInfo getFieldInfo(String name) {
  197           FieldInfo field = (FieldInfo)fieldInfo.get(name);
  198           if (field == null) {
  199               throw new IllegalArgumentException("Field " + name + " is not declared in " + getClassType().getClassName());
  200           }
  201           return field;
  202       }
  203       
  204       static class FieldInfo {
  205           int access;
  206           String name;
  207           Type type;
  208           Object value;
  209           
  210           public FieldInfo(int access, String name, Type type, Object value) {
  211               this.access = access;
  212               this.name = name;
  213               this.type = type;
  214               this.value = value;
  215           }
  216   
  217           public boolean equals(Object o) {
  218               if (o == null)
  219                   return false;
  220               if (!(o instanceof FieldInfo))
  221                   return false;
  222               FieldInfo other = (FieldInfo)o;
  223               if (access != other.access ||
  224                   !name.equals(other.name) ||
  225                   !type.equals(other.type)) {
  226                   return false;
  227               }
  228               if ((value == null) ^ (other.value == null))
  229                   return false;
  230               if (value != null && !value.equals(other.value))
  231                   return false;
  232               return true;
  233           }
  234   
  235           public int hashCode() {
  236               return access ^ name.hashCode() ^ type.hashCode() ^ ((value == null) ? 0 : value.hashCode());
  237           }
  238       }
  239   
  240       public void visit(int version,
  241                         int access,
  242                         String name,
  243                         String signature,
  244                         String superName,
  245                         String[] interfaces) {
  246           begin_class(version,
  247                       access,
  248                       name.replace('/', '.'),
  249                       TypeUtils.fromInternalName(superName),
  250                       TypeUtils.fromInternalNames(interfaces),
  251                       null); // TODO
  252       }
  253       
  254       public void visitEnd() {
  255           end_class();
  256       }
  257       
  258       public FieldVisitor visitField(int access,
  259                                      String name,
  260                                      String desc,
  261                                      String signature,
  262                                      Object value) {
  263           declare_field(access, name, Type.getType(desc), value);
  264           return null; // TODO
  265       }
  266       
  267       public MethodVisitor visitMethod(int access,
  268                                        String name,
  269                                        String desc,
  270                                        String signature,
  271                                        String[] exceptions) {
  272           return begin_method(access,
  273                               new Signature(name, desc),
  274                               TypeUtils.fromInternalNames(exceptions));        
  275       }
  276   }

Save This Page
Home » cglib-src-2.2 » net.sf.cglib.core » [javadoc | source]