WEB开发网
开发学院软件开发Java Classworking 工具箱: 分析泛型数据结构 阅读

Classworking 工具箱: 分析泛型数据结构

 2010-03-18 00:00:00 来源:WEB开发网   
核心提示: 清单 3 代码中有意思的部分在于内部的 DescriptionBuilderVisitor 类,这个类是 ASM 的 EmptyVisitor 类的扩展,Classworking 工具箱: 分析泛型数据结构(5),只覆盖了两个方法,覆盖的 visit() 方法处理实际的类信息,处理类型替换现在我

清单 3 代码中有意思的部分在于内部的 DescriptionBuilderVisitor 类。这个类是 ASM 的 EmptyVisitor 类的扩展,只覆盖了两个方法。覆盖的 visit() 方法处理实际的类信息,创建嵌套内部类 ClassSignatureVisitor 的实例,处理有签名的类(即泛型类)。这个嵌套内部类的要点就在于扫描泛型类的类型参数,找到每个泛型类的最佳上部绑定,并在包含它们的 DescriptionBuilderVisitor 类实例所拥有的哈希映射中设置这个绑定。DescriptionBuilderVisitor 覆盖的 visitField() 方法只检查字段有没有签名。如果字段没有签名,visitField() 就只用字段描述符字符串从类型目录获得类型信息。如果字段确实 有签名,那么 visitField() 就使用类型目录查找的备选形式(接受签名和替换类型的哈希映射)。

DescriptionBuilderVisitor 类代码的实际效果是构建一组字段定义,与提供给 SimpleClassDescription 构造函数的类的字段匹配。如果提供的类是泛型类,那么即使为这个类提供了最通用的参数类型定义,也会处理类的所有字段。对于类型参数定义的最简单形式,这个最通用的参数类型就是 java.lang.Object;如果类型参数定义包含类或接口绑定(例如 public class MyClass<T implements java.util.List>),那么最通用的类型与指定绑定匹配。

处理类型替换

现在我们已经完成了最简单的处理部分,剩下的惟一部分是实际的类型替换处理。清单 4 显示了执行这个处理的代码,包括 清单 2 所示的 TypeDirectory 类中遗漏的部分和新的 GenericTemplate 类:

清单 4. 类型替换代码

public class TypeDirectory 
{ 
  ... 
  /** Map from generic classes descriptor to generic class information. */ 
  private HashMap<String,GenericTemplate> m_templateMap = 
    new HashMap<String,GenericTemplate>(); 
  ... 
   
   
  /** 
   * Get description for generic class with specific type substitutions. 
   * 
   * @param sig field signature with type substitutions 
   * @param types actual types used for instance (values may be 
   * <code>null</code> if no substitution defined) 
   * @return type description 
   */ 
  public TypeDescription getSignatureInstance(String sig, 
    TypeDescription[] types) { 
     
    // first check for direct match on substituted signature 
    TypeDescription desc = (TypeDescription)m_typeMap.get(sig); 
    if (desc == null) { 
       
      // no direct match, first handle array 
      if (sig.charAt(0) == '[') { 
        desc = new ArrayClassDescriptor(sig, 
          getSignatureInstance(sig.substring(1), types)); 
      } else { 
         
        // not an array, get the generic class descriptor 
        String dtor = sig; 
        int split = dtor.indexOf('<'); 
        if (split >= 0) { 
          dtor = dtor.substring(0, split) + ';'; 
        } 
        GenericTemplate gdesc = m_templateMap.get(dtor); 
        if (gdesc == null) { 
          byte[] byts = m_loader.getBytes(dtor); 
          gdesc = new GenericTemplate(dtor, byts, this); 
        } 
         
        // handle type substitution to generic version of class 
        desc = gdesc.getParameterized(sig, types); 
      } 
    } 
    return desc; 
  } 
   
