Package org.jboss.lang

Source Code of org.jboss.lang.GenericsHelper

/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.lang;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.ClassFile;
import javassist.bytecode.FieldInfo;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.SignatureAttribute;

import org.jboss.javassist.JavassistUtil;
import org.jboss.lang.reflect.GenericArrayTypeImpl;
import org.jboss.lang.reflect.ParameterizedTypeImpl;
import org.jboss.lang.reflect.Type;
import org.jboss.lang.reflect.TypeVariable;
import org.jboss.lang.reflect.TypeVariableImpl;
import org.jboss.lang.reflect.WildcardTypeImpl;

/**
*
*
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
* @version $Revision: 1.1 $
*/
public class GenericsHelper
{
   final static Type[] NO_TYPES = new Type[0];
   final static TypeVariable[] NO_TYPE_VARIABLES = new TypeVariable[0];
  
   public static TypeVariable[] getTypeParameters(Class clazz)
   {
      SignatureAttribute.ClassSignature sig = getClassSignature(clazz);
      if (sig != null)
      {
         SignatureAttribute.TypeParameter[] params = sig.getParameters();
         TypeVariable[] tparams = new TypeVariable[params.length];
         for (int i = 0 ; i < params.length ; i++)
         {
            Object [] bounds = null;
            try {
               bounds = getBounds(params[i].getClassBound(), params[i].getInterfaceBound());
            } catch (ClassNotFoundException cnfe) {
               throw new RuntimeException(cnfe);
            }
            tparams[i] = new TypeVariableImpl(bounds, clazz, params[i].getName());
         }
         return tparams;
      }
      return NO_TYPE_VARIABLES;
   }
  
   /**
    * Convert the Type parameter bounds into appropriate Class objects.
    * @param classBound
    * @param interfaceBounds
    * @return
    * @throws ClassNotFoundException
    */
   private static Object [] getBounds(SignatureAttribute.ObjectType classBound, SignatureAttribute.ObjectType[] interfaceBounds) throws ClassNotFoundException {
      Object [] bounds = null;
      // If there is no super type specified, default to object
      if (classBound == null && (interfaceBounds == null || interfaceBounds.length == 0))
      {
         bounds = new Object[]{Object.class};
      }
      // If there are no interfaces, use only the class bound
      else if (interfaceBounds == null || interfaceBounds.length == 0) {
         Class superClass = Class.forName(classBound.toString());
         bounds =  new Object[]{superClass};
      }
      // If there is no superclass, use the interfaces
      else if (classBound == null) {
         bounds = new Object[interfaceBounds.length];
         for (int i=0; i<interfaceBounds.length; ++i) {
            bounds[i] = Class.forName(interfaceBounds[i].toString());
         }
      }
      // Use both the superclass and interfaces
      else {
         bounds = new Object[interfaceBounds.length + 1];
         bounds[0] = Class.forName(classBound.toString());
         for (int i=0; i<interfaceBounds.length; ++i) {
            bounds[i+1] = Class.forName(interfaceBounds[i].toString());
         }
      }
      return bounds;

   }
  
   public static Object[] getGenericInterfaces(Class clazz)
   {
      try
      {
         SignatureAttribute.ClassSignature sig = getClassSignature(clazz);
         if (sig != null)
         {
            SignatureAttribute.ClassType[] ifs = sig.getInterfaces();
            Object[] inters = new Object[ifs.length];
            for (int i = 0 ; i < ifs.length ; i++)
            {
               inters[i] = createType(Class.forName(ifs[i].getName()), ifs[i]);
            }
            return inters;
         }
        
         return clazz.getInterfaces();
      }
      catch (ClassNotFoundException e)
      {
         // AutoGenerated
         throw new RuntimeException(e);
      }
   }
  
   public static Object getGenericSuperclass(Class clazz)
   {
      if (!clazz.isInterface())
      {
         SignatureAttribute.ClassSignature sig = getClassSignature(clazz);
         if (sig != null)
         {
            SignatureAttribute.ClassType supa = sig.getSuperClass();
            if (supa != null)
            {
               return createType(clazz.getSuperclass(), supa);
            }
         }
      }     
      return clazz.getSuperclass();
   }
  
