[weld-commits] Weld SVN: r5183 - extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util.

weld-commits at lists.jboss.org weld-commits at lists.jboss.org
Tue Dec 1 08:26:58 EST 2009


Author: pete.muir at jboss.org
Date: 2009-12-01 08:26:57 -0500 (Tue, 01 Dec 2009)
New Revision: 5183

Added:
   extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInstanceProvider.java
   extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInvocationHandler.java
Log:
Add Stuart's dynamic annotation code

Added: extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInstanceProvider.java
===================================================================
--- extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInstanceProvider.java	                        (rev 0)
+++ extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInstanceProvider.java	2009-12-01 13:26:57 UTC (rev 5183)
@@ -0,0 +1,79 @@
+package org.jboss.weld.extensions.util;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Provide an instance of an annotation with member values
+ * 
+ * @author Stuart Douglas
+ * @author Pete Muir
+ * 
+ */
+public class AnnotationInstanceProvider
+{
+
+   protected final ConcurrentMap<Class<?>, Class<?>> cache;
+   
+   public AnnotationInstanceProvider()
+   {
+      cache = new ConcurrentHashMap<Class<?>, Class<?>>();
+   }
+
+   /**
+    * Returns an instance of the given annotation type with member values
+    * specified in the map.
+    */
+   public <T extends Annotation> T get(Class<T> annotation, Map<String, Object> values)
+   {
+      if (annotation == null)
+      {
+         throw new IllegalArgumentException("Must specify an annotation");
+      }
+      Class<?> clazz = cache.get(annotation);
+      // Not safe against data race, but doesn't matter, we can recompute and
+      // get the same value
+      if (clazz == null)
+      {
+         // create the proxy class
+         clazz = Proxy.getProxyClass(annotation.getClassLoader(), annotation, Serializable.class);
+         cache.put(annotation, clazz);
+      }
+      AnnotationInvocationHandler handler = new AnnotationInvocationHandler(values, annotation);
+      // create a new instance by obtaining the constructor via relection
+      try
+      {
+         return annotation.cast(clazz.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler }));
+      }
+      catch (IllegalArgumentException e)
+      {
+         throw new IllegalStateException("Error instantiating proxy for annotation. Annotation type: " + annotation, e);
+      }
+      catch (InstantiationException e)
+      {
+         throw new IllegalStateException("Error instantiating proxy for annotation. Annotation type: " + annotation, e);
+      }
+      catch (IllegalAccessException e)
+      {
+         throw new IllegalStateException("Error instantiating proxy for annotation. Annotation type: " + annotation, e);
+      }
+      catch (InvocationTargetException e)
+      {
+         throw new IllegalStateException("Error instantiating proxy for annotation. Annotation type: " + annotation, e.getCause());
+      }
+      catch (SecurityException e)
+      {
+         throw new IllegalStateException("Error accessing proxy constructor for annotation. Annotation type: " + annotation, e);
+      }
+      catch (NoSuchMethodException e)
+      {
+         throw new IllegalStateException("Error accessing proxy constructor for annotation. Annotation type: " + annotation, e);
+      }
+   }
+}