  /** 
   * Get description for signature with type mapping. 
   * 
   * @param sig field signature for type variables 
   * @param tmap type mapping for variables 
   * @return type description 
   */ 
  public TypeDescription getMappedSignatureInstance(String sig, 
    HashMap<String,TypeDescription> tmap) { 
    SignatureDecompositionVisitor vtor = 
      new SignatureDecompositionVisitor(tmap); 
    new SignatureReader(sig).acceptType(vtor); 
    return vtor.getDescription(); 
  } 
   
  /** 
   * Visitor for processing a signature with type substitutions. This uses 
   * itself recursively to process nested signatures, substituting actual 
   * types for any type variable references found. 
   */ 
  public class SignatureDecompositionVisitor extends EmptySignatureVisitor 
  { 
    private final HashMap<String,TypeDescription> m_parameterMap; 
    private int m_arrayCount; 
    private String m_className; 
    private char m_baseClass; 
    private ArrayList<TypeDescription> m_parameterTypes; 
    private boolean m_isNested; 
    private SignatureDecompositionVisitor m_nestedVisitor; 
     
    private void reset() { 
      m_arrayCount = 0; 
      m_className = null; 
      m_parameterTypes.clear(); 
      m_isNested = false; 
    } 
     
    private SignatureDecompositionVisitor(HashMap<String,TypeDescription> tmap) { 
      m_parameterMap = tmap; 
      m_parameterTypes = new ArrayList<TypeDescription>(); 
    } 
     
    private void checkParameter() { 
      if (m_isNested) { 
        m_parameterTypes.add(m_nestedVisitor.getDescription()); 
        m_isNested = false; 
      } 
    } 
     
    public SignatureVisitor visitArrayType() { 
      m_arrayCount++; 
      return this; 
    } 
     
    public void visitBaseType(char desc) { 
      m_baseClass = desc; 
    } 
     
    public void visitTypeVariable(String name) { 
      String dtor = m_parameterMap.get(name).getDescriptor(); 
      if (dtor == null) { 
        throw new IllegalStateException("Undefined type variable " + name); 
      } else if (dtor.length() < 3 || dtor.charAt(0) != 'L' || 
        dtor.charAt(dtor.length()-1) != ';') { 
        throw new IllegalArgumentException 
          ("Not a valid class descriptor: " + dtor); 
      } else { 
        m_className = dtor.substring(1, dtor.length()-1); 
      } 
    } 
     
    public void visitClassType(String name) { 
      m_className = name; 
    } 
     
    public SignatureVisitor visitTypeArgument(char wildcard) { 
      checkParameter(); 
      if (wildcard == '=' || wildcard == '+') { 
        if (m_nestedVisitor == null) { 
          m_nestedVisitor = new SignatureDecompositionVisitor(m_parameterMap); 
        } else { 
          m_nestedVisitor.reset(); 
        } 
        m_isNested = true; 
        return m_nestedVisitor; 
      } else { 
        m_parameterTypes.add(null); 
        return new EmptySignatureVisitor(); 
      } 
    } 
     
    public void visitTypeArgument() { 
      checkParameter(); 
      m_parameterTypes.add(null); 
    } 
     
    public void visitEnd() { 
      checkParameter(); 
    } 
     
    public TypeDescription getDescription() { 
       
      // create array signature prefix 
      StringBuffer buff = new StringBuffer(); 
      for (int i = 0; i < m_arrayCount; i++) { 
        buff.append('['); 
      } 
       
      // get the actual type description 
      if (m_className == null) { 
        buff.append(m_baseClass); 
        return getTypeInstance(buff.toString()); 
      } else { 
         
        // construct both descriptor and full signature for type 
        buff.append('L'); 
        buff.append(m_className); 
        if (m_parameterTypes.size() > 0) { 
          buff.append('<'); 
          for (int i = 0; i < m_parameterTypes.size(); i++) { 
            TypeDescription pdesc = m_parameterTypes.get(i); 
            if (pdesc == null) { 
              buff.append('*'); 
            } else { 
              buff.append(pdesc.getDescriptor()); 
            } 
          } 
          buff.append('>'); 
        } 
        buff.append(';'); 
         
        // get actual class description 
        if (m_parameterTypes.size() == 0) { 
          return getTypeInstance(buff.toString()); 
        } else { 
          TypeDescription[] ptypes = 
            new TypeDescription[m_parameterTypes.size()]; 
          ptypes = m_parameterTypes.toArray(ptypes); 
          return getSignatureInstance(buff.toString(), ptypes); 
        } 
      } 
    } 
  } 
  ... 
} 
 
