[seam-commits] Seam SVN: r11708 - modules/trunk/remoting/src/main/java/org/jboss/seam/remoting.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Tue Dec 1 05:53:57 EST 2009


Author: shane.bryzak at jboss.com
Date: 2009-12-01 05:53:56 -0500 (Tue, 01 Dec 2009)
New Revision: 11708

Added:
   modules/trunk/remoting/src/main/java/org/jboss/seam/remoting/AnnotationInvocationHandler.java
Modified:
   modules/trunk/remoting/src/main/java/org/jboss/seam/remoting/AnnotationsParser.java
Log:
support for qualifiers with literal member values


Added: modules/trunk/remoting/src/main/java/org/jboss/seam/remoting/AnnotationInvocationHandler.java
===================================================================
--- modules/trunk/remoting/src/main/java/org/jboss/seam/remoting/AnnotationInvocationHandler.java	                        (rev 0)
+++ modules/trunk/remoting/src/main/java/org/jboss/seam/remoting/AnnotationInvocationHandler.java	2009-12-01 10:53:56 UTC (rev 11708)
@@ -0,0 +1,300 @@
+package org.jboss.seam.remoting;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * 
+ * @author Shane Bryzak
+ */
+public class AnnotationInvocationHandler implements InvocationHandler
+{
+   private Class<? extends Annotation> annotationType;
+   
+   private Map<String,Object> memberValues;
+   
+   public AnnotationInvocationHandler(Class<? extends Annotation> annotationType,
+         Map<String,Object> memberValues)
+   {
+      this.annotationType = annotationType;
+      this.memberValues = memberValues;
+   }   
+   
+   public Object invoke(Object proxy, Method method, Object[] args)
+         throws Throwable
+   {
+      if ("annotationType".equals(method.getName()))
+      {
+         return annotationType;
+      }
+      else if ("equals".equals(method.getName()))
+      {
+         return equals(args[0]);
+      }
+      else if ("hashCode".equals(method.getName()))
+      {
+         return hashCode();
+      }
+      else if ("toString".equals(method.getName()))
+      {
+         return toString();
+      }
+      else
+      {
+         return memberValues.get(method.getName());
+      }
+   }
+   
+   @Override
+   public String toString()
+   {
+      StringBuilder string = new StringBuilder();
+      string.append('@').append(annotationType.getName()).append('(');
+      for (int i = 0; i < annotationType.getDeclaredMethods().length; i++)
+      {
+         string.append(annotationType.getDeclaredMethods()[i].getName()).append('=');
+         Object value = invoke(annotationType.getDeclaredMethods()[i], this);
+         if (value instanceof boolean[])
+         {
+            appendInBraces(string, Arrays.toString((boolean[]) value));
+         }
+         else if (value instanceof byte[])
+         {
+            appendInBraces(string, Arrays.toString((byte[]) value));
+         }
+         else if (value instanceof short[])
+         {
+            appendInBraces(string, Arrays.toString((short[]) value));
+         }
+         else if (value instanceof int[])
+         {
+            appendInBraces(string, Arrays.toString((int[]) value));
+         }
+         else if (value instanceof long[])
+         {
+            appendInBraces(string, Arrays.toString((long[]) value));
+         }
+         else if (value instanceof float[])
+         {
+            appendInBraces(string, Arrays.toString((float[]) value));
+         }
+         else if (value instanceof double[])
+         {
+            appendInBraces(string, Arrays.toString((double[]) value));
+         }
+         else if (value instanceof char[])
+         {
+            appendInBraces(string, Arrays.toString((char[]) value));
+         }
+         else if (value instanceof String[])
+         {
+            String[] strings = (String[]) value;
+            String[] quoted = new String[strings.length];
+            for (int j = 0; j < strings.length; j++)
+            {
+               quoted[j] = "\"" + strings[j] + "\"";
+            }
+            appendInBraces(string, Arrays.toString(quoted));
+         }
+         else if (value instanceof Class<?>[])
+         {
+            Class<?>[] classes = (Class<?>[]) value;
+            String[] names = new String[classes.length];
+            for (int j = 0; j < classes.length; j++)
+            {
+               names[j] = classes[j].getName() + ".class";
+            }
+            appendInBraces(string, Arrays.toString(names));
+         }
+         else if (value instanceof Object[])
+         {
+            appendInBraces(string, Arrays.toString((Object[]) value));
+         }
+         else if (value instanceof String)
+         {
+            string.append('"').append(value).append('"');
+         }
+         else if (value instanceof Class<?>)
+         {
+            string.append(((Class<?>) value).getName()).append(".class");
+         }
+         else
+         {
+            string.append(value);
+         }
+         if (i < annotationType.getDeclaredMethods().length - 1)
+         {
+            string.append(", ");
+         }
+      }
+      return string.append(')').toString();
+   }
+
+   private void appendInBraces(StringBuilder buf, String s)
+   {
+      buf.append('{').append(s.substring(1, s.length() - 1)).append('}');
+   }
+
+   @Override
+   public boolean equals(Object other)
+   {
+      if (other instanceof Annotation)
+      {
+         Annotation that = (Annotation) other;
+         if (this.annotationType.equals(that.annotationType()))
+         {
+            for (Method member : annotationType.getDeclaredMethods())
+            {
+               Object thisValue = memberValues.get(member.getName());
+               Object thatValue = invoke(member, that);
+               if (thisValue instanceof byte[] && thatValue instanceof byte[])
+               {
+                  if (!Arrays.equals((byte[]) thisValue, (byte[]) thatValue))
+                     return false;
+               }
+               else if (thisValue instanceof short[]
+                     && thatValue instanceof short[])
+               {
+                  if (!Arrays.equals((short[]) thisValue, (short[]) thatValue))
+                     return false;
+               }
+               else if (thisValue instanceof int[]
+                     && thatValue instanceof int[])
+               {
+                  if (!Arrays.equals((int[]) thisValue, (int[]) thatValue))
+                     return false;
+               }
+               else if (thisValue instanceof long[]
+                     && thatValue instanceof long[])
+               {
+                  if (!Arrays.equals((long[]) thisValue, (long[]) thatValue))
+                     return false;
+               }
+               else if (thisValue instanceof float[]
+                     && thatValue instanceof float[])
+               {
+                  if (!Arrays.equals((float[]) thisValue, (float[]) thatValue))
+                     return false;
+               }
+               else if (thisValue instanceof double[]
+                     && thatValue instanceof double[])
+               {
+                  if (!Arrays
+                        .equals((double[]) thisValue, (double[]) thatValue))
+                     return false;
+               }
+               else if (thisValue instanceof char[]
+                     && thatValue instanceof char[])
+               {
+                  if (!Arrays.equals((char[]) thisValue, (char[]) thatValue))
+                     return false;
+               }
+               else if (thisValue instanceof boolean[]
+                     && thatValue instanceof boolean[])
+               {
+                  if (!Arrays.equals((boolean[]) thisValue,
+                        (boolean[]) thatValue))
+                     return false;
+               }
+               else if (thisValue instanceof Object[]
+                     && thatValue instanceof Object[])
+               {
+                  if (!Arrays
+                        .equals((Object[]) thisValue, (Object[]) thatValue))
+                     return false;
+               }
+               else
+               {
+                  if (!thisValue.equals(thatValue))
+                     return false;
+               }
+            }
+            return true;
+         }
+      }
+      return false;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      int hashCode = 0;
+      for (Method member : annotationType.getDeclaredMethods())
+      {
+         int memberNameHashCode = 127 * member.getName().hashCode();
+         Object value = memberValues.get(member.getName());
+         int memberValueHashCode;
+         if (value instanceof boolean[])
+         {
+            memberValueHashCode = Arrays.hashCode((boolean[]) value);
+         }
+         else if (value instanceof short[])
+         {
+            memberValueHashCode = Arrays.hashCode((short[]) value);
+         }
+         else if (value instanceof int[])
+         {
+            memberValueHashCode = Arrays.hashCode((int[]) value);
+         }
+         else if (value instanceof long[])
+         {
+            memberValueHashCode = Arrays.hashCode((long[]) value);
+         }
+         else if (value instanceof float[])
+         {
+            memberValueHashCode = Arrays.hashCode((float[]) value);
+         }
+         else if (value instanceof double[])
+         {
+            memberValueHashCode = Arrays.hashCode((double[]) value);
+         }
+         else if (value instanceof byte[])
+         {
+            memberValueHashCode = Arrays.hashCode((byte[]) value);
+         }
+         else if (value instanceof char[])
+         {
+            memberValueHashCode = Arrays.hashCode((char[]) value);
+         }
+         else if (value instanceof Object[])
+         {
+            memberValueHashCode = Arrays.hashCode((Object[]) value);
+         }
+         else
+         {
+            memberValueHashCode = value.hashCode();
+         }
+         hashCode += memberNameHashCode ^ memberValueHashCode;
+      }
+      return hashCode;
+   }
+
+   private static Object invoke(Method method, Object instance)
+   {
+      try
+      {
+         if (!method.isAccessible())
+            method.setAccessible(true);
+         return method.invoke(instance);
+      }
+      catch (IllegalArgumentException e)
+      {
+         throw new RuntimeException("Error checking value of member method "
+               + method.getName() + " on " + method.getDeclaringClass(), e);
+      }
+      catch (IllegalAccessException e)
+      {
+         throw new RuntimeException("Error checking value of member method "
+               + method.getName() + " on " + method.getDeclaringClass(), e);
+      }
+      catch (InvocationTargetException e)
+      {
+         throw new RuntimeException("Error checking value of member method "
+               + method.getName() + " on " + method.getDeclaringClass(), e);
+      }
+   }
+}