Property changes on: extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInstanceProvider.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Added: extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInvocationHandler.java
===================================================================
--- extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInvocationHandler.java	                        (rev 0)
+++ extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInvocationHandler.java	2009-12-01 13:26:57 UTC (rev 5183)
@@ -0,0 +1,373 @@
+package org.jboss.weld.extensions.util;
+
+import java.io.IOException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+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;
+
+/**
+ * Class that handles the method calls for a java.lang.reflect.Proxy that
+ * implements an annotation.
+ * 
+ * The generated handler takes a Map<String,Object> as a constructor argument
+ * with the keys equal to the annotation method names. For Annotation, array and
+ * Enum types the values must exactly match the return type or a
+ * ClassCastException will result.
+ * 
+ * For character types the the value must be an instance of java.lang.Character
+ * or String.
+ * 
+ * Numeric types do not have to match exactly, as they are converted using
+ * java.lang.Number's xxxValue methods.
+ * 
+ * 
+ * @author Stuart Douglas
+ * 
+ */
+class AnnotationInvocationHandler implements InvocationHandler, Serializable
+{
+   
+   private static class SerializationProxy
+   {
+      private final Map<String, Object> valueMap;
+      private final Class<? extends Annotation> annotationType;
+      
+      private SerializationProxy(Map<String, Object> valueMap, Class<? extends Annotation> annotationType)
+      {
+         this.valueMap = valueMap;
+         this.annotationType = annotationType;
+      }
+      
+      private Object readResolve() throws ObjectStreamException
+      {
+         return new AnnotationInvocationHandler(valueMap, annotationType);
+      }
+      
+   }
+
+   private static final long serialVersionUID = 4801508041776645033L;
+
+   private final Map<String, Object> valueMap;
+
+   private final Class<? extends Annotation> annotationType;
+
+   private final Method[] members;
+
+   AnnotationInvocationHandler(Map<String, Object> valueMap, Class<? extends Annotation> annotationType)
+   {
+      this.valueMap = valueMap;
+      this.annotationType = annotationType;
+      this.members = annotationType.getDeclaredMethods();
+   }
+   
+   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+   {
+      if (method.getName().equals("equals"))
+      {
+         return equals(args[0]);
+      }
+      else if (method.getName().equals("hashCode"))
+      {
+         return hashCode();
+      }
+      else if (method.getName().equals("toString"))
+      {
+         return toString();
+      }
+      else if (method.getName().equals("annotationType"))
+      {
+         return annotationType;
+      }
+      else
+      {
+         Object val = valueMap.get(method.getName());
+         if (val != null)
+         {
+            Class r = method.getReturnType();
+            if (Integer.class.isAssignableFrom(r) || r == int.class)
+            {
+               val = ((Number) val).intValue();
+            }
+            else if (Long.class.isAssignableFrom(r) || r == long.class)
+            {
+               val = ((Number) val).longValue();
+            }
+            else if (Short.class.isAssignableFrom(r) || r == short.class)
+            {
+               val = ((Number) val).shortValue();
+            }
+            else if (Byte.class.isAssignableFrom(r) || r == byte.class)
+            {
+               val = ((Number) val).shortValue();
+            }
+            else if (Double.class.isAssignableFrom(r) || r == double.class)
+            {
+               val = ((Number) val).doubleValue();
+            }
+            else if (Float.class.isAssignableFrom(r) || r == float.class)
+            {
+               val = ((Number) val).floatValue();
+            }
+            else if (Character.class.isAssignableFrom(r) || r == char.class)
+            {
+               if (String.class.isAssignableFrom(val.getClass()))
+               {
+                  val = val.toString().charAt(0);
+               }
+            }
+         }
+         return val;
+      }
+
+   }
+
+   @Override
+   public String toString()
+   {
+      StringBuilder string = new StringBuilder();
+      string.append('@').append(annotationType.getName()).append('(');
+      for (int i = 0; i < members.length; i++)
+      {
+         string.append(members[i].getName()).append('=');
+         Object value = invoke(members[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 < members.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 : members)
+            {
+               Object thisValue = valueMap.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 : members)
+      {
+         int memberNameHashCode = 127 * member.getName().hashCode();
+         Object value = valueMap.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 Object writeReplace() throws ObjectStreamException
+   {
+      return new SerializationProxy(valueMap, annotationType);
+   }
+   
+   private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
+   {
+      throw new UnsupportedOperationException("Must use SerializationProxy");
+   }
+
+   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);
+      }
+   }
+}


Property changes on: extensions/trunk/core/src/main/java/org/jboss/weld/extensions/util/AnnotationInvocationHandler.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native



More information about the weld-commits mailing list