]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/BindingRequest.java
Rest API for Historian data
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / reflection / BindingRequest.java
1 package org.simantics.databoard.binding.reflection;
2
3 import java.lang.annotation.Annotation;
4 import java.lang.reflect.Field;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collections;
8 import java.util.List;
9 import org.simantics.databoard.annotations.ArgumentImpl;
10 import org.simantics.databoard.annotations.Arguments;
11 import org.simantics.databoard.binding.Binding;
12 import org.simantics.databoard.primitives.MutableInteger;
13
14 public class BindingRequest {
15         
16         public static BindingRequest create( Field field )
17         {
18         Annotation[] annotations = ClassBindingFactory.getFieldAnnotations(field);
19         Class<?> fieldClass = field.getType(); 
20         return new BindingRequest(fieldClass, annotations);
21         }
22         
23         /** Requested class */
24     private Class<?> clazz;
25     private ClassLoader cl;
26     
27     /** Annotations */
28     public final Annotation[] annotations;
29     
30     public final Annotation[] NO_ANNOTATIONS = new Annotation[0];
31     
32     public final String className; // eg. java.util.Map
33     public final String signature; // eg. Ljava/util/Map;
34     public final String descriptor; //eg. Ljava/util/Map<I;I>;
35     
36     public BindingRequest[] componentRequests;
37     public Binding[] componentBindings;
38     
39     transient int hash;
40
41     /**
42      * Create BindingRequest that creates class lazily. 
43      * 
44      * @param cl classloader
45      * @param className 
46      * @param classSignature 
47      * @param classDescriptor
48      * @param annotations 
49      */
50     public BindingRequest(ClassLoader cl, String className, String classSignature, String classDescriptor, Annotation...annotations)
51     {
52         this.className = className;
53         this.cl = cl;    
54         this.signature = classSignature;
55         this.annotations = annotations;
56         this.descriptor = classDescriptor;
57         hash = className.hashCode();
58         for (Annotation a : annotations) {
59             hash = 7*hash + a.hashCode();
60         }
61     }
62     
63     /**
64      * Create BindingRequest
65      * 
66      * @param clazz
67      * @param annotations
68      */
69     public BindingRequest(Class<?> clazz, Annotation...annotations)
70     {
71         assert annotations!=null;
72         this.clazz = clazz;
73         Annotation[] classAnnotations = clazz.getAnnotations();
74         if (classAnnotations!=null && classAnnotations.length>0) {
75             this.annotations = new Annotation[classAnnotations.length + annotations.length];
76             System.arraycopy(annotations, 0, this.annotations, 0, annotations.length);
77             System.arraycopy(classAnnotations, 0, this.annotations, annotations.length, classAnnotations.length);
78         } else {
79                 this.annotations = annotations;
80         }
81         
82         className = clazz.getCanonicalName();
83         signature = getSignature(clazz);
84         List<Class<?>> args = createArgsList();
85         StringBuilder desc = new StringBuilder();
86         _buildDescriptor(desc, clazz, args, new MutableInteger(0));
87         descriptor = desc.toString();
88         hash = clazz.getName().hashCode();
89         for (Annotation a : annotations) {
90             hash = 7*hash + a.hashCode();
91         }
92     }
93     
94     private void _buildDescriptor(StringBuilder sb, Class<?> c, List<Class<?>> classes, MutableInteger pos)
95     {
96         int genericCount = c.getTypeParameters().length;
97         int genericsLeft = classes.size()-pos.value;
98         if ( genericCount>0 && genericsLeft >= genericCount ) {
99                 sb.append('L');
100                 sb.append(c.getName().replaceAll("\\.", "/"));
101                 sb.append('<');
102                 for (int i=0; i<genericCount; i++) 
103                 {
104                         Class<?> gc = classes.get( pos.value++ );
105                         _buildDescriptor(sb, gc, classes, pos);
106                 }
107                 sb.append('>');                 
108                 sb.append(';');
109         } else {
110                 sb.append( getSignature(c) );
111         }
112     }
113
114     public BindingRequest(Class<?> clazz, List<Annotation> annotations)
115     {
116         this(clazz, annotations.toArray(new Annotation[annotations.size()]));
117     }
118     
119     public BindingRequest(Class<?> clazz, Class<?>[] parameters)
120     {
121         this(clazz, new ArgumentImpl(parameters));
122     }
123     
124     public boolean hasAnnotation(Class<?> annotationClass) 
125     {
126         for (Annotation a : annotations)
127             if (annotationClass.equals(a.annotationType())) return true;
128         return false;
129     }
130     
131     @SuppressWarnings("unchecked")
132     public <A extends Annotation> A getAnnotation(Class<A> annotationClass) 
133     {
134         for (Annotation a : annotations)
135         {
136             if (annotationClass.equals(a.annotationType()))
137                 return (A) a;
138         }
139         return null;
140     }
141     @Override
142     public int hashCode() {
143         return hash;
144     }
145     
146     @Override
147     public boolean equals(Object obj) {
148         if (obj==null) return false;
149         if (obj instanceof BindingRequest==false) return false;
150         BindingRequest other = (BindingRequest) obj;
151         return other.descriptor.equals(descriptor) &&
152             Arrays.deepEquals(annotations, other.annotations);
153     }
154     
155     public Class<?> getClazz()
156     {
157         if ( clazz==null ) {
158                 try {
159                                 clazz = cl.loadClass( className );
160                         } catch (ClassNotFoundException e) {
161                                 throw new RuntimeException( e );
162                         }
163         }
164         return clazz;
165     }
166         
167     /**
168      * Return a version of annotations list, where given set of annotations and
169      * a number of class arguments were dropped. 
170      * 
171      * @param argumentsToDrop the number of class arguments to drop
172      * @param annotationsToDrop annotation to drop
173      * @return request without argument annotation
174      */
175     public Annotation[] dropAnnotations(int argumentsToDrop, Annotation...annotationsToDrop)
176     {
177         ArrayList<Annotation> result = new ArrayList<Annotation>( annotations.length );
178         nextA:
179         for (Annotation a : annotations) {
180                 for (Annotation b : annotationsToDrop) 
181                         if (a==b) continue nextA;
182                 if (a instanceof Arguments && argumentsToDrop>0) {
183                         Arguments c = ArgumentImpl.dropArguments((Arguments) a, argumentsToDrop);
184                         if (c!=null) result.add(c);
185                 } else result.add(a);
186         }
187         Annotation[] newAnnotations = result.toArray( new Annotation[result.size()] );
188         return newAnnotations;
189     }
190     
191     
192     @Override
193     public String toString() {
194         StringBuilder sb = new StringBuilder();
195         sb.append(clazz.getName());
196         if ( annotations!=null && annotations.length>0 ) {
197             sb.append('(');
198             for (int i=0; i<annotations.length; i++) {
199                 Annotation a = annotations[i];
200                 if (i>0) sb.append(", ");
201                 sb.append(a);
202             }           
203             sb.append(')');
204         }
205         
206         return sb.toString();
207     }
208     
209     /**
210      * Get signature, e.g. Ljava/util/Map;
211      * 
212      * @return singature string
213      */
214     public static String getSignature(Class<?> clazz) {
215                 if (clazz==void.class) return "V";
216                 if (clazz==boolean.class) return "Z";
217                 if (clazz==char.class) return "C";
218                 if (clazz==byte.class) return "B";
219                 if (clazz==short.class) return "S";
220                 if (clazz==int.class) return "I";
221                 if (clazz==float.class) return "F";
222                 if (clazz==long.class) return "J";
223                 if (clazz==double.class) return "D";
224                 if (clazz.isArray()) return clazz.getName().replaceAll("\\.", "/");             
225                 return "L"+clazz.getName().replaceAll("\\.", "/")+";";
226     }
227     
228     @SuppressWarnings("unchecked")
229         List<Class<?>> createArgsList()
230     {
231         if (annotations==null || !hasAnnotation(Arguments.class)) return Collections.EMPTY_LIST;
232         List<Class<?>> result = new ArrayList<Class<?>>();
233         for (Annotation a : annotations) {
234                 if ( a instanceof Arguments ) {
235                         Arguments args = (Arguments) a;
236                         for (Class<?> clazz : args.value()) result.add( clazz );
237                 }
238         }
239         return result;
240     }
241         
242 }