1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard;
14 import java.io.IOException;
\r
15 import java.util.Comparator;
\r
16 import java.util.Map;
\r
18 import org.simantics.databoard.adapter.AdaptException;
\r
19 import org.simantics.databoard.adapter.Adapter;
\r
20 import org.simantics.databoard.adapter.AdapterConstructionException;
\r
21 import org.simantics.databoard.adapter.AdapterFactory;
\r
22 import org.simantics.databoard.adapter.RuntimeAdaptException;
\r
23 import org.simantics.databoard.adapter.RuntimeAdapterConstructionException;
\r
24 import org.simantics.databoard.annotations.ArgumentImpl;
\r
25 import org.simantics.databoard.annotations.Arguments;
\r
26 import org.simantics.databoard.binding.ArrayBinding;
\r
27 import org.simantics.databoard.binding.Binding;
\r
28 import org.simantics.databoard.binding.BooleanBinding;
\r
29 import org.simantics.databoard.binding.ByteBinding;
\r
30 import org.simantics.databoard.binding.DoubleBinding;
\r
31 import org.simantics.databoard.binding.FloatBinding;
\r
32 import org.simantics.databoard.binding.IntegerBinding;
\r
33 import org.simantics.databoard.binding.LongBinding;
\r
34 import org.simantics.databoard.binding.StringBinding;
\r
35 import org.simantics.databoard.binding.VariantBinding;
\r
36 import org.simantics.databoard.binding.classfactory.TypeClassFactory;
\r
37 import org.simantics.databoard.binding.error.BindingConstructionException;
\r
38 import org.simantics.databoard.binding.error.BindingException;
\r
39 import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;
\r
40 import org.simantics.databoard.binding.factory.BindingRepository;
\r
41 import org.simantics.databoard.binding.factory.TypeBindingFactory;
\r
42 import org.simantics.databoard.binding.impl.BooleanArrayBinding;
\r
43 import org.simantics.databoard.binding.impl.BooleanBindingDefault;
\r
44 import org.simantics.databoard.binding.impl.ByteArrayBinding;
\r
45 import org.simantics.databoard.binding.impl.ByteBindingDefault;
\r
46 import org.simantics.databoard.binding.impl.DoubleArrayBinding;
\r
47 import org.simantics.databoard.binding.impl.DoubleBindingDefault;
\r
48 import org.simantics.databoard.binding.impl.FloatArrayBinding;
\r
49 import org.simantics.databoard.binding.impl.FloatBindingDefault;
\r
50 import org.simantics.databoard.binding.impl.IntArrayBinding;
\r
51 import org.simantics.databoard.binding.impl.IntegerBindingDefault;
\r
52 import org.simantics.databoard.binding.impl.LongArrayBinding;
\r
53 import org.simantics.databoard.binding.impl.LongBindingDefault;
\r
54 import org.simantics.databoard.binding.impl.StringArrayBinding;
\r
55 import org.simantics.databoard.binding.impl.StringBindingDefault;
\r
56 import org.simantics.databoard.binding.impl.UnsignedByteBinding;
\r
57 import org.simantics.databoard.binding.impl.UnsignedIntegerBinding;
\r
58 import org.simantics.databoard.binding.impl.UnsignedLongBinding;
\r
59 import org.simantics.databoard.binding.mutable.MutableBooleanBinding;
\r
60 import org.simantics.databoard.binding.mutable.MutableByteBinding;
\r
61 import org.simantics.databoard.binding.mutable.MutableDoubleBinding;
\r
62 import org.simantics.databoard.binding.mutable.MutableFloatBinding;
\r
63 import org.simantics.databoard.binding.mutable.MutableIntegerBinding;
\r
64 import org.simantics.databoard.binding.mutable.MutableLongBinding;
\r
65 import org.simantics.databoard.binding.mutable.MutableStringBinding;
\r
66 import org.simantics.databoard.binding.mutable.MutableVariantBinding;
\r
67 import org.simantics.databoard.binding.reflection.BindingProvider;
\r
68 import org.simantics.databoard.binding.reflection.BindingRequest;
\r
69 import org.simantics.databoard.binding.reflection.ClassBindingFactory;
\r
70 import org.simantics.databoard.binding.reflection.VoidBinding;
\r
71 import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;
\r
72 import org.simantics.databoard.serialization.Serializer;
\r
73 import org.simantics.databoard.serialization.SerializerConstructionException;
\r
74 import org.simantics.databoard.serialization.SerializerFactory;
\r
75 import org.simantics.databoard.type.ArrayType;
\r
76 import org.simantics.databoard.type.Datatype;
\r
77 import org.simantics.databoard.util.DataValueUtil;
\r
80 * This ia a facade class for the binding services.
82 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
84 public class Bindings {
\r
86 public static final Databoard databoard;
90 /** Repository of mutable bindings */
\r
91 public static final Map<Datatype, Binding> mutableBindingRepository;
\r
93 /** Repository of default bindings */
\r
94 public static final Map<Datatype, Binding> defaultBindingRepository;
\r
96 /** Repository of class Bindings */
\r
97 public static final BindingRepository bindingRepository;
\r
99 /** Repository of serializers */
\r
100 public static final Map<Binding, Serializer> serializerRepository;
\r
105 /** Mutable Bindings Factory */
106 public static final TypeBindingFactory mutableBindingFactory;
\r
108 /** Default Bindings Factory */
\r
109 public static final TypeBindingFactory defaultBindingFactory;
\r
111 /** Reflection based Binding Factory, create binding to class */
\r
112 public static final ClassBindingFactory classBindingFactory;
\r
114 /** Serializer Factory */
\r
115 public static final SerializerFactory serializationFactory;
\r
117 /** Adapter Factory */
\r
118 public static final AdapterFactory adapterFactory;
\r
120 /** Class Factory */
\r
121 public static final TypeClassFactory typeClassFactory;
\r
124 // Bindings to various primitives
\r
125 public static final StringBinding STRING; // java.lang.String
\r
126 public static final IntegerBinding INTEGER; // java.lang.Integer
\r
127 public static final BooleanBinding BOOLEAN; // java.lang.Boolean
\r
128 public static final ByteBinding BYTE; // java.lang.Byte
\r
129 public static final LongBinding LONG; // java.lang.Long
\r
130 public static final DoubleBinding DOUBLE; // java.lang.Double
\r
131 public static final FloatBinding FLOAT; // java.lang.Float
\r
132 public static final VariantBinding VARIANT; // Variant
\r
133 public static final VariantBinding OBJECT; // java.lang.Object ( as variant )
\r
134 public static final VariantBinding STR_VARIANT; // java.lang.String ( as variant )
\r
136 public static final Binding VOID; // void ( as {} )
\r
137 public static final Binding BEAN; // Bean ( as variant )
\r
139 public static final ArrayBinding BOOLEAN_ARRAY; // boolean[]
\r
140 public static final ArrayBinding BYTE_ARRAY; // byte[]
\r
141 public static final ArrayBinding INT_ARRAY; // int[]
\r
142 public static final ArrayBinding LONG_ARRAY; // long[]
\r
143 public static final ArrayBinding FLOAT_ARRAY; // float[]
\r
144 public static final ArrayBinding DOUBLE_ARRAY; // double[]
\r
145 public static final ArrayBinding STRING_ARRAY; // String[]
\r
147 public static final StringBinding MUTABLE_STRING; // MutableString
\r
148 public static final IntegerBinding MUTABLE_INTEGER; // MutableInteger
\r
149 public static final BooleanBinding MUTABLE_BOOLEAN; // MutableBoolean
\r
150 public static final ByteBinding MUTABLE_BYTE; // MutableByte
\r
151 public static final LongBinding MUTABLE_LONG; // MutableLong
\r
152 public static final FloatBinding MUTABLE_FLOAT; // MutableFloat
\r
153 public static final DoubleBinding MUTABLE_DOUBLE; // MutableDouble
\r
154 public static final VariantBinding MUTABLE_VARIANT; // MutableVariant
\r
156 public static final IntegerBinding UNSIGNED_INTEGER; // UnsignedInteger.Immutable
\r
157 public static final ByteBinding UNSIGNED_BYTE; // UnsignedByte.Immutable
\r
158 public static final LongBinding UNSIGNED_LONG; // UnsignedLong.Immutable
\r
160 public static final IntegerBinding MUTABLE_UNSIGNED_INTEGER; // UnsignedInteger.Mutable
\r
161 public static final ByteBinding MUTABLE_UNSIGNED_BYTE; // UnsignedByte.Mutable
\r
162 public static final LongBinding MUTABLE_UNSIGNED_LONG; // UnsignedLong.Mutable
\r
165 * Get or create a binding that is completely mutable java class.
167 * DataType | Class of the bound instance
168 * ===================|==================
169 * UnionType | GenericBinding.TaggedObject.class
170 * OptionType | ValueContainer.class
171 * RecordType | Object[].class
172 * BooleanType | MutableBoolean.class
173 * DoubleType | MutableDouble.class
174 * FloatType | MutableFloat.class
175 * ByteType | MutableByte.class
176 * IntegerType | MutableInt.class
177 * LongType | MutableLong.class
178 * StringType | ValueContainer.class
179 * ArrayType | ArrayList.class
180 * MapType | TreeMap.class
181 * VariantType | MutableVariant.class
\r
183 * Note, requesting a binding with this convenience method stores the
\r
184 * binding and the type with strong reference, thus preventing garbage
\r
185 * collection. To allow garbage collection, please use another instance of
\r
186 * GenericBindingFactory and binding repository (Map<Datatype, Binding>). <p>
188 * @param type the type to create binding to
189 * @return binding binding to a mutable class
191 @SuppressWarnings("unchecked")
192 public static <T extends Binding> T getMutableBinding(Datatype type) {
194 Binding binding = mutableBindingRepository.get(type);
\r
195 if (binding!=null) return (T) binding;
\r
196 synchronized(mutableBindingRepository) {
\r
197 return (T) mutableBindingFactory.getBinding(type);
\r
199 } catch (BindingConstructionException e) {
\r
200 // Unexpected - if error is thrown there is fault in GenericBindingScheme
\r
201 throw new RuntimeBindingConstructionException(e);
\r
206 * Get or create a binding based on default java classes, such as
\r
207 * Integer.class, or byte[].class. The result is often binding for an
\r
208 * immutable classs. These bindings are more efficient than mutable bindings (above).
\r
210 * DataType | Class of the bound instance
\r
211 * ===================|==================
\r
212 * BooleanType | Boolean.class
\r
213 * ByteType | Byte.class
\r
214 * FloatType | Float.class
\r
215 * DoubleType | Double.class
\r
216 * IntegerType | Int.class
\r
217 * LongType | Long.class
\r
218 * StringType | String.class
\r
219 * UnionType | TaggedObject.class
\r
220 * OptionType | ValueContainer.class
\r
221 * RecordType | Object[].class
\r
222 * MapType | TreeMap.class
\r
223 * VariantType | Variant.class
\r
224 * ArrayType(Boolean) | boolean[].class
\r
225 * ArrayType(Byte) | byte[].class
\r
226 * ArrayType(Integer) | int[].class
\r
227 * ArrayType(Long) | long[].class
\r
228 * ArrayType(Float) | float[].class
\r
229 * ArrayType(Double) | double[].class
\r
230 * ArrayType(Byte) | byte[].class
\r
231 * ArrayType( T ) | Object[].class
\r
233 * Note, requesting a binding with this convenience method stores the
\r
234 * binding and the type with strong reference, thus preventing garbage
\r
235 * collection. To allow garbage collection, please use another instance of
\r
236 * DefaultBindingFactory and binding repository (Map<Datatype, Binding>). <p>
\r
238 * @param type the type to create binding to
\r
239 * @return binding binding to a mutable class
\r
241 @SuppressWarnings("unchecked")
\r
242 public static <T extends Binding> T getBinding(Datatype type) {
\r
244 Binding binding = defaultBindingRepository.get(type);
\r
245 if (binding!=null) return (T) binding;
\r
246 synchronized(defaultBindingRepository) {
\r
247 return (T) defaultBindingFactory.getBinding(type);
\r
249 } catch (BindingConstructionException e) {
\r
250 // Unexpected - if error is thrown there is fault in DefaultBindingScheme
\r
251 throw new RuntimeBindingConstructionException(e);
\r
256 * Get a binding to a Java Class. Details can be added by placing annotations
\r
257 * to the java classes. See more in package org.simantics.databoard.annotations.
260 * Whether the result is a completely mutable or not depends on the
\r
261 * requested class. For instance, fields such as Boolean, Integer, Long
262 * are not mutable, instead MutableBoolean, MutableInteger and MutableLong are.
263 * The length of Object[] is not mutable, but length of List<Object> is. <p>
\r
265 * Note, requesting a binding with this convenience method stores the
\r
266 * binding and the class with strong reference, thus preventing garbage
\r
267 * collection. To allow garbage collection, please use another instance of
\r
268 * BindingFactory and binding repository (Map<BindingRequest, Binding>). <p>
\r
270 * Is asm library is available, the binding is bytecode generated. Then read
\r
271 * and write operations are direct get/set calls or direct field read/writes.
\r
272 * There is no reflection used. <p>
\r
274 * @see ClassBindingFactory
277 * @throws BindingConstructionException
279 @SuppressWarnings("unchecked")
280 public static <T extends Binding> T getBinding(Class<?> clazz)
281 throws BindingConstructionException
283 Binding binding = bindingRepository.get( clazz );
\r
284 if (binding != null) {
\r
285 return (T) binding;
\r
288 BindingRequest request = new BindingRequest( clazz );
\r
289 synchronized(classBindingFactory) {
\r
290 binding = classBindingFactory.construct(request);
\r
295 @SuppressWarnings("unchecked")
\r
296 public static <T extends Binding> T getBinding(BindingRequest request)
\r
297 throws BindingConstructionException
\r
299 synchronized(classBindingFactory) {
\r
300 return (T) classBindingFactory.construct(request);
\r
305 * Get a binding for a Java Class. Use this method to acquire class
\r
306 * parameters for a generics class. <p>
\r
310 * Binding binding = Bindings.getBinding(Map.class, String.class, Integer.class);
\r
311 * Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();
\r
315 * Binding d = Bindings.getBinding(List.class, Integer.class);
\r
316 * List<Integer> list = (List<Integer>) d.createRandom(5);
\r
320 * Binding d = Bindings.getBinding(List.class, List.class, Integer.class);
\r
321 * List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);
\r
323 * @see ClassBindingFactory
\r
326 * @throws BindingConstructionException
\r
328 @SuppressWarnings("unchecked")
\r
329 public static <T extends Binding> T getBinding(Class<?> clazz, Class<?>...parameters)
\r
330 throws BindingConstructionException
\r
332 BindingRequest request = new BindingRequest( clazz, parameters );
\r
333 synchronized(classBindingFactory) {
\r
334 return (T) classBindingFactory.construct(request);
\r
339 * Try to get a binding for the actual class of a Java object.
\r
340 * @param obj A Java object
\r
341 * @return A binding for the class of the object
\r
342 * @throws BindingConstructionException if no binding can be constructed
\r
344 public static <T extends Binding> T getInstanceBinding(Object obj)
\r
345 throws BindingConstructionException
\r
347 return getBinding(obj.getClass());
\r
351 * Read binding and type from a class. DataType details and parameters
\r
352 * are read as annotations placed in the class.
\r
353 * (See org.simantics.databoard.annotations)
\r
355 * As an exception, in the subclasses of {@link Throwable}, the fields of
\r
356 * Throwable are omited.
\r
358 * This method is used for well-known classes where the caller is 100% sure
\r
359 * that a binding is construable without exception. <p>
\r
363 * @throws RuntimeBindingConstructionException
\r
365 @SuppressWarnings("unchecked")
\r
366 public static <T extends Binding> T getBindingUnchecked(Class<?> clazz)
\r
367 throws RuntimeBindingConstructionException
\r
370 return (T) getBinding(clazz);
\r
371 } catch (BindingConstructionException e) {
\r
372 throw new RuntimeBindingConstructionException(e);
\r
377 * Get a binding for a Java Class. Use this method to acquire class
\r
378 * parameters for a generics class. <p>
\r
382 * Binding binding = Bindings.getBinding(Map.class, String.class, Integer.class);
\r
383 * Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();
\r
387 * Binding d = Bindings.getBinding(List.class, Integer.class);
\r
388 * List<Integer> list = (List<Integer>) d.createRandom(5);
\r
392 * Binding d = Bindings.getBinding(List.class, List.class, Integer.class);
\r
393 * List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);
\r
395 * @see ClassBindingFactory
\r
398 * @throws BindingConstructionException
\r
400 @SuppressWarnings("unchecked")
\r
401 public static <T extends Binding> T getBindingUnchecked(Class<?> clazz, Class<?>...parameters)
\r
402 throws RuntimeBindingConstructionException
\r
405 Arguments args = new ArgumentImpl(parameters);
\r
406 BindingRequest request = new BindingRequest( clazz, args );
\r
407 Binding binding = bindingRepository.get( request );
\r
408 if (binding!=null);
\r
409 synchronized(classBindingFactory) {
\r
410 binding = classBindingFactory.construct(request);
\r
412 return (T) binding;
\r
413 } catch (BindingConstructionException e) {
\r
414 throw new RuntimeBindingConstructionException(e);
\r
419 * Add a simple binding to reflection binding factory.
\r
423 * @param parameters parameter classes
\r
425 public static void addBinding( Binding binding, Class<?> clazz, Class<?>...parameters )
\r
427 ArgumentImpl args = new ArgumentImpl( parameters );
\r
428 BindingRequest request = new BindingRequest( clazz, args );
\r
429 bindingRepository.put( request, binding );
\r
433 * Add binding factory for compositive bindings
\r
437 public static void addBindingFactory( BindingProvider factory )
\r
439 classBindingFactory.addFactory( factory );
\r
443 * Creates a bean class
\r
447 public static BindingRequest getBeanBindingRequest( Datatype type ) throws RuntimeBindingConstructionException {
\r
449 return typeClassFactory.getClass(type);
\r
450 } catch (BindingConstructionException e) {
\r
451 throw new RuntimeBindingConstructionException(e);
\r
456 * Creates a bean class
\r
460 public static Class<?> getBeanClass( Datatype type ) throws BindingConstructionException {
\r
461 BindingRequest br = typeClassFactory.getClass(type);
\r
462 return br.getClazz();
\r
466 * Create binding from datatype that instantiates java classes.
\r
467 * RecordTypes are Beans, UnionTypes are Classes with @Union annotation,
\r
468 * ArrayTypes are [].
\r
473 public static Binding getBeanBinding( Datatype type ) throws RuntimeBindingConstructionException {
\r
475 BindingRequest br = typeClassFactory.getClass(type);
\r
476 return getBinding( br );
\r
477 } catch (BindingConstructionException e) {
\r
478 throw new RuntimeBindingConstructionException(e);
\r
483 * Get a default array binding for a given component type binding.
\r
484 * Returns a primitive array type binding for primitive types and an
\r
485 * ObjectArrayBinding for others.
\r
487 * @param componentBinding A binding for a component type
\r
488 * @return A binding for the array type
\r
490 public static Binding getArrayBinding(Binding componentBinding) {
\r
491 return getBinding(new ArrayType(componentBinding.type()));
\r
495 * Get serializer that follows Databoard serialization spec.
\r
498 * @return serializer
\r
499 * @throws SerializerConstructionException
\r
501 public static Serializer getSerializer(Binding binding) throws SerializerConstructionException {
\r
502 return serializationFactory.construct(binding);
\r
506 * Get serializer that follows Databoard serialization spec.
\r
509 * @return serializer
\r
510 * @throws RuntimeSerializerConstructionException
\r
512 public static Serializer getSerializerUnchecked(Binding binding) throws RuntimeSerializerConstructionException {
\r
514 return serializationFactory.construct(binding);
\r
515 } catch (SerializerConstructionException e) {
\r
516 throw new RuntimeSerializerConstructionException(e);
\r
521 * Get serializer that follows Databoard serialization spec.
\r
524 * @return serializer
\r
525 * @throws SerializerConstructionException
\r
527 public static Serializer getSerializer(Class<?> clazz) throws SerializerConstructionException {
\r
529 Binding binding = getBinding(clazz);
\r
530 return serializationFactory.construct(binding);
\r
531 } catch (BindingConstructionException e) {
\r
532 throw new SerializerConstructionException( e );
\r
537 * Get serializer that follows Databoard serialization spec.
\r
540 * @return serializer serializer
\r
541 * @throws RuntimeSerializerConstructionException
\r
543 public static Serializer getSerializerUnchecked(Class<?> clazz) throws RuntimeSerializerConstructionException {
\r
545 Binding binding = getBinding(clazz);
\r
546 return serializationFactory.construct(binding);
\r
547 } catch (SerializerConstructionException e) {
\r
548 throw new RuntimeSerializerConstructionException(e);
\r
549 } catch (BindingConstructionException e) {
\r
550 throw new RuntimeSerializerConstructionException( new SerializerConstructionException(e) );
\r
554 * Create an adapter that adapts two bindings of the same
557 * @param domain binding of the source instance
558 * @param range binding of the result instance
559 * @return result adapter
560 * @throws AdapterConstructionException
562 public static Adapter getAdapter(Binding domain, Binding range)
563 throws AdapterConstructionException
565 return adapterFactory.getAdapter(domain, range, false, false);
569 * Create an adapter that adapts between two bindings of the same
572 * @param domain binding of the source instance
573 * @param range binding of the result instance
574 * @return result adapter
575 * @throws AdapterConstructionException
577 public static Adapter getAdapterUnchecked(Binding domain, Binding range)
578 throws RuntimeAdapterConstructionException
581 return adapterFactory.getAdapter(domain, range, false, false);
582 } catch (AdapterConstructionException e) {
583 throw new RuntimeAdapterConstructionException(e);
588 * Create a type adapter that adapts instances from one Datatype to
589 * another. Type Adapter does the following conversions:
591 * o Number Types, e.g. long -> double
592 * o Unit Types, e.g. mph -> km/h
593 * o Record Types, for each field of the range, there must be equal in domain
594 * o Union Types, for each tag type of the domain, there must be equal in range
596 * {@link AdaptException} is thrown at runtime, if number conversion is not
597 * posible, e.g. converting value 500 from Integer to Byte.
598 * Note, there is also a possibility of precision loss, in many conversions
\r
599 * e.g. from double to int.
601 * @param domain binding of the source instance
602 * @param range binding of the result instance
604 * @throws AdapterConstructionException
606 public static Adapter getTypeAdapter(Binding domain, Binding range)
607 throws AdapterConstructionException
609 return adapterFactory.getAdapter(domain, range, true, false);
613 * Create a type adapter that adapts instances from one DataType to
614 * another. Type Adapter does the following conversions:
616 * o Number Types, e.g. long -> double
617 * o Unit Types, e.g. mph -> km/h
618 * o Record Types, for each field of the range, there must be equal in domain
619 * o Union Types, for each tag type of the domain, there must be equal in range
621 * {@link AdaptException} is thrown at runtime, if number values are
622 * not compatible, e.g. converting value 500 from Long to Byte.
623 * Note, there is also a possibility of precision loss, e.g. when
624 * converting from double to int.
626 * @param domain binding of the source instance
627 * @param range binding of the result instance
628 * @return result adapter
629 * @throws AdapterConstructionException
631 public static Adapter getTypeAdapterUnchecked(Binding domain, Binding range)
634 return adapterFactory.getAdapter(domain, range, true, false);
635 } catch (AdapterConstructionException e) {
636 throw new RuntimeAdapterConstructionException(e);
641 * Adapt a value of one type to another.
646 * @return adapted value
647 * @throws AdapterConstructionException
648 * @throws AdaptException
650 public static Object adapt(Object value, Binding domain, Binding range)
651 throws AdaptException
654 if (domain.equals(range)) {
\r
657 else if (range instanceof VariantBinding) {
\r
658 if (domain instanceof VariantBinding) {
\r
659 // Copy variant contents directly
\r
660 Binding contentBinding = ((VariantBinding)domain).getContentBinding( value );
\r
661 Object content = ((VariantBinding)domain).getContent( value );
\r
662 return ((VariantBinding)range).create( contentBinding, content );
\r
665 // Default to just wrapping the value (avoid adapter construction to save memory)
\r
666 return ((VariantBinding)range).create(domain, value);
\r
669 else if (domain instanceof VariantBinding) {
\r
670 return adapt(((VariantBinding)domain).getContent( value ), ((VariantBinding)domain).getContentBinding( value ), range );
\r
673 return adapterFactory.getAdapter(domain, range, true, false).adapt(value);
\r
675 } catch (AdapterConstructionException | BindingException e) {
676 throw new AdaptException(e);
681 * Adapt a value of one type to another. Exceptions are run-time. Use this
\r
682 * if it safe to assume the conversion will be successful.
687 * @return adapted value
688 * @throws AdapterConstructionException
689 * @throws AdaptException
691 public static Object adaptUnchecked(Object value, Binding domain, Binding range)
692 throws RuntimeAdapterConstructionException, RuntimeAdaptException
695 if (domain==range) {
\r
698 if (range instanceof VariantBinding && !(domain instanceof VariantBinding)) {
\r
699 // Default to just wrapping the value (avoid adapter construction to save memory)
\r
700 return ((VariantBinding)range).create(domain, value);
\r
702 return adapterFactory.getAdapter(domain, range, true, false).adaptUnchecked(value);
703 } catch (RuntimeAdapterConstructionException e) {
704 throw new RuntimeAdaptException(new AdaptException(e.getCause()));
705 } catch (AdapterConstructionException e) {
706 throw new RuntimeAdaptException(new AdaptException(e));
707 } catch (BindingException e) {
\r
708 throw new RuntimeAdaptException(new AdaptException(e));
\r
713 * Adapt and clone a value instance to another type. Immutable
\r
714 * bindings may return the argument as is, others return a cloned copy.
719 * @return adapted value
720 * @throws AdapterConstructionException
721 * @throws AdaptException
723 public static Object clone(Object value, Binding domain, Binding range)
724 throws AdaptException
727 if (domain==range) {
\r
728 if (domain.isImmutable()) {
\r
731 return domain.clone(value);
\r
734 return adapterFactory.getAdapter(domain, range, true, true).adapt(value);
735 } catch (AdapterConstructionException e) {
736 throw new AdaptException(e);
742 * Clone a value of one binding to another. Bindings that handle immutable values
743 * may return the same instance, others will guarantee a complete copy.
745 * This method throws only runtime exceptions. Use this if it is safe to assume
\r
746 * that the conversion will be successful.
\r
751 * @return adapted value
752 * @throws AdapterConstructionException
753 * @throws AdaptException
755 public static Object cloneUnchecked(Object value, Binding domain, Binding range)
756 throws RuntimeAdapterConstructionException, RuntimeAdaptException
759 return adapterFactory.getAdapter(domain, range, true, true).adapt(value);
760 } catch (AdaptException e) {
761 throw new RuntimeAdaptException(e);
762 } catch (RuntimeAdapterConstructionException e) {
763 throw new RuntimeAdaptException(new AdaptException(e.getCause()));
764 } catch (AdapterConstructionException e) {
765 throw new RuntimeAdaptException(new AdaptException(e));
770 * Compares two data values for order. Returns a negative integer,
771 * zero, or a positive integer if, the first argument precedes/lesser than
\r
772 * the second, is equal to, or successor/greater than the second.<p>
774 * DataTypes of b1 and b2 are not equal, then data types are compared. <p>
776 * The comparison function is defined at
777 * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals <p>
779 * Note, comparing 2 different number types will not result a value comparison.
780 * Instead values have the following type precedence ByteType, IntegerType, LongType,
781 * FloatType, and the highest DoubleType. <p>
783 * @param b1 Binding of o1
784 * @param o1 the first object to be compared.
785 * @param b2 Binding of o2
786 * @param o2 the second object to be compared.
787 * @return a negative integer, zero, or a positive integer as the
788 * first argument is less than, equal to, or greater than the
790 * @throws BindingException if object cannot be handled by a binding
792 public static int compare(Binding b1, Object o1, Binding b2, Object o2)
793 throws BindingException
795 return DataValueUtil.compare(b1, o1, b2, o2);
799 * Compare two data values for equality. <p>
801 * Note, comparing 2 different number types will not result a value comparison.
802 * Instead values have the following type precedence ByteType, IntegerType, LongType,
803 * FloatType, and the highest DoubleType. <p>
809 * @return true if equal
810 * @throws BindingException
812 public static boolean equals(Binding b1, Object o1, Binding b2, Object o2)
813 throws BindingException
815 return DataValueUtil.equals(b1, o1, b2, o2);
818 public static Comparator<Object> createComparator(final Binding b1, final Binding b2)
820 return DataValueUtil.createComparator(b1, b2);
824 * Print the content of an object as a structure.
\r
825 * Utility function for debug purposes.
\r
830 public static String toString(Object o) {
\r
832 Binding b = Bindings.getBinding( o.getClass() );
\r
833 return b.printValueDefinition(o, true);
\r
834 } catch (BindingConstructionException e) {
\r
835 return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
\r
836 } catch (IOException e) {
\r
837 return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
\r
838 } catch (BindingException e) {
\r
839 return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
\r
844 STRING = new StringBindingDefault( Datatypes.STRING );
\r
845 INTEGER = new IntegerBindingDefault( Datatypes.INTEGER );
\r
846 BOOLEAN = new BooleanBindingDefault( Datatypes.BOOLEAN );
\r
847 BYTE = new ByteBindingDefault( Datatypes.BYTE );
\r
848 LONG = new LongBindingDefault( Datatypes.LONG );
\r
849 DOUBLE = new DoubleBindingDefault( Datatypes.DOUBLE );
\r
850 FLOAT = new FloatBindingDefault( Datatypes.FLOAT );
\r
851 VOID = VoidBinding.VOID_BINDING;
\r
852 BOOLEAN_ARRAY = new BooleanArrayBinding( Datatypes.BOOLEAN_ARRAY, BOOLEAN );
\r
853 BYTE_ARRAY = new ByteArrayBinding( Datatypes.BYTE_ARRAY, BYTE );
\r
854 INT_ARRAY = new IntArrayBinding( Datatypes.INTEGER_ARRAY, INTEGER );
\r
855 LONG_ARRAY = new LongArrayBinding( Datatypes.LONG_ARRAY, LONG );
\r
856 FLOAT_ARRAY = new FloatArrayBinding( Datatypes.FLOAT_ARRAY, FLOAT );
\r
857 DOUBLE_ARRAY = new DoubleArrayBinding( Datatypes.DOUBLE_ARRAY, DOUBLE );
\r
858 STRING_ARRAY = new StringArrayBinding( Datatypes.STRING_ARRAY, STRING );
\r
859 UNSIGNED_INTEGER = new UnsignedIntegerBinding.Immutable( Datatypes.INTEGER );
\r
860 UNSIGNED_BYTE = new UnsignedByteBinding.Immutable( Datatypes.BYTE );
\r
861 UNSIGNED_LONG = new UnsignedLongBinding.Immutable( Datatypes.LONG );
\r
862 MUTABLE_STRING = new MutableStringBinding( Datatypes.STRING );
\r
863 MUTABLE_INTEGER = new MutableIntegerBinding( Datatypes.INTEGER );
\r
864 MUTABLE_BOOLEAN = new MutableBooleanBinding( Datatypes.BOOLEAN );
\r
865 MUTABLE_BYTE = new MutableByteBinding( Datatypes.BYTE );
\r
866 MUTABLE_LONG = new MutableLongBinding( Datatypes.LONG );
\r
867 MUTABLE_FLOAT = new MutableFloatBinding( Datatypes.FLOAT );
\r
868 MUTABLE_DOUBLE = new MutableDoubleBinding( Datatypes.DOUBLE );
\r
869 MUTABLE_UNSIGNED_INTEGER = new UnsignedIntegerBinding.Mutable( Datatypes.INTEGER );
\r
870 MUTABLE_UNSIGNED_BYTE = new UnsignedByteBinding.Mutable( Datatypes.BYTE );
\r
871 MUTABLE_UNSIGNED_LONG = new UnsignedLongBinding.Mutable( Datatypes.LONG );
\r
873 databoard = new Databoard();
\r
875 mutableBindingRepository = databoard.mutableBindingRepository;
\r
876 defaultBindingRepository = databoard.defaultBindingRepository;
\r
877 bindingRepository = databoard.bindingRepository;
\r
878 serializerRepository = databoard.serializerRepository;
\r
879 mutableBindingFactory = databoard.mutableBindingFactory;
\r
880 defaultBindingFactory = databoard.defaultBindingFactory;
\r
881 classBindingFactory = databoard.classBindingFactory;
\r
882 serializationFactory = databoard.serializationFactory;
\r
883 adapterFactory = databoard.adapterFactory;
\r
884 typeClassFactory = databoard.typeClassFactory;
\r
886 BEAN = databoard.BEAN;
\r
887 VARIANT = databoard.VARIANT;
\r
888 MUTABLE_VARIANT = new MutableVariantBinding( classBindingFactory, adapterFactory );
\r
889 STR_VARIANT = databoard.STR_VARIANT;
\r
890 OBJECT = databoard.OBJECT;
\r
892 databoard.initialize();
\r