Previously Datatype.class binding was never cached nor statically
constructed and made available as Bindings.DATATYPE which is only
sensible because Datatype class is a central building block of Databoard
and therefore its binding should also be readily available instead of
all clients having to request for it separately.
A weak hashmap cache was also added for signature strings in
BindingRequest because it was noticed that in conditions where code
makes a lot of requests for uncached binding, the cost of String
construction in BindingRequest.getSignature starts to dominate
cpu/memory costs. Two main problems in there were: constantly creating
new strings and using the very inefficient String.replaceAll instead of
String.replace(char, char).
gitlab #82
Change-Id: I50fbbc2bbe1e5d6b8b5864c3aed4c228022e66dc
(cherry picked from commit
a1696e5257fae039410c924155fdeffc1ce1b3e9)
public static final VariantBinding STR_VARIANT; // java.lang.String ( as variant )
public static final Binding VOID; // void ( as {} )
- public static final Binding BEAN; // Bean ( as variant )
+ public static final Binding BEAN; // Bean ( as variant )
+ public static final Binding DATATYPE; // org.simantics.databoard.type.Datatype
public static final ArrayBinding BOOLEAN_ARRAY; // boolean[]
public static final ArrayBinding BYTE_ARRAY; // byte[]
OBJECT = databoard.OBJECT;
databoard.initialize();
+
+ DATATYPE = getBindingUnchecked(Datatype.class);
}
-
+
}
BindingRequest br = new BindingRequest( Datatype.class );
Binding datatypeBinding = getBinding( br );
typeClassFactory.getRepository().put(datatypeBinding.type(), br);
+ bindingRepository.put(br, datatypeBinding);
} catch (ClassNotFoundException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
@Override
public int deepHashValue(Object value, IdentityHashMap<Object, Object> hashedObjects) throws BindingException {
- Datatype type = getContentType(value);
+ Datatype type = getContentType(value);
Binding binding = getContentBinding(value);
- Binding dataTypeBinding = Bindings.getBindingUnchecked(Datatype.class);
Object element = getContent(value, binding);
- return dataTypeBinding.deepHashValue(type, hashedObjects) + binding.deepHashValue(element, hashedObjects);
+ return Bindings.DATATYPE.deepHashValue(type, hashedObjects) + binding.deepHashValue(element, hashedObjects);
}
@Override
// Compare Type
Datatype t1 = getContentType(o1);
Datatype t2 = getContentType(o2);
- Binding dataTypeBinding = Bindings.getBindingUnchecked(Datatype.class);
- int dif = dataTypeBinding.compare(t1, t2);
+ int dif = Bindings.DATATYPE.compare(t1, t2);
if (dif!=0) return dif;
// Compare Value
Binding bi1 = getContentBinding(o1);
/*******************************************************************************
- * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
+ * 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
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
+ * Semantum Oy - gitlab #82
*******************************************************************************/
package org.simantics.databoard.binding.factory;
import org.simantics.databoard.binding.Binding;
import org.simantics.databoard.binding.reflection.BindingRequest;
+import org.simantics.databoard.type.Datatype;
public class BindingRepository {
classMap.clear();
}
+ /**
+ * {@link Datatype} class has annotations but it can be considered a "class
+ * request" as it is a fundamental building block of Databoard and it has a
+ * fixed structure. Therefore {@link #classMap} is allowed to contain a cached
+ * Datatype.class -> Binding mapping.
+ */
+ private static final String DATATYPE_CLASS_NAME = Datatype.class.getName();
+
boolean isClassRequest( BindingRequest request )
{
- return request.className != null && (request.annotations==null || request.annotations.length==0);
+ return (request.className != null
+ && ((request.annotations==null || request.annotations.length==0)
+ || DATATYPE_CLASS_NAME.equals(request.className))
+ );
}
}
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
package org.simantics.databoard.binding.reflection;
import java.lang.annotation.Annotation;
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);
/** 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>;
hash = 7*hash + a.hashCode();
}
}
-
+
+ /**
+ * Create BindingRequest
+ *
+ * @param clazz
+ * @param annotations
+ */
+ public BindingRequest(Class<?> clazz)
+ {
+ this(clazz, NO_ANNOTATIONS);
+ }
+
/**
* Create 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")
if(literalRange != null) {
Collection<Resource> dts = graph.getAssertedObjects(literalRange, L0.HasDataType);
if(dts.size() == 1) {
- Datatype dt = graph.getPossibleValue(dts.iterator().next(), Bindings.getBindingUnchecked(Datatype.class));
+ Datatype dt = graph.getPossibleValue(dts.iterator().next(), Bindings.DATATYPE);
if(requiredDatatype == null) requiredDatatype = dt;
}
}