   public static TypeVariable[] getTypeParameters(Constructor ctor)
   {
      SignatureAttribute.MethodSignature methodSig = getMethodSignature(ctor);
      if (methodSig != null)
      {
         SignatureAttribute.TypeParameter[] params = methodSig.getTypeParameters();
         TypeVariable[] tparams = new TypeVariable[params.length];
         for (int i = 0 ; i < params.length ; i++)
         {
            Object [] bounds = null;
            try {
               bounds = getBounds(params[i].getClassBound(), params[i].getInterfaceBound());
            } catch (ClassNotFoundException cnfe) {
               throw new RuntimeException(cnfe);
            }
            tparams[i] = new TypeVariableImpl(bounds, params[i].getClass(), params[i].getName());
         }
         return tparams;
      }
      return NO_TYPE_VARIABLES;
   }
  
   public static Object[] getGenericParameterTypes(Constructor c)
   {
      SignatureAttribute.MethodSignature methodSig = getMethodSignature(c);
      return getGenericParameterTypes(c.getDeclaringClass(), c.getParameterTypes(), methodSig);
   }
  
   public static Object[] getGenericExceptionTypes(Constructor c)
   {
      SignatureAttribute.MethodSignature methodSig = getMethodSignature(c);
      return getGenericExceptionTypes(c.getExceptionTypes(), methodSig);
   }

   public static String toGenericString(Constructor c)
   {
      SignatureAttribute.MethodSignature methodSig = getMethodSignature(c);
      JBossStringBuilder buf = new JBossStringBuilder();
      appendModifiers(buf, c);
      appendTypeParameters(buf, getTypeParameters(c));
      buf.append(c.getDeclaringClass().getName());
      appendGenericParameterTypes(buf, getGenericParameterTypes(c.getDeclaringClass(), c.getParameterTypes(), methodSig));
      if (c.getExceptionTypes().length > 0)
      {
         buf.append(" throws ");
         appendGenericExceptionTypes(buf, getGenericExceptionTypes(c.getExceptionTypes(), methodSig));
      }
     
      return buf.toString();
   }
  
   public static TypeVariable[] getTypeParameters(Method meth)
   {
      SignatureAttribute.MethodSignature methodSig = getMethodSignature(meth);
      if (methodSig != null)
      {
         SignatureAttribute.TypeParameter[] params = methodSig.getTypeParameters();
         TypeVariable[] tparams = new TypeVariable[params.length];
         for (int i = 0 ; i < params.length ; i++)
         {
            Object [] bounds = null;
            try {
               bounds = getBounds(params[i].getClassBound(), params[i].getInterfaceBound());
            } catch (ClassNotFoundException cnfe) {
               throw new RuntimeException(cnfe);
            }
            tparams[i] = new TypeVariableImpl(bounds, params[i].getClass(), params[i].getName());
         }
         return tparams;
      }
      return NO_TYPE_VARIABLES;
   }
     
   public static Object getGenericReturnType(Method m)
   {
      SignatureAttribute.MethodSignature methodSig = getMethodSignature(m);
      return getGenericReturnType(m, methodSig);
   }
  
   public static Object[] getGenericParameterTypes(Method m)
   {
      SignatureAttribute.MethodSignature methodSig = getMethodSignature(m);
      return getGenericParameterTypes(m.getDeclaringClass(), m.getParameterTypes(), methodSig);
   }
  
   public static Object[] getGenericExceptionTypes(Method m)
   {
      SignatureAttribute.MethodSignature methodSig = getMethodSignature(m);
      return getGenericExceptionTypes(m.getExceptionTypes(), methodSig);
   }

