[jboss-cvs] container/src/main/org/jboss/annotation/factory ...

Kabir Khan kkhan at jboss.com
Tue Jul 18 07:23:50 EDT 2006


  User: kkhan   
  Date: 06/07/18 07:23:50

  Added:       src/main/org/jboss/annotation/factory     
                        AnnotationProxy.java
                        AnnotationValidationException.java
                        SimpleAnnotationValidator.java
                        AnnotationValidator.java AnnotationCreator.java
  Log:
  Move annotation creator into container from aop module
  
  Use jboss retro to create a JDK 1.4 dist and test under JDK 1,4.
  
  Revision  Changes    Path
  1.1      date: 2006/07/18 11:23:50;  author: kkhan;  state: Exp;container/src/main/org/jboss/annotation/factory/AnnotationProxy.java
  
  Index: AnnotationProxy.java
  ===================================================================
  /*
    * JBoss, Home of Professional Open Source
    * Copyright 2005, JBoss Inc., and individual contributors as indicated
    * by the @authors tag. See the copyright.txt 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.annotation.factory;
  
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  import java.lang.reflect.Proxy;
  import java.util.Map;
  
  /**
   * Comment
   *
   * @author <a href="mailto:bill at jboss.org">Bill Burke</a>
   * @author <a href="mailto:kabir.khan at jboss.org">Kabir Khan</a>
   * @version $Revision: 1.1 $
   */
  public class AnnotationProxy implements InvocationHandler
  {
     Map map;
     Class annotationType;
  
     public AnnotationProxy(Class annotationType, Map valueMap)
     {
        this.annotationType = annotationType;
        map = valueMap;
     }
  
     public Object invoke(Object proxy, Method method, Object[] args)
             throws Throwable
     {
        if (method.getName().equals("equals"))
        {
           return doEquals(proxy, args[0]);
        }
        else if (method.getName().equals("hashCode"))
        {
           return doHashCode();
        }
        else if (method.getName().equals("toString"))
        {
           return map.toString();
        }
        else if (method.getName().equals("annotationType"))
        {
           return annotationType;
        }
        
        /*
        Object obj = map.get(method.getName());
        if (!method.getReturnType().equals(obj.getClass()))
        {
           System.err.println("***** " + method.toString() + " has bad return type: " + obj.getClass().getName());
        }
        return obj;
        */
        return map.get(method.getName());
     }
  
     public Object getValue(String name)
     {
        return map.get(name);
     }
     
     private Object doEquals(Object proxy, Object obj)
     {
        if (obj == proxy) return Boolean.TRUE;
        if (obj == null) return Boolean.FALSE;
  
        Class[] intfs = proxy.getClass().getInterfaces();
        if (!intfs[0].isAssignableFrom(obj.getClass()))
        {
           return Boolean.FALSE;
        }
        try
        {
           Proxy.getInvocationHandler(obj);
        }
        catch (Exception ex)
        {
           return Boolean.FALSE;
        }
        return Boolean.TRUE;
     }
  
     private Object doHashCode()
     {
        return new Integer(map.hashCode());
     }
  
     public static Object createProxy(Map map, Class annotation) throws Exception
     {
        AnnotationProxy proxyHandler = new AnnotationProxy(annotation, map);
        return java.lang.reflect.Proxy.newProxyInstance(annotation.getClassLoader(), new Class[]{annotation}, proxyHandler);
     }
  }
  
  
  
  1.1      date: 2006/07/18 11:23:50;  author: kkhan;  state: Exp;container/src/main/org/jboss/annotation/factory/AnnotationValidationException.java
  
  Index: AnnotationValidationException.java
  ===================================================================
  /*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt 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.annotation.factory;
  
  /**
   * 
   * @author <a href="kabir.khan at jboss.com">Kabir Khan</a>
   * @version $Revision: 1.1 $
   */
  public class AnnotationValidationException extends RuntimeException
  {
     private static final long serialVersionUID = 2710034018990217179L;
  
     public AnnotationValidationException(String msg)
     {
        super(msg);
     }
     
  }
  
  
  
  1.1      date: 2006/07/18 11:23:50;  author: kkhan;  state: Exp;container/src/main/org/jboss/annotation/factory/SimpleAnnotationValidator.java
  
  Index: SimpleAnnotationValidator.java
  ===================================================================
  /*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt 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.annotation.factory;
  
  import java.lang.reflect.Method;
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import java.util.ArrayList;
  import java.util.Map;
  
  /**
   * Validates if all attributes have been filled in for an annotation. 
   * Makes no attempt to read default values
   * 
   * @author <a href="kabir.khan at jboss.com">Kabir Khan</a>
   * @version $Revision: 1.1 $
   */
  public class SimpleAnnotationValidator implements AnnotationValidator
  {
  
     public void validate(Map map, Class annotation)
     {
        ArrayList notAssignedAttributes = null;
        Method[] methods = getDeclaredMethods(annotation);
        for (int i = 0 ; i < methods.length ; i++)
        {
           if (map.get(methods[i].getName()) == null)
           {
              if (notAssignedAttributes == null)
              {
                 notAssignedAttributes = new ArrayList();
              }
              notAssignedAttributes.add(methods[i].getName());
           }
        }
  
        if (notAssignedAttributes != null)
        {
           throw new AnnotationValidationException("Unable to fill in default attributes for " + annotation + " " + notAssignedAttributes);
        }
     }
     
     private Method[] getDeclaredMethods(final Class clazz)
     {
        return (Method[])AccessController.doPrivileged(new PrivilegedAction() {
           public Object run() 
           {
              return clazz.getDeclaredMethods();
           };  
        });
     }
  
  }
  
  
  
  1.1      date: 2006/07/18 11:23:50;  author: kkhan;  state: Exp;container/src/main/org/jboss/annotation/factory/AnnotationValidator.java
  
  Index: AnnotationValidator.java
  ===================================================================
  /*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt 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.annotation.factory;
  
  import java.util.Map;
  
  /**
   * Validates that all annotations created for a proxy have been filled in.
   * Depending on the underlying implementation fills in missing attributes with default values.
   * 
   * @author <a href="kabir.khan at jboss.com">Kabir Khan</a>
   * @version $Revision: 1.1 $
   */
  public interface AnnotationValidator
  {
     /**
      * Validates that all annotations created for a proxy have been filled in.
      * Depending on the underlying implementation fills in missing attributes with default values.
      * @param map The annotation attribute values
      * @param annotation The annotation type
      * @throws AnnotationValidationException if some attributes were not filled in and no default value exists for that attribute
      */
     void validate(Map map, Class annotation);
  }
  
  
  
  1.1      date: 2006/07/18 11:23:50;  author: kkhan;  state: Exp;container/src/main/org/jboss/annotation/factory/AnnotationCreator.java
  
  Index: AnnotationCreator.java
  ===================================================================
  /*
    * JBoss, Home of Professional Open Source
    * Copyright 2005, JBoss Inc., and individual contributors as indicated
    * by the @authors tag. See the copyright.txt 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.annotation.factory;
  
  import org.jboss.annotation.factory.ast.ASTAnnotation;
  import org.jboss.annotation.factory.ast.ASTChar;
  import org.jboss.annotation.factory.ast.ASTIdentifier;
  import org.jboss.annotation.factory.ast.ASTMemberValueArrayInitializer;
  import org.jboss.annotation.factory.ast.ASTMemberValuePair;
  import org.jboss.annotation.factory.ast.ASTMemberValuePairs;
  import org.jboss.annotation.factory.ast.ASTSingleMemberValue;
  import org.jboss.annotation.factory.ast.ASTStart;
  import org.jboss.annotation.factory.ast.ASTString;
  import org.jboss.annotation.factory.ast.AnnotationParser;
  import org.jboss.annotation.factory.ast.AnnotationParserVisitor;
  import org.jboss.annotation.factory.ast.Node;
  import org.jboss.annotation.factory.ast.SimpleNode;
  import org.jboss.annotation.factory.javassist.DefaultValueAnnotationValidator;
  
  import java.io.StringReader;
  import java.lang.annotation.Annotation;
  import java.lang.reflect.Array;
  import java.lang.reflect.Field;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.security.AccessController;
  import java.security.PrivilegedActionException;
  import java.security.PrivilegedExceptionAction;
  import java.util.HashMap;
  
  /**
   * Comment
   *
   * @author <a href="mailto:bill at jboss.org">Bill Burke</a>
   * @author <a href="mailto:kabir.khan at jboss.org">Kabir Khan</a>
   * @version $Revision: 1.1 $
   */
  public class AnnotationCreator implements AnnotationParserVisitor
  {
     private Class annotation;
     private Class type;
     public Object typeValue;
     
     static final AnnotationValidator defaultAnnotationReader;
     static
     {
        boolean haveJavassist = false;
        try
        {
           Class clazz = Class.forName("javassist.CtClass");
           haveJavassist = true;
        }
        catch(ClassNotFoundException ignore)
        {
        }
        
        if (haveJavassist)
        {
           defaultAnnotationReader = new DefaultValueAnnotationValidator();
        }
        else
        {
           defaultAnnotationReader = new SimpleAnnotationValidator();
        }
        
     }
  
     public AnnotationCreator(Class annotation, Class type)
     {
        this.type = type;
        this.annotation = annotation;
     }
  
  
     public Object visit(ASTMemberValuePairs node, Object data)
     {
        node.childrenAccept(this, data);
        return null;
     }
  
     public Object visit(ASTMemberValuePair node, Object data)
     {
        String name = node.getIdentifier().getValue();
        node.getValue().jjtAccept(this, name);
        return data;
     }
  
     public Object visit(ASTSingleMemberValue node, Object data)
     {
        node.getValue().jjtAccept(this, "value");
        return data;
     }
  
     public Object visit(ASTIdentifier node, Object data)
     {
        try
        {
           if (type.equals(Class.class))
           {
              String classname = node.getValue();
              if (classname.endsWith(".class"))
              {
                 classname = classname.substring(0, classname.indexOf(".class"));
              }
              if (classname.equals("void"))
              {
                 typeValue = void.class;
              }
              else if (classname.equals("int"))
              {
                 typeValue = int.class;
              }
              else if (classname.equals("byte"))
              {
                 typeValue = byte.class;
              }
              else if (classname.equals("long"))
              {
                 typeValue = long.class;
              }
              else if (classname.equals("double"))
              {
                 typeValue = double.class;
              }
              else if (classname.equals("float"))
              {
                 typeValue = float.class;
              }
              else if (classname.equals("char"))
              {
                 typeValue = char.class;
              }
              else if (classname.equals("short"))
              {
                 typeValue = short.class;
              }
              else if (classname.equals("boolean"))
              {
                 typeValue = boolean.class;
              }
              else
              {
                 typeValue = Thread.currentThread().getContextClassLoader().loadClass(classname);
              }
           }
           else if (type.isPrimitive())
           {
              if (type.equals(boolean.class))
              {
                 typeValue = new Boolean(node.getValue());
              }
              else if (type.equals(short.class))
              {
                 typeValue = Short.valueOf(node.getValue());
              }
              else if (type.equals(float.class))
              {
                 typeValue = Float.valueOf(node.getValue());
              }
              else if (type.equals(double.class))
              {
                 typeValue = Double.valueOf(node.getValue());
              }
              else if (type.equals(long.class))
              {
                 typeValue = Long.valueOf(node.getValue());
              }
              else if (type.equals(byte.class))
              {
                 typeValue = new Byte(node.getValue());
              }
              else if (type.equals(int.class))
              {
                 typeValue = new Integer(node.getValue());
              }
           }
           else // its an enum
           {
              int index = node.getValue().lastIndexOf('.');
              if (index == -1) throw new RuntimeException("Enum must be fully qualified: " + node.getValue());
              String className = node.getValue().substring(0, index);
              String en = node.getValue().substring(index + 1);
              Class enumClass = Thread.currentThread().getContextClassLoader().loadClass(className);
  
              if (enumClass.getSuperclass().getName().equals("java.lang.Enum"))
              {
                 Method valueOf = null;
                 Method[] methods = enumClass.getSuperclass().getMethods();
                 for (int i = 0; i < methods.length; i++)
                 {
                    if (methods[i].getName().equals("valueOf"))
                    {
                       valueOf = methods[i];
                       break;
                    }
                 }
                 Object[] args = {enumClass, en};
                 typeValue = valueOf.invoke(null, args);
              }
              else
              {
                 Field field = enumClass.getField(en);
                 typeValue = field.get(null);
              }
           }
        }
        catch (ClassNotFoundException e)
        {
           throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
           throw new RuntimeException(e);
        }
        catch (InvocationTargetException e)
        {
           throw new RuntimeException(e);
        }
        catch (NoSuchFieldException e)
        {
           throw new RuntimeException(e);
        }
        return null;
     }
  
     public Object visit(ASTString node, Object data)
     {
        if (!type.equals(String.class)) throw new RuntimeException(annotation.getName() + "." + data + " is not an String");
        typeValue = node.getValue();
        return null;
     }
  
     public Object visit(ASTChar node, Object data)
     {
        if (!type.equals(char.class)) throw new RuntimeException(annotation.getName() + "." + data + " is not an char");
        typeValue = new Character(node.getValue());
        return null;
     }
  
  
     public Object visit(ASTMemberValueArrayInitializer node, Object data)
     {
        if (!type.isArray()) throw new RuntimeException(annotation.getName() + "." + data + " is not an array");
        Class baseType = type.getComponentType();
        int size = node.jjtGetNumChildren();
        typeValue = Array.newInstance(baseType, size);
  
        for (int i = 0; i < size; i++)
        {
           AnnotationCreator creator = new AnnotationCreator(annotation, baseType);
           node.jjtGetChild(i).jjtAccept(creator, null);
           Array.set(typeValue, i, creator.typeValue);
        }
        return null;
     }
  
     public Object visit(ASTAnnotation node, Object data)
     {
        try
        {
           Class subAnnotation = Thread.currentThread().getContextClassLoader().loadClass(node.getIdentifier());
           typeValue = createAnnotation(node, subAnnotation);
        }
        catch (Exception e)
        {
           throw new RuntimeException(e);
        }
        return null;
     }
  
     // Unneeded
  
     public Object visit(SimpleNode node, Object data)
     {
        return null;
     }
  
     public Object visit(ASTStart node, Object data)
     {
        return null;
     }
  
     private static Class getMemberType(Class annotation, String member)
     {
        Method[] methods = annotation.getMethods();
        for (int i = 0; i < methods.length; i++)
        {
           if (methods[i].getName().equals(member))
           {
              return methods[i].getReturnType();
           }
        }
        throw new RuntimeException("unable to determine member type for annotation: " + annotation.getName() + "." + member);
     }
     
     public static Object createAnnotation(ASTAnnotation node, Class annotation) throws Exception
     {
        HashMap map = new HashMap();
        
        if (node.jjtGetNumChildren() > 0)
        {
           Node contained = node.jjtGetChild(0);
           if (contained instanceof ASTSingleMemberValue)
           {
              Class type = getMemberType(annotation, "value");
              AnnotationCreator creator = new AnnotationCreator(annotation, type);
              contained.jjtAccept(creator, "value");
              map.put("value", creator.typeValue);
           }
           else
           {
              ASTMemberValuePairs pairs = (ASTMemberValuePairs) contained;
              for (int i = 0; i < pairs.jjtGetNumChildren(); i++)
              {
                 ASTMemberValuePair member = (ASTMemberValuePair) pairs.jjtGetChild(i);
                 Class type = getMemberType(annotation, member.getIdentifier().getValue());
                 AnnotationCreator creator = new AnnotationCreator(annotation, type);
                 member.jjtAccept(creator, null);
                 map.put(member.getIdentifier().getValue(), creator.typeValue);
              }
           }
        }
        
        defaultAnnotationReader.validate(map, annotation);
        return AnnotationProxy.createProxy(map, annotation);
     }
  
     public static Object createAnnotation(final String annotationExpr, final Class annotation) throws Exception
     {
        try
        {
           Object proxy = AccessController.doPrivileged(new PrivilegedExceptionAction() {
             public Object run() throws Exception{
                AnnotationParser parser = new AnnotationParser(new StringReader(annotationExpr));
                org.jboss.annotation.factory.ast.ASTStart start = parser.Start();
                ASTAnnotation node = (ASTAnnotation) start.jjtGetChild(0);
                
                return createAnnotation(node, annotation);
             }
           });
           
           return proxy;
        }
        catch (PrivilegedActionException e)
        {
           throw new RuntimeException(e.getException());
        }
     }
  
  }
  
  
  



More information about the jboss-cvs-commits mailing list