1 package org.simantics.databoard.binding.reflection;
\r
3 import java.lang.annotation.Annotation;
\r
4 import java.lang.reflect.Field;
\r
5 import java.util.ArrayList;
\r
6 import java.util.Arrays;
\r
7 import java.util.Collections;
\r
8 import java.util.List;
\r
9 import org.simantics.databoard.annotations.ArgumentImpl;
\r
10 import org.simantics.databoard.annotations.Arguments;
\r
11 import org.simantics.databoard.binding.Binding;
\r
12 import org.simantics.databoard.primitives.MutableInteger;
\r
14 public class BindingRequest {
\r
16 public static BindingRequest create( Field field )
\r
18 Annotation[] annotations = ClassBindingFactory.getFieldAnnotations(field);
\r
19 Class<?> fieldClass = field.getType();
\r
20 return new BindingRequest(fieldClass, annotations);
\r
23 /** Requested class */
\r
24 private Class<?> clazz;
\r
25 private ClassLoader cl;
\r
28 public final Annotation[] annotations;
\r
30 public final Annotation[] NO_ANNOTATIONS = new Annotation[0];
\r
32 public final String className; // eg. java.util.Map
\r
33 public final String signature; // eg. Ljava/util/Map;
\r
34 public final String descriptor; //eg. Ljava/util/Map<I;I>;
\r
36 public BindingRequest componentRequest;
\r
37 public Binding componentBinding;
\r
42 * Create BindingRequest that creates class lazily.
\r
44 * @param cl classloader
\r
46 * @param classSignature
\r
47 * @param classDescriptor
\r
48 * @param annotations
\r
50 public BindingRequest(ClassLoader cl, String className, String classSignature, String classDescriptor, Annotation...annotations)
\r
52 this.className = className;
\r
54 this.signature = classSignature;
\r
55 this.annotations = annotations;
\r
56 this.descriptor = classDescriptor;
\r
57 hash = className.hashCode();
\r
58 for (Annotation a : annotations) {
\r
59 hash = 7*hash + a.hashCode();
\r
64 * Create BindingRequest
\r
67 * @param annotations
\r
69 public BindingRequest(Class<?> clazz, Annotation...annotations)
\r
71 assert annotations!=null;
\r
73 Annotation[] classAnnotations = clazz.getAnnotations();
\r
74 if (classAnnotations!=null && classAnnotations.length>0) {
\r
75 this.annotations = new Annotation[classAnnotations.length + annotations.length];
\r
76 System.arraycopy(annotations, 0, this.annotations, 0, annotations.length);
\r
77 System.arraycopy(classAnnotations, 0, this.annotations, annotations.length, classAnnotations.length);
\r
79 this.annotations = annotations;
\r
82 className = clazz.getCanonicalName();
\r
83 signature = getSignature(clazz);
\r
84 List<Class<?>> args = createArgsList();
\r
85 StringBuilder desc = new StringBuilder();
\r
86 _buildDescriptor(desc, clazz, args, new MutableInteger(0));
\r
87 descriptor = desc.toString();
\r
88 hash = clazz.getName().hashCode();
\r
89 for (Annotation a : annotations) {
\r
90 hash = 7*hash + a.hashCode();
\r
94 private void _buildDescriptor(StringBuilder sb, Class<?> c, List<Class<?>> classes, MutableInteger pos)
\r
96 int genericCount = c.getTypeParameters().length;
\r
97 int genericsLeft = classes.size()-pos.value;
\r
98 if ( genericCount>0 && genericsLeft >= genericCount ) {
\r
100 sb.append(c.getName().replaceAll("\\.", "/"));
\r
102 for (int i=0; i<genericCount; i++)
\r
104 Class<?> gc = classes.get( pos.value++ );
\r
105 _buildDescriptor(sb, gc, classes, pos);
\r
110 sb.append( getSignature(c) );
\r
114 public BindingRequest(Class<?> clazz, List<Annotation> annotations)
\r
116 this(clazz, annotations.toArray(new Annotation[annotations.size()]));
\r
119 public BindingRequest(Class<?> clazz, Class<?>[] parameters)
\r
121 this(clazz, new ArgumentImpl(parameters));
\r
124 public boolean hasAnnotation(Class<?> annotationClass)
\r
126 for (Annotation a : annotations)
\r
127 if (annotationClass.equals(a.annotationType())) return true;
\r
131 @SuppressWarnings("unchecked")
\r
132 public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
\r
134 for (Annotation a : annotations)
\r
136 if (annotationClass.equals(a.annotationType()))
\r
142 public int hashCode() {
\r
147 public boolean equals(Object obj) {
\r
148 if (obj==null) return false;
\r
149 if (obj instanceof BindingRequest==false) return false;
\r
150 BindingRequest other = (BindingRequest) obj;
\r
151 return other.descriptor.equals(descriptor) &&
\r
152 Arrays.deepEquals(annotations, other.annotations);
\r
155 public Class<?> getClazz()
\r
157 if ( clazz==null ) {
\r
159 clazz = cl.loadClass( className );
\r
160 } catch (ClassNotFoundException e) {
\r
161 throw new RuntimeException( e );
\r
168 * Return a version of annotations list, where given set of annotations and
\r
169 * a number of class arguments were dropped.
\r
171 * @param argumentsToDrop the number of class arguments to drop
\r
172 * @param annotationsToDrop annotation to drop
\r
173 * @return request without argument annotation
\r
175 public Annotation[] dropAnnotations(int argumentsToDrop, Annotation...annotationsToDrop)
\r
177 ArrayList<Annotation> result = new ArrayList<Annotation>( annotations.length );
\r
179 for (Annotation a : annotations) {
\r
180 for (Annotation b : annotationsToDrop)
\r
181 if (a==b) continue nextA;
\r
182 if (a instanceof Arguments && argumentsToDrop>0) {
\r
183 Arguments c = ArgumentImpl.dropArguments((Arguments) a, argumentsToDrop);
\r
184 if (c!=null) result.add(c);
\r
185 } else result.add(a);
\r
187 Annotation[] newAnnotations = result.toArray( new Annotation[result.size()] );
\r
188 return newAnnotations;
\r
193 public String toString() {
\r
194 StringBuilder sb = new StringBuilder();
\r
195 sb.append(clazz.getName());
\r
196 if ( annotations!=null && annotations.length>0 ) {
\r
198 for (int i=0; i<annotations.length; i++) {
\r
199 Annotation a = annotations[i];
\r
200 if (i>0) sb.append(", ");
\r
206 return sb.toString();
\r
210 * Get signature, e.g. Ljava/util/Map;
\r
212 * @return singature string
\r
214 public static String getSignature(Class<?> clazz) {
\r
215 if (clazz==void.class) return "V";
\r
216 if (clazz==boolean.class) return "Z";
\r
217 if (clazz==char.class) return "C";
\r
218 if (clazz==byte.class) return "B";
\r
219 if (clazz==short.class) return "S";
\r
220 if (clazz==int.class) return "I";
\r
221 if (clazz==float.class) return "F";
\r
222 if (clazz==long.class) return "J";
\r
223 if (clazz==double.class) return "D";
\r
224 if (clazz.isArray()) return clazz.getName().replaceAll("\\.", "/");
\r
225 return "L"+clazz.getName().replaceAll("\\.", "/")+";";
\r
228 @SuppressWarnings("unchecked")
\r
229 List<Class<?>> createArgsList()
\r
231 if (annotations==null || !hasAnnotation(Arguments.class)) return Collections.EMPTY_LIST;
\r
232 List<Class<?>> result = new ArrayList<Class<?>>();
\r
233 for (Annotation a : annotations) {
\r
234 if ( a instanceof Arguments ) {
\r
235 Arguments args = (Arguments) a;
\r
236 for (Class<?> clazz : args.value()) result.add( clazz );
\r