]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/BindingRequest.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / reflection / BindingRequest.java
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/BindingRequest.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/BindingRequest.java
new file mode 100644 (file)
index 0000000..593eb30
--- /dev/null
@@ -0,0 +1,242 @@
+package org.simantics.databoard.binding.reflection;\r
+\r
+import java.lang.annotation.Annotation;\r
+import java.lang.reflect.Field;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Collections;\r
+import java.util.List;\r
+import org.simantics.databoard.annotations.ArgumentImpl;\r
+import org.simantics.databoard.annotations.Arguments;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.primitives.MutableInteger;\r
+\r
+public class BindingRequest {\r
+       \r
+       public static BindingRequest create( Field field )\r
+       {\r
+       Annotation[] annotations = ClassBindingFactory.getFieldAnnotations(field);\r
+       Class<?> fieldClass = field.getType(); \r
+       return new BindingRequest(fieldClass, annotations);             \r
+       }\r
+       \r
+       /** Requested class */\r
+    private Class<?> clazz;\r
+    private ClassLoader cl;\r
+    \r
+    /** Annotations */\r
+    public final Annotation[] annotations;\r
+    \r
+    public final Annotation[] NO_ANNOTATIONS = new Annotation[0];\r
+    \r
+    public final String className; // eg. java.util.Map\r
+    public final String signature; // eg. Ljava/util/Map;\r
+    public final String descriptor; //eg. Ljava/util/Map<I;I>;\r
+    \r
+    public BindingRequest componentRequest;\r
+    public Binding componentBinding;\r
+    \r
+    transient int hash;\r
+\r
+    /**\r
+     * Create BindingRequest that creates class lazily. \r
+     * \r
+     * @param cl classloader\r
+     * @param className \r
+     * @param classSignature \r
+     * @param classDescriptor\r
+     * @param annotations \r
+     */\r
+    public BindingRequest(ClassLoader cl, String className, String classSignature, String classDescriptor, Annotation...annotations)\r
+    {\r
+       this.className = className;\r
+       this.cl = cl;    \r
+       this.signature = classSignature;\r
+       this.annotations = annotations;\r
+       this.descriptor = classDescriptor;\r
+        hash = className.hashCode();\r
+        for (Annotation a : annotations) {\r
+            hash = 7*hash + a.hashCode();\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Create BindingRequest\r
+     * \r
+     * @param clazz\r
+     * @param annotations\r
+     */\r
+    public BindingRequest(Class<?> clazz, Annotation...annotations)\r
+    {\r
+        assert annotations!=null;\r
+        this.clazz = clazz;\r
+        Annotation[] classAnnotations = clazz.getAnnotations();\r
+        if (classAnnotations!=null && classAnnotations.length>0) {\r
+            this.annotations = new Annotation[classAnnotations.length + annotations.length];\r
+            System.arraycopy(annotations, 0, this.annotations, 0, annotations.length);\r
+            System.arraycopy(classAnnotations, 0, this.annotations, annotations.length, classAnnotations.length);\r
+        } else {\r
+               this.annotations = annotations;\r
+               }\r
+        \r
+        className = clazz.getCanonicalName();\r
+        signature = getSignature(clazz);\r
+        List<Class<?>> args = createArgsList();\r
+        StringBuilder desc = new StringBuilder();\r
+        _buildDescriptor(desc, clazz, args, new MutableInteger(0));\r
+        descriptor = desc.toString();\r
+        hash = clazz.getName().hashCode();\r
+        for (Annotation a : annotations) {\r
+            hash = 7*hash + a.hashCode();\r
+        }\r
+    }\r
+    \r
+    private void _buildDescriptor(StringBuilder sb, Class<?> c, List<Class<?>> classes, MutableInteger pos)\r
+    {\r
+       int genericCount = c.getTypeParameters().length;\r
+       int genericsLeft = classes.size()-pos.value;\r
+       if ( genericCount>0 && genericsLeft >= genericCount ) {\r
+               sb.append('L');\r
+               sb.append(c.getName().replaceAll("\\.", "/"));\r
+               sb.append('<');\r
+               for (int i=0; i<genericCount; i++) \r
+               {\r
+                       Class<?> gc = classes.get( pos.value++ );\r
+                       _buildDescriptor(sb, gc, classes, pos);\r
+               }\r
+               sb.append('>');                 \r
+               sb.append(';');\r
+       } else {\r
+               sb.append( getSignature(c) );\r
+       }\r
+    }\r
+\r
+    public BindingRequest(Class<?> clazz, List<Annotation> annotations)\r
+    {\r
+       this(clazz, annotations.toArray(new Annotation[annotations.size()]));\r
+    }\r
+    \r
+    public BindingRequest(Class<?> clazz, Class<?>[] parameters)\r
+    {\r
+       this(clazz, new ArgumentImpl(parameters));\r
+    }\r
+    \r
+    public boolean hasAnnotation(Class<?> annotationClass) \r
+    {\r
+        for (Annotation a : annotations)\r
+            if (annotationClass.equals(a.annotationType())) return true;\r
+        return false;\r
+    }\r
+    \r
+    @SuppressWarnings("unchecked")\r
+    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) \r
+    {\r
+        for (Annotation a : annotations)\r
+        {\r
+            if (annotationClass.equals(a.annotationType()))\r
+                return (A) a;\r
+        }\r
+        return null;\r
+    }\r
+    @Override\r
+    public int hashCode() {\r
+        return hash;\r
+    }\r
+    \r
+    @Override\r
+    public boolean equals(Object obj) {\r
+        if (obj==null) return false;\r
+        if (obj instanceof BindingRequest==false) return false;\r
+        BindingRequest other = (BindingRequest) obj;\r
+        return other.descriptor.equals(descriptor) &&\r
+            Arrays.deepEquals(annotations, other.annotations);\r
+    }\r
+    \r
+    public Class<?> getClazz()\r
+    {\r
+       if ( clazz==null ) {\r
+               try {\r
+                               clazz = cl.loadClass( className );\r
+                       } catch (ClassNotFoundException e) {\r
+                               throw new RuntimeException( e );\r
+                       }\r
+       }\r
+       return clazz;\r
+    }\r
+        \r
+    /**\r
+     * Return a version of annotations list, where given set of annotations and\r
+     * a number of class arguments were dropped. \r
+     * \r
+     * @param argumentsToDrop the number of class arguments to drop\r
+     * @param annotationsToDrop annotation to drop\r
+     * @return request without argument annotation\r
+     */\r
+    public Annotation[] dropAnnotations(int argumentsToDrop, Annotation...annotationsToDrop)\r
+    {\r
+       ArrayList<Annotation> result = new ArrayList<Annotation>( annotations.length );\r
+       nextA:\r
+       for (Annotation a : annotations) {\r
+               for (Annotation b : annotationsToDrop) \r
+                       if (a==b) continue nextA;\r
+               if (a instanceof Arguments && argumentsToDrop>0) {\r
+                       Arguments c = ArgumentImpl.dropArguments((Arguments) a, argumentsToDrop);\r
+                       if (c!=null) result.add(c);\r
+               } else result.add(a);\r
+       }\r
+       Annotation[] newAnnotations = result.toArray( new Annotation[result.size()] );\r
+       return newAnnotations;\r
+    }\r
+    \r
+    \r
+    @Override\r
+    public String toString() {\r
+        StringBuilder sb = new StringBuilder();\r
+        sb.append(clazz.getName());\r
+        if ( annotations!=null && annotations.length>0 ) {\r
+            sb.append('(');\r
+            for (int i=0; i<annotations.length; i++) {\r
+                Annotation a = annotations[i];\r
+                if (i>0) sb.append(", ");\r
+                sb.append(a);\r
+            }           \r
+            sb.append(')');\r
+        }\r
+        \r
+        return sb.toString();\r
+    }\r
+    \r
+    /**\r
+     * Get signature, e.g. Ljava/util/Map;\r
+     * \r
+     * @return singature string\r
+     */\r
+    public static String getSignature(Class<?> clazz) {\r
+               if (clazz==void.class) return "V";\r
+               if (clazz==boolean.class) return "Z";\r
+               if (clazz==char.class) return "C";\r
+               if (clazz==byte.class) return "B";\r
+               if (clazz==short.class) return "S";\r
+               if (clazz==int.class) return "I";\r
+               if (clazz==float.class) return "F";\r
+               if (clazz==long.class) return "J";\r
+               if (clazz==double.class) return "D";\r
+               if (clazz.isArray()) return clazz.getName().replaceAll("\\.", "/");             \r
+               return "L"+clazz.getName().replaceAll("\\.", "/")+";";\r
+    }\r
+    \r
+    @SuppressWarnings("unchecked")\r
+       List<Class<?>> createArgsList()\r
+    {\r
+       if (annotations==null || !hasAnnotation(Arguments.class)) return Collections.EMPTY_LIST;\r
+       List<Class<?>> result = new ArrayList<Class<?>>();\r
+       for (Annotation a : annotations) {\r
+               if ( a instanceof Arguments ) {\r
+                       Arguments args = (Arguments) a;\r
+                       for (Class<?> clazz : args.value()) result.add( clazz );\r
+               }\r
+       }\r
+       return result;\r
+    }\r
+        \r
+}\r