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