]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/BindingRequest.java
Fixing several binding-related bugs
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / reflection / BindingRequest.java
index 4ada936032036b149dd182ac6bb005e138234ffd..ac2d9cf1b7246f6be353c8a15aea887ce3b8d45b 100644 (file)
@@ -1,3 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2018 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum Oy - gitlab #82, gitlab #313
+ *******************************************************************************/
 package org.simantics.databoard.binding.reflection;
 
 import java.lang.annotation.Annotation;
@@ -6,13 +18,25 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
 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 {
-       
+
+    /**
+     * A weak cache for signature strings by Class.
+     * Prevents the system from constructing new strings
+     * from Classes for every non-trivial BindingRequest. 
+     */
+    private static final Map<Class<?>, String> signatureCache = Collections.<Class<?>, String>synchronizedMap(new WeakHashMap<>());
+
+    public static final Annotation[] NO_ANNOTATIONS = {};
+
        public static BindingRequest create( Field field )
        {
        Annotation[] annotations = ClassBindingFactory.getFieldAnnotations(field);
@@ -27,8 +51,6 @@ public class BindingRequest {
     /** 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<I;I>;
@@ -38,6 +60,23 @@ public class BindingRequest {
     
     transient int hash;
 
+    /**
+     * Cloning constructor with replacement annotations.
+     * 
+     * @param other the request to clone
+     * @param annotations the annotations to use while cloning
+     */
+    private BindingRequest(BindingRequest other, Annotation...annotations)
+    {
+        this.clazz = other.clazz;
+        this.cl = other.cl;
+        this.annotations = annotations;
+        this.className = other.className;
+        this.signature = other.signature;
+        this.descriptor = other.descriptor;
+        hash = calcHash(clazz.getName());
+    }
+
     /**
      * Create BindingRequest that creates class lazily. 
      * 
@@ -54,12 +93,20 @@ public class BindingRequest {
        this.signature = classSignature;
        this.annotations = annotations;
        this.descriptor = classDescriptor;
-        hash = className.hashCode();
-        for (Annotation a : annotations) {
-            hash = 7*hash + a.hashCode();
-        }
+       hash = calcHash(className);
     }
-    
+
+    /**
+     * Create BindingRequest
+     * 
+     * @param clazz
+     * @param annotations
+     */
+    public BindingRequest(Class<?> clazz)
+    {
+        this(clazz, NO_ANNOTATIONS);
+    }
+
     /**
      * Create BindingRequest
      * 
@@ -81,17 +128,23 @@ public class BindingRequest {
         
         className = clazz.getCanonicalName();
         signature = getSignature(clazz);
-        List<Class<?>> 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();
+        descriptor = _buildDescriptor(new StringBuilder(), clazz, createArgsList(), new MutableInteger(0)).toString();
+        hash = calcHash(clazz.getName());
+    }
+
+    public BindingRequest withAnnotations(Annotation... newAnnotations) {
+        return new BindingRequest(this, newAnnotations);
+    }
+
+    private int calcHash(String className) {
+        int hash = className.hashCode();
+        for (Annotation a : this.annotations) {
+            hash += a.hashCode();
         }
+        return hash;
     }
-    
-    private void _buildDescriptor(StringBuilder sb, Class<?> c, List<Class<?>> classes, MutableInteger pos)
+
+    private StringBuilder _buildDescriptor(StringBuilder sb, Class<?> c, List<Class<?>> classes, MutableInteger pos)
     {
        int genericCount = c.getTypeParameters().length;
        int genericsLeft = classes.size()-pos.value;
@@ -109,6 +162,7 @@ public class BindingRequest {
        } else {
                sb.append( getSignature(c) );
        }
+       return sb;
     }
 
     public BindingRequest(Class<?> clazz, List<Annotation> annotations)
@@ -221,8 +275,17 @@ public class BindingRequest {
                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("\\.", "/")+";";
+               String cached = signatureCache.get(clazz);
+               if (cached == null) {
+                       cached = clazz.isArray()
+                                       ? clazz.getName().replace('.', '/')
+                                       : "L"+clazz.getName().replace('.', '/')+";";
+                       signatureCache.put(clazz, cached);
+                       //System.out.println("BindingRequest.getSignature: cache miss for " + clazz + " = " + cached);
+               } else {
+                       //System.out.println("BindingRequest.getSignature: cache hit for " + clazz + " = " + cached);
+               }
+               return cached;
     }
     
     @SuppressWarnings("unchecked")