   public static String toGenericString(Method m)
   {
      SignatureAttribute.MethodSignature methodSig = getMethodSignature(m);
      JBossStringBuilder buf = new JBossStringBuilder();
      appendModifiers(buf, m);
      if (m.getTypeParameters().length > 0) {
         appendTypeParameters(buf, getTypeParameters(m));
      }
     
      buf.append(formatTypeName(getGenericReturnType(m, methodSig)));
      buf.append(" ");
      buf.append(m.getDeclaringClass().getName());
      buf.append(".");
      buf.append(m.getName());
      appendGenericParameterTypes(buf, getGenericParameterTypes(m.getDeclaringClass(), m.getParameterTypes(), methodSig));
      if (m.getExceptionTypes().length > 0)
      {
         buf.append(" throws ");
         appendGenericExceptionTypes(buf, getGenericExceptionTypes(m.getExceptionTypes(), methodSig));
      }
     
      return buf.toString();
   }

   public static Object getGenericType(Field f)
   {
      CtField fld = JavassistUtil.getCtField(f);
      FieldInfo info = fld.getFieldInfo2();
      SignatureAttribute sig = (SignatureAttribute)info.getAttribute(SignatureAttribute.tag);
      if (sig != null)
      {
         try
         {
            SignatureAttribute.ObjectType type = SignatureAttribute.toFieldSignature(sig.getSignature());
            return createType(f.getType(), type);
         }
         catch (BadBytecode e)
         {
            throw new RuntimeException(e);
         }
      }
     
      return f.getType();
   }
  
   public static String toGenericString(Field f)
   {
      JBossStringBuilder buf = new JBossStringBuilder();
      appendModifiers(buf, f);
      Object type = getGenericType(f);
      buf.append(formatTypeName(type));
      buf.append(" ");
      buf.append(f.getDeclaringClass().getName());
      buf.append(".");
      buf.append(f.getName());
      return buf.toString();
   }

   public static Object[] getTypeParameters(Object o)
   {
      if (o instanceof Class)
      {
         return getTypeParameters((Class)o);
      }
      else if (o instanceof Method)
      {
         return getTypeParameters((Method)o);
      }
      else if (o instanceof Constructor)
      {
         return getTypeParameters((Constructor)o);
      }
     
      if (o == null)
      {
         throw new IllegalArgumentException("Null object passed in");
      }
      throw new IllegalArgumentException("Object of type " + o.getClass().getName() + " does not implement GenericDeclaration");
   }
   private static String formatTypeName(Object type)
   {
      if (type instanceof Class)
      {
         return ((Class)type).getName();
      }
      else
      {
         return type.toString();
      }
   }
   private static void appendModifiers(JBossStringBuilder buf, Member m)
   {
      int length = buf.length();
      buf.append(Modifier.toString(m.getModifiers()));
      if (buf.length() > length)
      {
         buf.append(" ");
      }
   }
   private static void appendTypeParameters(JBossStringBuilder buf, TypeVariable[] tvs)
   {
      if (tvs.length == 0)
      {
         return;
      }
      buf.append("<");
      for (int i = 0 ; i < tvs.length ; i++)
      {
         if (i > 0)
         {
            buf.append(",");
         }
         buf.append(tvs[i]);
      }
     
      buf.append("> ");
   }
  
   private static void appendGenericParameterTypes(JBossStringBuilder buf, Object[] params)
   {
      buf.append("(");
     
      for (int i = 0 ; i < params.length ; i++)
      {
         if (i > 0)
         {
            buf.append(", ");
         }
         buf.append(formatTypeName(params[i]));
      }
     
      buf.append(")");
   }
  
   private static void appendGenericExceptionTypes(JBossStringBuilder buf, Object[] exceptions)
   {
      for (int i = 0 ; i < exceptions.length ; i++)
      {
         if (i > 0)
         {
            buf.append(", ");
         }
         buf.append(exceptions[i].toString());
      }
   }
  