Modified: modules/trunk/remoting/src/main/java/org/jboss/seam/remoting/AnnotationsParser.java
===================================================================
--- modules/trunk/remoting/src/main/java/org/jboss/seam/remoting/AnnotationsParser.java	2009-12-01 07:00:40 UTC (rev 11707)
+++ modules/trunk/remoting/src/main/java/org/jboss/seam/remoting/AnnotationsParser.java	2009-12-01 10:53:56 UTC (rev 11708)
@@ -3,18 +3,26 @@
 import java.io.StringReader;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.jboss.seam.remoting.annotationparser.AnnotationParser;
 import org.jboss.seam.remoting.annotationparser.ParseException;
 import org.jboss.seam.remoting.annotationparser.syntaxtree.AnnotationsUnit;
+import org.jboss.seam.remoting.annotationparser.syntaxtree.Literal;
 import org.jboss.seam.remoting.annotationparser.syntaxtree.MarkerAnnotation;
+import org.jboss.seam.remoting.annotationparser.syntaxtree.MemberValue;
 import org.jboss.seam.remoting.annotationparser.syntaxtree.MemberValuePair;
+import org.jboss.seam.remoting.annotationparser.syntaxtree.MemberValuePairs;
 import org.jboss.seam.remoting.annotationparser.syntaxtree.Name;
 import org.jboss.seam.remoting.annotationparser.syntaxtree.Node;