public class GenericTemplate 
{ 
  private final String m_descriptor; 
  private final String m_baseName; 
  private final TypeDirectory m_typeDirectory; 
  private final FieldDescription[] m_genericFields; 
  private final String[] m_typeParameters; 
  private final TypeDescription[] m_upperBounds; 
   
  protected GenericTemplate(String dtor, byte[] byts, TypeDirectory dir) { 
    m_descriptor = dtor; 
    m_baseName = BinaryClassLoader.nameFromDescriptor(dtor); 
    m_typeDirectory = dir; 
    dir.addTemplate(this); 
    DescriptionBuilderVisitor vtor = new DescriptionBuilderVisitor(dir); 
    ClassReader creader = new ClassReader(byts); 
    creader.accept(vtor, true); 
    m_genericFields = vtor.getFields(); 
    m_typeParameters = vtor.getTypeParameters(); 
    m_upperBounds = vtor.getUpperBounds(); 
  } 
   
  public String getDescriptor() { 
    return m_descriptor; 
  } 
   
  public boolean equals(Object obj) { 
    if (obj == this) { 
      return true; 
    } else if (obj instanceof GenericTemplate) { 
      return m_descriptor.equals(((GenericTemplate)obj).m_descriptor); 
    } else { 
      return false; 
    } 
  } 
   
  public int hashCode() { 
    return m_descriptor.hashCode(); 
  } 
   
  /** 
   * Get description for parameterized type with type substitutions. 
   * 
   * @param sig signature including all type substitutions 
   * @param types actual types used for instance (values may be 
   * <code>null</code> if no substitution defined) 
   * @param tdir type directory 
   * @return substituted type description 
   */ 
  public TypeDescription getParameterized(String sig, TypeDescription[] types) { 
    return new ParameterizedClassDescription(sig, types); 
  } 
   
  /** 
   * Visitor for generating the description information for a generic class. 
   */ 
  public class DescriptionBuilderVisitor extends EmptyVisitor 
  { 
    private final TypeDirectory m_typeDirectory; 
    private ArrayList<FieldDescription> m_fields; 
    private ArrayList<String> m_typeParameters; 
    private ArrayList<TypeDescription> m_upperBounds; 
     
    private DescriptionBuilderVisitor(TypeDirectory dir) { 
      m_typeDirectory = dir; 
      m_fields = new ArrayList<FieldDescription>(); 
      m_typeParameters = new ArrayList<String>(); 
      m_upperBounds = new ArrayList<TypeDescription>(); 
    } 
     
    public void visit(int version, int access, String name, String sig, 
      String sname, String[] inames) { 
      if (sig != null) { 
        new SignatureReader(sig).accept(new ClassSignatureVisitor()); 
      } 
      super.visit(version, access, name, sig, sname, inames); 
    } 
 
    public FieldVisitor visitField(int access, String name, String desc, 
      String sig, Object value) { 
      TypeDescription type = null; 
      if (sig == null) { 
        type = m_typeDirectory.getTypeInstance(desc); 
      } 
      m_fields.add(new FieldDescription(name, sig, type)); 
      return super.visitField(access, name, desc, sig, value); 
    } 
     
    private FieldDescription[] getFields() { 
      return m_fields.toArray(new FieldDescription[m_fields.size()]); 
    } 
     
    private String[] getTypeParameters() { 
      return m_typeParameters.toArray(new String[m_typeParameters.size()]); 
    } 
     