   /**
    * Create the type impl object.
    * @param targetClass
    * @param type
    * @return an object representing the type
    * TODO: this method should probably be re-organized to make it a bit simpler.
    */
   private static Object createType(Class targetClass, SignatureAttribute.Type type)
   {
      try
      {
         if (type instanceof SignatureAttribute.ClassType)
         {           
            SignatureAttribute.TypeArgument[] args = ((SignatureAttribute.ClassType)type).getTypeArguments();
           
            if (args == null)
            {
               return targetClass;
            }
            else
            {
               Object ownerType = null;
               Object[] typeArgs = NO_TYPES;
               if (type instanceof SignatureAttribute.NestedClassType)
               {
                  SignatureAttribute.NestedClassType nestedType = (SignatureAttribute.NestedClassType)type;
                  ownerType = createType(targetClass.getDeclaringClass(), nestedType.getDeclaringClass()) ;
               }
               if (args.length > 0)
               {
                  typeArgs = new Object[args.length];
                  for (int i = 0; i < args.length; i++)
                  {
                     if (args[i].getType() instanceof SignatureAttribute.NestedClassType)
                     {
                        SignatureAttribute.NestedClassType nestedType = (SignatureAttribute.NestedClassType) args[i].getType();
                        Class nestedClass = Class.forName(nestedType.getDeclaringClass().getName() + "$" + nestedType.getName());
                        typeArgs[i] = createType(nestedClass, args[i].getType());
                     }
                     else if (args[i].isWildcard())
                     {
                        Object bound = null;
                        if (args[i].getType() != null)
                        {
                           if (args[i].getType() instanceof SignatureAttribute.ClassType)
                           {
                              bound = Class.forName(((SignatureAttribute.ClassType) args[i].getType()).getName());
                           }
                           else if (args[i].getType() instanceof SignatureAttribute.TypeVariable)
                           {
                              SignatureAttribute.TypeVariable tv = (SignatureAttribute.TypeVariable) args[i].getType();
                              Object[] bounds = new Object[] {Object.class};
                              bound = new TypeVariableImpl(bounds, targetClass, tv.getName());                          
                           }
                        }
                        typeArgs[i] = new WildcardTypeImpl(bound, args[i].getKind());
                     }
                     else if (args[i].getType() instanceof SignatureAttribute.ClassType)
                     {
                        typeArgs[i] = Class.forName(((SignatureAttribute.ClassType) args[i].getType()).getName());
                     }
                     else if (args[i].getType() instanceof SignatureAttribute.TypeVariable)
                     {
                        SignatureAttribute.TypeVariable tv = (SignatureAttribute.TypeVariable) args[i].getType();
                        Object[] bounds = new Object[] {Object.class};
                        typeArgs[i] = new TypeVariableImpl(bounds, targetClass, tv.getName());
                     }
                     else
                     {
                        throw new RuntimeException("Invalid argument type " + args[i].getType());
                     }
                  }
               }
              
               return new ParameterizedTypeImpl(type.toString(), targetClass, ownerType, typeArgs);
            }
         }
         else if (type instanceof SignatureAttribute.TypeVariable)
         {
            SignatureAttribute.TypeVariable tv = (SignatureAttribute.TypeVariable)type;
            Object [] bounds = new Object[]{Object.class};
            return new TypeVariableImpl(bounds, targetClass, tv.getName());
         }
         else if (type instanceof SignatureAttribute.ArrayType)
         {
            SignatureAttribute.ArrayType arrayType = (SignatureAttribute.ArrayType)type;
            return new GenericArrayTypeImpl(arrayType.getComponentType(), arrayType.getDimension(), arrayType.toString());
         }
         else if (type instanceof SignatureAttribute.BaseType)
         {
            SignatureAttribute.BaseType baseType = (SignatureAttribute.BaseType)type;
            return getPrimitiveType(baseType.getDescriptor());
         }
      }
      catch (ClassNotFoundException e)
      {
         throw new RuntimeException(e);
      }
     
      throw new RuntimeException("Unknown type " + type.getClass());
   }
  