+import org.jboss.seam.remoting.annotationparser.syntaxtree.NodeChoice;
 import org.jboss.seam.remoting.annotationparser.syntaxtree.NodeListOptional;
+import org.jboss.seam.remoting.annotationparser.syntaxtree.NodeOptional;
 import org.jboss.seam.remoting.annotationparser.syntaxtree.NodeSequence;
 import org.jboss.seam.remoting.annotationparser.syntaxtree.NodeToken;
 import org.jboss.seam.remoting.annotationparser.syntaxtree.NormalAnnotation;
@@ -28,40 +36,42 @@
  * @author Shane Bryzak
  */
 public class AnnotationsParser extends DepthFirstVisitor
-{
-   public enum AnnotationType { MARKER, SINGLE_MEMBER, NORMAL }
-   
+{    
    protected class AnnotationMetadata
    {
-      private AnnotationType type;
-      private String name;
+      private Class<? extends Annotation> annotationType;
+      private Map<String,Object> memberValues = new HashMap<String,Object>();
       
-      public AnnotationMetadata(AnnotationType type, String name)
+      public AnnotationMetadata(String name)
       {
-         this.type = type;
-         this.name = name;
+         this.annotationType = calcAnnotationType(name, beanType);
+      }      
+      
+      public void addMemberValue(String name, Object value)
+      {
+         memberValues.put(name, value);
       }
       
-      public AnnotationType getType()
+      public Map<String,Object> getMemberValues()
       {
-         return type;
+         return memberValues;
       }
       
-      public String getName()
+      public Class<? extends Annotation> getAnnotationType()
       {
-         return name;
+         return annotationType;
       }
    }
-   
+
+   private Class<?> beanType;
    private List<AnnotationMetadata> meta = new ArrayList<AnnotationMetadata>();
    
-   private AnnotationMetadata currentAnnotation;
-   
    private Annotation[] annotations;
    
    @SuppressWarnings("unchecked")
    public AnnotationsParser(Class<?> beanType, String declaration)
    {
+      this.beanType = beanType;
       // TODO cache the results somewhere
       
       AnnotationParser parser = new AnnotationParser(new StringReader(declaration));
@@ -82,12 +92,11 @@
       for (int i = 0; i < meta.size(); i++)
       {
          AnnotationMetadata ann = meta.get(i);
-         Class<?> annotationType = calcAnnotationType(ann.getName(), beanType);
          InvocationHandler handler = new AnnotationInvocationHandler(
-               (Class<? extends Annotation>) annotationType, null);
+               (Class<? extends Annotation>) ann.getAnnotationType(), ann.getMemberValues());
          annotations[i] = (Annotation) Proxy.newProxyInstance(
-               annotationType.getClassLoader(),
-               new Class[] {annotationType}, handler);
+               ann.getAnnotationType().getClassLoader(),
+               new Class[] {ann.getAnnotationType()}, handler);
       }
       
       meta = null;
@@ -123,45 +132,146 @@
    @Override
    public void visit(AnnotationsUnit node)
    {
+      List<org.jboss.seam.remoting.annotationparser.syntaxtree.Annotation> annotations = 
+         new ArrayList<org.jboss.seam.remoting.annotationparser.syntaxtree.Annotation>(); 
+      
+      NodeOptional n = (NodeOptional) node.f0;
+      if (n.present())
+      {
+         if (n.node instanceof NodeSequence)
+         {
+            NodeSequence ns = (NodeSequence) n.node;
+            {
+               for (Node nsNode : ns.nodes)
+               {
+                  if (nsNode instanceof org.jboss.seam.remoting.annotationparser.syntaxtree.Annotation)
+                  {
+                     annotations.add((org.jboss.seam.remoting.annotationparser.syntaxtree.Annotation) nsNode);
+                  }
+                  else if (nsNode instanceof NodeListOptional)
+                  {
+                     NodeListOptional nlo = (NodeListOptional) nsNode;
+                     if (nlo.present())
+                     {
+                        for (Node nloNode : nlo.nodes)
+                        {
+                           if (nloNode instanceof org.jboss.seam.remoting.annotationparser.syntaxtree.Annotation)
+                           {
+                              annotations.add((org.jboss.seam.remoting.annotationparser.syntaxtree.Annotation) nloNode);
+                           }
+                        }
+                     }
+                  }
+               }
+            }
+         }
+      }
+      
+      for (org.jboss.seam.remoting.annotationparser.syntaxtree.Annotation a : annotations)
+      {
+         processAnnotation(a);
+      }
+      
       super.visit(node);
    }
    
-   @Override
-   public void visit(org.jboss.seam.remoting.annotationparser.syntaxtree.Annotation node)
-   {     
-      Node choice = node.f0.choice;
-      
-      AnnotationType type = null;
-      Name name = null;
-      
-      if (choice instanceof MarkerAnnotation)
+   private void processAnnotation(org.jboss.seam.remoting.annotationparser.syntaxtree.Annotation node)
+   {           
+      if (node.f0.choice instanceof MarkerAnnotation)
       {
-         type = AnnotationType.MARKER;
-         name = ((MarkerAnnotation) choice).f1;
+         meta.add(new AnnotationMetadata(extractName(((MarkerAnnotation) node.f0.choice).f1)));
       }
-      else if (choice instanceof NormalAnnotation)
+      else if (node.f0.choice instanceof NormalAnnotation)
       {
-         type = AnnotationType.NORMAL;
-         name = ((NormalAnnotation) choice).f1;
+         NormalAnnotation ann = (NormalAnnotation) node.f0.choice;
+         AnnotationMetadata metadata = new AnnotationMetadata(extractName(ann.f1));
+         
+         if (ann.f3.present() && ann.f3.node instanceof MemberValuePairs)
+         {
+            MemberValuePairs mvp = (MemberValuePairs) ann.f3.node;
+            extractMemberValue(metadata, mvp.f0.f0.tokenImage, mvp.f0.f2);
+            
+            if (mvp.f1.present())
+            {
+               for (Node n : mvp.f1.nodes)
+               {
+                  if (n instanceof MemberValuePair)
+                  {
+                     MemberValuePair p = (MemberValuePair) n;
+                     extractMemberValue(metadata, p.f0.tokenImage, p.f2);
+                  }
+               }
+            }
+         }
+         meta.add(metadata);
       }
-      else if (choice instanceof SingleMemberAnnotation)
+      else if (node.f0.choice instanceof SingleMemberAnnotation)
       {
-         type = AnnotationType.SINGLE_MEMBER;
-         name = ((SingleMemberAnnotation) choice).f1;
+         AnnotationMetadata metadata = new AnnotationMetadata(
+               extractName(((SingleMemberAnnotation) node.f0.choice).f1));
+         extractMemberValue(metadata, "value", ((SingleMemberAnnotation) node.f0.choice).f3);
+         meta.add(metadata);
       }
          
-      currentAnnotation = new AnnotationMetadata(type, extractName(name));
-      meta.add(currentAnnotation);
+   }
+   
+   private void extractMemberValue(AnnotationMetadata metadata, String memberName, 
+         MemberValue memberValue)
+   {
+      Class<?> memberType = null;
       
-      super.visit(node);      
+      for (Method m : metadata.getAnnotationType().getMethods())
+      {
+         if (memberName.equals(m.getName()))
+         {
+            memberType = m.getReturnType();
+            break;
+         }
+      }
+      
+      if (memberType == null)
+      {
+         throw new RuntimeException("Annotation member " + memberName + 
+               " not found on annotation type " + metadata.getAnnotationType().getName());
+      }
+      
+      Object value = null;
+      
+      switch (memberValue.f0.which)
+      {        
+         // TODO add the missing conversions
+         case 0: // Annotation  
+            break;
+         case 1: // MemberValueArray
+            break;
+         case 2: // Literal
+            value = convertLiteral((Literal) memberValue.f0.choice);
+            break;
+      }
+      
+      metadata.addMemberValue(memberName, value);
    }
    
-   @Override
-   public void visit(MemberValuePair node)
+   private Object convertLiteral(Literal literal)
    {
+      // TODO add the missing conversions
       
+      switch (literal.f0.which)
+      {
+         case 0: // <INTEGER_LITERAL>
+            return Integer.parseInt(((NodeToken) literal.f0.choice).tokenImage);
+         case 1: // <FLOATING_POINT_LITERAL>
+            return Float.parseFloat(((NodeToken) literal.f0.choice).tokenImage);
+         case 2: // <CHARACTER_LITERAL>                  
+         case 3: // <STRING_LITERAL>
+            String value = ((NodeToken) literal.f0.choice).tokenImage; 
+            return value.substring(1, value.length() - 1); // strip the double quotes
+         case 4: // BooleanLiteral()
+         case 5: // NullLiteral()
+      }      
+      return null;
    }
-   
+      
    private String extractName(Name name)
    {
       StringBuilder sb = new StringBuilder();



More information about the seam-commits mailing list