    private TypeDescription[] getUpperBounds() { 
      return m_upperBounds.toArray(new TypeDescription[m_upperBounds.size()]); 
    } 
     
    private class ClassSignatureVisitor extends EmptySignatureVisitor 
    { 
      private boolean m_isBounded; 
       
      public void visitFormalTypeParameter(String name) { 
        m_typeParameters.add(name); 
        m_upperBounds.add(m_typeDirectory.getTypeInstance("Ljava/lang/Object;")); 
      } 
 
      public SignatureVisitor visitClassBound() { 
        return new EmptySignatureVisitor() { 
          public void visitClassType(String name) { 
            m_upperBounds.set(m_upperBounds.size()-1, 
              m_typeDirectory.getTypeInstance("L" + name + ';')); 
            m_isBounded = true; 
          } 
        }; 
      } 
 
      public SignatureVisitor visitInterfaceBound() { 
        return new EmptySignatureVisitor() { 
          public void visitClassType(String name) { 
            if (!m_isBounded) { 
              m_upperBounds.set(m_upperBounds.size()-1, 
                m_typeDirectory.getTypeInstance(name)); 
            } 
          } 
        }; 
      } 
    } 
  } 
   
  /** 
   * Parameterized type description, with actual types substituted for all 
   * type parameters. The actual substitution of type parameters into the 
   * fields is done at the time of first use to avoid issues with 
   * recursive class references. 
   */ 
  private class ParameterizedClassDescription extends TypeDescription 
  { 
    private final TypeDescription[] m_types; 
    private final String m_name; 
    private FieldDescription[] m_fields; 
     
    /** 
     * Constructor. This creates the description for a parameterized type 
     * with type substitutions from the generic instance. This has to add 
     * itself to the type directory during construction to handle 
     * recursive references. 
     * 
     * @param sig signature including all type substitutions 
     * @param types actual types used for instance (values may be 
     * <code>null</code> if no substitution defined) 
     * @return substituted type description 
     */ 
    public ParameterizedClassDescription(String sig, TypeDescription[] types) { 
      super(sig); 
      StringBuffer buff = new StringBuffer(); 
      buff.append(m_baseName); 
      buff.append('<'); 
      for (int i = 0; i < types.length; i++) { 
        if (i > 0) { 
          buff.append(','); 
        } 
        if (types[i] == null) { 
          buff.append('*'); 
        } else { 
          buff.append(types[i]); 
        } 
      } 
      buff.append('>'); 
      m_name = buff.toString(); 
      m_types = types; 
      m_typeDirectory.addType(this); 
    } 
     
    public FieldDescription[] getFields() { 
      if (m_fields == null) { 
         
        // make sure the number of parameter types is correct 
        if (m_typeParameters.length != m_types.length) { 
          throw new IllegalArgumentException("Wrong number of 
           parameter types"); 
        } 
         
        // build substitution map for type parameters 
        HashMap<String,TypeDescription> tmap = 
          new HashMap<String,TypeDescription>(); 
        for (int i = 0; i < m_typeParameters.length; i++) { 
          TypeDescription type = m_types[i]; 
          if (type == null) { 
            type = m_upperBounds[i]; 
          } 
          tmap.put(m_typeParameters[i], type); 
        } 
         
        // handle the actual type substitutions 
        m_fields = new FieldDescription[m_genericFields.length]; 
        for (int i = 0; i < m_genericFields.length; i++) { 
          FieldDescription field = m_genericFields[i]; 
          if (field.getType() == null) { 
            String sig = field.getSignature(); 
            TypeDescription desc = 
             m_typeDirectory.getMappedSignatureInstance(sig, tmap); 
            m_fields[i] = new FieldDescription(field.getName(), sig, desc); 
          } else { 
            m_fields[i] = field; 
          } 
        } 
      } 
      return m_fields; 
    } 
     
    public String toString() { 
      return m_name; 
    } 
  } 
} 

上一页  1 2 3 4 5 6 7 8  下一页

Tags:Classworking 工具箱 分析

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接