   private static Class getPrimitiveType(char typeDescriptor) {
        
        if (typeDescriptor == 'V')
        {
            return void.class;
        }
        else if (typeDescriptor == 'I')
        {
            return int.class;
        }
        else if (typeDescriptor == 'B')
        {
            return byte.class;
        }
        else if (typeDescriptor == 'J')
        {
            return long.class;
        }
        else if (typeDescriptor == 'D')
        {
            return double.class;
        }
        else if (typeDescriptor == 'F')
        {
            return float.class;
        }
        else if (typeDescriptor == 'C')
        {
            return char.class;
        }
        else if (typeDescriptor == 'S')
        {
            return short.class;
        }
        else if (typeDescriptor == 'Z')
        {
            return boolean.class;
        }
        throw new RuntimeException("bad descriptor: " + typeDescriptor);

   }
  
  
  
   private static Class getRawClass(SignatureAttribute.ClassType type)
   {
      try
      {
         String name = ((SignatureAttribute.ClassType)type).getName();
         return Class.forName(name);
      }
      catch (ClassNotFoundException e)
      {
         throw new RuntimeException(e);
      }
   }

   private static SignatureAttribute.ClassSignature getClassSignature(Class clazz)
   {
      CtClass ctclazz = JavassistUtil.getCtClass(clazz);
      ClassFile cf = ctclazz.getClassFile2();
      SignatureAttribute sig = (SignatureAttribute)cf.getAttribute(SignatureAttribute.tag);
      if (sig != null)
      {
         try
         {
            SignatureAttribute.ClassSignature type = SignatureAttribute.toClassSignature(sig.getSignature());
            return type;
         }
         catch (BadBytecode e)
         {
            throw new RuntimeException(e);
         }
      }
      return null;
   }
  
   private static SignatureAttribute.MethodSignature getMethodSignature(Method m)
   {
      CtMethod mtd = JavassistUtil.getCtMethod(m);
      MethodInfo info = mtd.getMethodInfo2();
      return getMethodSignature(info);
   }
  
   private static SignatureAttribute.MethodSignature getMethodSignature(Constructor c)
   {
      CtConstructor con = JavassistUtil.getCtConstructor(c);
      MethodInfo info = con.getMethodInfo2();
      return getMethodSignature(info);
   }
  
   private static SignatureAttribute.MethodSignature getMethodSignature(MethodInfo info)
   {
      SignatureAttribute sig = (SignatureAttribute)info.getAttribute(SignatureAttribute.tag);
      if (sig != null)
      {
         try
         {
            SignatureAttribute.MethodSignature type = SignatureAttribute.toMethodSignature(sig.getSignature());
            return type;
         }
         catch (BadBytecode e)
         {
            throw new RuntimeException(e);
         }
      }
      return null;
   }
  
   private static Object getGenericReturnType(Method m, SignatureAttribute.MethodSignature methodSig)
   {
      if (methodSig != null)
      {
         return createType(m.getReturnType(), methodSig.getReturnType());
      }
      else
      {
         return m.getReturnType();
      }
   }
  
   private static Object[] getGenericParameterTypes(Class targetClass, Class[] parameterTypes, SignatureAttribute.MethodSignature methodSig)
   {
      if (methodSig != null)
      {
         SignatureAttribute.Type[] types = methodSig.getParameterTypes();
         Object[] paramTypes = new Object[types.length];
        
         for (int i = 0 ; i < types.length ; i++)
         {
            paramTypes[i] = createType(parameterTypes[i], types[i]);
         }
        
         return paramTypes;
      }
      return parameterTypes;
   }
  
   private static Object[] getGenericExceptionTypes(Class[] exceptionTypes, SignatureAttribute.MethodSignature methodSig)
   {
      if (methodSig != null) {
         SignatureAttribute.Type[] types = methodSig.getExceptionTypes();
         Object[] exTypes = new Object[types.length];
        
         for (int i = 0 ; i < types.length ; i++)
         {
            // Here it is assumed that exceptionTypes and types are in the same order
            exTypes[i] = createType(exceptionTypes[i], types[i]);
         }
        
         return exTypes;
      }
      return exceptionTypes;
   }

}
TOP

Related Classes of org.jboss.lang.GenericsHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.