1 package org.simantics.databoard.binding.reflection;
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;
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;
14 public class BindingRequest {
16 public static BindingRequest create( Field field )
18 Annotation[] annotations = ClassBindingFactory.getFieldAnnotations(field);
19 Class<?> fieldClass = field.getType();
20 return new BindingRequest(fieldClass, annotations);
23 /** Requested class */
24 private Class<?> clazz;
25 private ClassLoader cl;
28 public final Annotation[] annotations;
30 public final Annotation[] NO_ANNOTATIONS = new Annotation[0];
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>;
36 public BindingRequest[] componentRequests;
37 public Binding[] componentBindings;
42 * Create BindingRequest that creates class lazily.
44 * @param cl classloader
46 * @param classSignature
47 * @param classDescriptor
50 public BindingRequest(ClassLoader cl, String className, String classSignature, String classDescriptor, Annotation...annotations)
52 this.className = className;
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();
64 * Create BindingRequest
69 public BindingRequest(Class<?> clazz, Annotation...annotations)
71 assert annotations!=null;
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);
79 this.annotations = annotations;
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();
94 private void _buildDescriptor(StringBuilder sb, Class<?> c, List<Class<?>> classes, MutableInteger pos)
96 int genericCount = c.getTypeParameters().length;
97 int genericsLeft = classes.size()-pos.value;
98 if ( genericCount>0 && genericsLeft >= genericCount ) {
100 sb.append(c.getName().replaceAll("\\.", "/"));
102 for (int i=0; i<genericCount; i++)
104 Class<?> gc = classes.get( pos.value++ );
105 _buildDescriptor(sb, gc, classes, pos);
110 sb.append( getSignature(c) );
114 public BindingRequest(Class<?> clazz, List<Annotation> annotations)
116 this(clazz, annotations.toArray(new Annotation[annotations.size()]));
119 public BindingRequest(Class<?> clazz, Class<?>[] parameters)
121 this(clazz, new ArgumentImpl(parameters));
124 public boolean hasAnnotation(Class<?> annotationClass)
126 for (Annotation a : annotations)
127 if (annotationClass.equals(a.annotationType())) return true;
131 @SuppressWarnings("unchecked")
132 public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
134 for (Annotation a : annotations)
136 if (annotationClass.equals(a.annotationType()))
142 public int hashCode() {
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);
155 public Class<?> getClazz()
159 clazz = cl.loadClass( className );
160 } catch (ClassNotFoundException e) {
161 throw new RuntimeException( e );
168 * Return a version of annotations list, where given set of annotations and
169 * a number of class arguments were dropped.
171 * @param argumentsToDrop the number of class arguments to drop
172 * @param annotationsToDrop annotation to drop
173 * @return request without argument annotation
175 public Annotation[] dropAnnotations(int argumentsToDrop, Annotation...annotationsToDrop)
177 ArrayList<Annotation> result = new ArrayList<Annotation>( annotations.length );
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);
187 Annotation[] newAnnotations = result.toArray( new Annotation[result.size()] );
188 return newAnnotations;
193 public String toString() {
194 StringBuilder sb = new StringBuilder();
195 sb.append(clazz.getName());
196 if ( annotations!=null && annotations.length>0 ) {
198 for (int i=0; i<annotations.length; i++) {
199 Annotation a = annotations[i];
200 if (i>0) sb.append(", ");
206 return sb.toString();
210 * Get signature, e.g. Ljava/util/Map;
212 * @return singature string
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("\\.", "/")+";";
228 @SuppressWarnings("unchecked")
229 List<Class<?>> createArgsList()
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 );