-/*******************************************************************************\r
- * Copyright (c) 2010 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
+/*******************************************************************************
+ * Copyright (c) 2010 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
+ *******************************************************************************/
package org.simantics.databoard.binding;
-import java.io.IOException;\r
-import java.io.Reader;\r
-import java.util.Comparator;\r
-import java.util.HashSet;\r
-import java.util.IdentityHashMap;\r
-import java.util.Random;\r
-import java.util.Set;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
-import org.simantics.databoard.accessor.error.AccessorException;\r
-import org.simantics.databoard.accessor.reference.ChildReference;\r
-import org.simantics.databoard.adapter.AdaptException;\r
-import org.simantics.databoard.adapter.AdapterConstructionException;\r
-import org.simantics.databoard.adapter.RuntimeAdaptException;\r
-import org.simantics.databoard.binding.error.BindingException;\r
-import org.simantics.databoard.binding.error.RuntimeBindingException;\r
-import org.simantics.databoard.binding.impl.BindingPrintContext;\r
-import org.simantics.databoard.binding.mutable.MutableVariant;\r
-import org.simantics.databoard.binding.mutable.Variant;\r
-import org.simantics.databoard.binding.util.DefaultValue;\r
-import org.simantics.databoard.binding.util.RandomValue;\r
-import org.simantics.databoard.parser.DataParser;\r
-import org.simantics.databoard.parser.DataValuePrinter;\r
-import org.simantics.databoard.parser.ParseException;\r
-import org.simantics.databoard.parser.PrintFormat;\r
-import org.simantics.databoard.parser.repository.DataTypeSyntaxError;\r
-import org.simantics.databoard.parser.repository.DataValueRepository;\r
-import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;\r
-import org.simantics.databoard.serialization.Serializer;\r
-import org.simantics.databoard.serialization.SerializerFactory;\r
-import org.simantics.databoard.serialization.SerializerScheme;\r
-import org.simantics.databoard.type.Datatype;\r
-import org.simantics.databoard.util.IdentityPair;\r
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Random;
+import java.util.Set;
-/**\r
- * This class represents connection between abstract datatype and java class.\r
- * A binding allows an access to an Object in scope of a datatype. <p>\r
- * \r
- * For example, IntegerBinding gives unified access to any integer class\r
- * (Integer, int, MutableInteger, UnsignedInteger). There is same unification\r
- * for primitive types and constructed types (record, map, array, union, variant). <p>\r
- * \r
- * You can get a hold of binding several ways:\r
- * 1) Use one of the default bindings e.g. {@link Bindings#BYTE_ARRAY}\r
- * 2) Create one using Datatype {@link Bindings#getMutableBinding(Datatype)}\r
- * 3) Create one using Reflectiong {@link Bindings#getBinding(Class)}\r
- * 4) Instantiate binding your self. e.g. new TreeMapBinding( Bindings.STRING, Bindings.STRING );\r
- * 5) Sub-class one of the abstract binding classes \r
- * @see BooleanBinding\r
- * @see ByteBinding\r
- * @see IntegerBinding\r
- * @see LongBinding\r
- * @see FloatBinding\r
- * @see DoubleBinding\r
- * @see StringBinding\r
- * @see RecordBinding\r
- * @see ArrayBinding\r
- * @see MapBinding\r
- * @see OptionalBinding\r
- * @see UnionBinding\r
- * @see VariantBinding\r
- * \r
- * See examples/BindingExample.java \r
- * @see Bindings Facade class Bindings provices extra functionality. \r
- * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.accessor.error.AccessorConstructionException;
+import org.simantics.databoard.accessor.error.AccessorException;
+import org.simantics.databoard.accessor.reference.ChildReference;
+import org.simantics.databoard.adapter.AdaptException;
+import org.simantics.databoard.adapter.AdapterConstructionException;
+import org.simantics.databoard.adapter.RuntimeAdaptException;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.binding.error.RuntimeBindingException;
+import org.simantics.databoard.binding.impl.BindingPrintContext;
+import org.simantics.databoard.binding.mutable.MutableVariant;
+import org.simantics.databoard.binding.mutable.Variant;
+import org.simantics.databoard.binding.util.DefaultValue;
+import org.simantics.databoard.binding.util.RandomValue;
+import org.simantics.databoard.parser.DataParser;
+import org.simantics.databoard.parser.DataValuePrinter;
+import org.simantics.databoard.parser.ParseException;
+import org.simantics.databoard.parser.PrintFormat;
+import org.simantics.databoard.parser.repository.DataTypeSyntaxError;
+import org.simantics.databoard.parser.repository.DataValueRepository;
+import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;
+import org.simantics.databoard.serialization.Serializer;
+import org.simantics.databoard.serialization.SerializerFactory;
+import org.simantics.databoard.serialization.SerializerScheme;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.util.IdentityPair;
+
+/**
+ * This class represents connection between abstract datatype and java class.
+ * A binding allows an access to an Object in scope of a datatype. <p>
+ *
+ * For example, IntegerBinding gives unified access to any integer class
+ * (Integer, int, MutableInteger, UnsignedInteger). There is same unification
+ * for primitive types and constructed types (record, map, array, union, variant). <p>
+ *
+ * You can get a hold of binding several ways:
+ * 1) Use one of the default bindings e.g. {@link Bindings#BYTE_ARRAY}
+ * 2) Create one using Datatype {@link Bindings#getMutableBinding(Datatype)}
+ * 3) Create one using Reflectiong {@link Bindings#getBinding(Class)}
+ * 4) Instantiate binding your self. e.g. new TreeMapBinding( Bindings.STRING, Bindings.STRING );
+ * 5) Sub-class one of the abstract binding classes
+ * @see BooleanBinding
+ * @see ByteBinding
+ * @see IntegerBinding
+ * @see LongBinding
+ * @see FloatBinding
+ * @see DoubleBinding
+ * @see StringBinding
+ * @see RecordBinding
+ * @see ArrayBinding
+ * @see MapBinding
+ * @see OptionalBinding
+ * @see UnionBinding
+ * @see VariantBinding
+ *
+ * See examples/BindingExample.java
+ * @see Bindings Facade class Bindings provices extra functionality.
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
* @author Hannu Niemisto
*/
public abstract class Binding implements Comparator<Object> {
protected Datatype type;
- protected transient Serializer binarySerializer;\r
+ protected transient Serializer binarySerializer;
/**
* Get Value Type
}
public abstract <T> T accept(Visitor<T> v);
- \r
- /**\r
- * Absolutely for databoard-internal use only. Used in caching serializers\r
- * constructed by {@link SerializerFactory}.\r
- * \r
- * @return the serializer that has been cached in this Binding instance or\r
- * <code>null</code> if nothing is cached yet\r
- * @since Simantics 1.15.1\r
- */\r
- public Serializer cachedSerializer() {\r
- return binarySerializer;\r
- }\r
-\r
- /**\r
- * Absolutely for databoard-internal use only. Used in caching serializers\r
- * constructed by {@link SerializerFactory}.\r
- * \r
- * @param serializer the cached serializer to set for this binding\r
- * @since Simantics 1.15.1\r
- */\r
- public void cacheSerializer(Serializer serializer) {\r
- this.binarySerializer = serializer;\r
- }\r
+
+ /**
+ * Absolutely for databoard-internal use only. Used in caching serializers
+ * constructed by {@link SerializerFactory}.
+ *
+ * @return the serializer that has been cached in this Binding instance or
+ * <code>null</code> if nothing is cached yet
+ * @since Simantics 1.15.1
+ */
+ public Serializer cachedSerializer() {
+ return binarySerializer;
+ }
+
+ /**
+ * Absolutely for databoard-internal use only. Used in caching serializers
+ * constructed by {@link SerializerFactory}.
+ *
+ * @param serializer the cached serializer to set for this binding
+ * @since Simantics 1.15.1
+ */
+ public void cacheSerializer(Serializer serializer) {
+ this.binarySerializer = serializer;
+ }
/**
* Get or create default serializer.
*
* <a href="http://dev.simantics.org/index.php/Org.simantics.databoard_Manual#Binary_Serialization">Binary Serialization format</a>
*
- * @return serializer for this binding\r
+ * @return serializer for this binding
* @deprecated Instead use {@link Bindings#getSerializerUnchecked(Binding)} or {@link SerializerScheme#getSerializerUnchecked(Binding)}
- */\r
+ */
@Deprecated
public Serializer serializer()
throws RuntimeSerializerConstructionException
- { \r
- //return Bindings.serializationFactory.getSerializerUnchecked(this);\r
+ {
+ //return Bindings.serializationFactory.getSerializerUnchecked(this);
if (binarySerializer==null) {
synchronized (this) {
- if (binarySerializer==null) binarySerializer = Bindings.serializationFactory.getSerializerUnchecked(this);\r
- }\r
+ if (binarySerializer==null) binarySerializer = Bindings.serializationFactory.getSerializerUnchecked(this);
+ }
}
- return binarySerializer;\r
+ return binarySerializer;
}
public abstract boolean isInstance(Object obj);
*/
public boolean isImmutable() {
return false;
- }\r
- \r
- /**\r
- * Read values from one object to another.\r
- * \r
- * @param srcBinding\r
- * @param src\r
- * @param dst valid object of this binding\r
- * @throws BindingException\r
- */\r
+ }
+
+ /**
+ * Read values from one object to another.
+ *
+ * @param srcBinding
+ * @param src
+ * @param dst valid object of this binding
+ * @throws BindingException
+ */
public abstract void readFrom(Binding srcBinding, Object src, Object dst) throws BindingException;
- \r
- /**\r
- * Read values from another object.\r
- * \r
- * @param srcBinding\r
- * @param src\r
- * @param dst valid object of this binding\r
- * @throws RuntimeBindingException\r
- */\r
- public void readFromUnchecked(Binding srcBinding, Object src, Object dst) throws RuntimeBindingException\r
- {\r
- try {\r
- readFrom(srcBinding, src, dst);\r
- } catch (BindingException e) {\r
- throw new RuntimeBindingException( e );\r
- }\r
- }\r
- \r
- /**\r
- * Read values from one object to another.\r
- * \r
- * @param srcBinding\r
- * @param src\r
- * @param dst valid object of this binding\r
- * @return dst or new instance if could not be read to dst\r
- * @throws BindingException\r
- */\r
- public Object readFromTry(Binding srcBinding, Object src, Object dst) throws BindingException\r
- {\r
- readFrom(srcBinding, src, dst);\r
- return dst;\r
- }\r
- public Object readFromTryUnchecked(Binding srcBinding, Object src, Object dst) throws BindingException\r
- {\r
- try {\r
- return readFromTry(srcBinding, src, dst);\r
- } catch (BindingException e) {\r
- throw new RuntimeBindingException( e );\r
- }\r
- }\r
+
+ /**
+ * Read values from another object.
+ *
+ * @param srcBinding
+ * @param src
+ * @param dst valid object of this binding
+ * @throws RuntimeBindingException
+ */
+ public void readFromUnchecked(Binding srcBinding, Object src, Object dst) throws RuntimeBindingException
+ {
+ try {
+ readFrom(srcBinding, src, dst);
+ } catch (BindingException e) {
+ throw new RuntimeBindingException( e );
+ }
+ }
+
+ /**
+ * Read values from one object to another.
+ *
+ * @param srcBinding
+ * @param src
+ * @param dst valid object of this binding
+ * @return dst or new instance if could not be read to dst
+ * @throws BindingException
+ */
+ public Object readFromTry(Binding srcBinding, Object src, Object dst) throws BindingException
+ {
+ readFrom(srcBinding, src, dst);
+ return dst;
+ }
+ public Object readFromTryUnchecked(Binding srcBinding, Object src, Object dst) throws BindingException
+ {
+ try {
+ return readFromTry(srcBinding, src, dst);
+ } catch (BindingException e) {
+ throw new RuntimeBindingException( e );
+ }
+ }
/**
* Assert the obj is valid data type
public String printValueDefinition(Object value, boolean singleLine) throws IOException, BindingException
{
DataValueRepository valueRepository = new DataValueRepository();
- valueRepository.put("value", this, value);\r
- StringBuilder sb = new StringBuilder();\r
- DataValuePrinter vp = new DataValuePrinter(sb, valueRepository);\r
- vp.setFormat( PrintFormat.MULTI_LINE );\r
- vp.print(this, value);\r
- return sb.toString();\r
+ valueRepository.put("value", this, value);
+ StringBuilder sb = new StringBuilder();
+ DataValuePrinter vp = new DataValuePrinter(sb, valueRepository);
+ vp.setFormat( PrintFormat.MULTI_LINE );
+ vp.print(this, value);
+ return sb.toString();
}
/**
* first argument is less than, equal to, or greater than the
* second.
* @throws BindingException if object cannot be handled by a binding
- */ \r
+ */
@Override
public int compare(Object o1, Object o2)
throws RuntimeBindingException
return accept(new DefaultValue());
}
- /**\r
- * Create random valid value.\r
- * \r
- * @param seed random seed\r
- * @return random value\r
- * @throws BindingException\r
- */\r
- public Object createRandom(int seed) \r
- throws BindingException\r
- {\r
- try {\r
- return accept(new RandomValue( seed ));\r
- } catch (RuntimeBindingException e) {\r
- throw e.getCause();\r
- }\r
- }\r
- \r
- /**\r
- * Create random valid value.\r
- * \r
- * @param rv random seed\r
- * @return random value\r
- * @throws BindingException\r
- */\r
- public Object createRandom(RandomValue rv) \r
- throws BindingException\r
- {\r
- try {\r
- return accept(rv);\r
- } catch (RuntimeBindingException e) {\r
- throw e.getCause();\r
- }\r
- }\r
- \r
- /**\r
- * Create random valid value.\r
- * \r
- * @param random random seed\r
- * @return random value\r
- * @throws BindingException\r
- */\r
- public Object createRandom(Random random) \r
- throws BindingException\r
- {\r
- try {\r
- return accept(new RandomValue( random ));\r
- } catch (RuntimeBindingException e) {\r
- throw e.getCause();\r
- }\r
- }\r
+ /**
+ * Create random valid value.
+ *
+ * @param seed random seed
+ * @return random value
+ * @throws BindingException
+ */
+ public Object createRandom(int seed)
+ throws BindingException
+ {
+ try {
+ return accept(new RandomValue( seed ));
+ } catch (RuntimeBindingException e) {
+ throw e.getCause();
+ }
+ }
+
+ /**
+ * Create random valid value.
+ *
+ * @param rv random seed
+ * @return random value
+ * @throws BindingException
+ */
+ public Object createRandom(RandomValue rv)
+ throws BindingException
+ {
+ try {
+ return accept(rv);
+ } catch (RuntimeBindingException e) {
+ throw e.getCause();
+ }
+ }
+
+ /**
+ * Create random valid value.
+ *
+ * @param random random seed
+ * @return random value
+ * @throws BindingException
+ */
+ public Object createRandom(Random random)
+ throws BindingException
+ {
+ try {
+ return accept(new RandomValue( random ));
+ } catch (RuntimeBindingException e) {
+ throw e.getCause();
+ }
+ }
public Object createRandomUnchecked(int seed)
throws RuntimeBindingException
{
return accept(new RandomValue( seed ));
- }\r
- \r
- public String toString(Object value) throws BindingException {\r
- BindingPrintContext ctx = new BindingPrintContext();\r
- toString(value, ctx);\r
- return ctx.b.toString();\r
- }\r
-\r
- public String toStringUnchecked(Object value) {\r
- try {\r
- BindingPrintContext ctx = new BindingPrintContext();\r
- toString(value, ctx);\r
- return ctx.b.toString();\r
- } catch ( BindingException e ) {\r
- return e.toString();\r
- }\r
- }\r
- \r
- public String toString(Object value, boolean singleLine) throws BindingException {\r
- BindingPrintContext ctx = new BindingPrintContext();\r
- ctx.singleLine = singleLine;\r
- toString(value, ctx);\r
- return ctx.b.toString();\r
- }\r
-\r
- protected abstract void toString(Object value, BindingPrintContext ctx) throws BindingException;\r
- \r
- \r
- /** \r
- * Get component binding count\r
- * \r
- * @return component count\r
- */\r
- public abstract int getComponentCount();\r
- \r
- /**\r
- * Get a component value of a structured data object.\r
- * @param object The structured data object\r
- * @param ref The child component reference\r
- * @return The value of the data component\r
- * @throws BindingException\r
- */\r
- public Object getComponent(Object object, ChildReference ref) throws BindingException {\r
- Variant value = new MutableVariant(this, object);\r
- try {\r
- return value.getComponent(ref).getValue();\r
- } catch ( AccessorConstructionException e ) {\r
- throw new BindingException("Component access failed.", e);\r
- }\r
- }\r
- \r
- /**\r
- * Get a component value of a structured data object.\r
- * @param object The structured data object\r
- * @param ref The child component reference\r
- * @param binding The output data binding for the component value\r
- * @return The value of the data component\r
- * @throws BindingException\r
- */\r
- public Object getComponent(Object object, ChildReference ref, Binding binding) throws BindingException {\r
- Binding componentBinding = getComponentBinding( ref );\r
- Variant value = new MutableVariant(this, object);\r
- try {\r
- return Bindings.adapt( value.getComponent( ref ), componentBinding, binding );\r
- } catch ( AdaptException | AccessorConstructionException e ) {\r
- throw new BindingException("Component access failed.", e);\r
- }\r
- }\r
- \r
- /**\r
- * Set the value of a component in a structured data object.\r
- * @param object The structured data object\r
- * @param ref The child component reference\r
- * @param binding Data type binding for the component value\r
- * @param componentValue The new child component value\r
- * @throws BindingException\r
- */\r
- public void setComponent( Object object, ChildReference ref, Binding binding, Object componentValue ) throws BindingException {\r
- MutableVariant value = new MutableVariant( this, object );\r
- try {\r
- value.setComponent( ref, binding, componentValue );\r
- } catch ( AccessorException | AccessorConstructionException e ) {\r
- throw new BindingException("Component access failed.", e );\r
- }\r
- }\r
- \r
- /**\r
- * Get component binding\r
- * @param index\r
- * @return binding\r
- */\r
- public abstract Binding getComponentBinding(int index);\r
- \r
- /**\r
- * Get component binding\r
- * @param path child path or <tt>null</tt> to return this.\r
- * @return binding \r
- * @throws IllegalArgumentException if path cannot be applied to this binding\r
- */\r
- public abstract Binding getComponentBinding(ChildReference path);\r
- \r
- @Override\r
- /**\r
- * Each child class implements #deepEquals or #baseEquals or neither, depending on\r
- * whether it includes references to child Binding instances or other fields.\r
- * @see java.lang.Object#equals(java.lang.Object)\r
- */\r
- final public boolean equals(Object obj) {\r
- if (this == obj) return true;\r
- if (obj == null) return false;\r
- if (this.getClass() != obj.getClass()) return false;\r
- \r
- return equals(obj, new HashSet<IdentityPair<Binding, Binding>>());\r
- }\r
- \r
- /**\r
- * Perform a deep equality check between this Binding object and another,\r
- * with a memory for recursive references. Child classes should implement either the\r
- * #deepEquals or #baseEquals method, or neither if there is no new data to compare.\r
- */\r
- final protected boolean equals(Object obj, Set<IdentityPair<Binding, Binding>> compareHistory) {\r
- if (this == obj) return true;\r
- if (this.getClass() != obj.getClass()) return false;\r
- \r
- IdentityPair<Binding, Binding> pair = new IdentityPair<Binding, Binding>(this, (Binding)obj); \r
- if (compareHistory.contains(pair)) return true;\r
- \r
- compareHistory.add(pair);\r
- return deepEquals(obj, compareHistory);\r
- }\r
- \r
- /**\r
- * Perform a comparison of the fields of this Binding instance. Always make a call to super.baseEquals().\r
- */\r
- protected boolean baseEquals(Object obj) {\r
- return type == null ? ((Binding)obj).type == null : type.equals(((Binding)obj).type);\r
- }\r
- \r
- /**\r
- * Perform a deep comparison of this Binding object with another.\r
- * Matching child Binding instances must be compared with #equals(Object, Set<IdentityPair<Binding, Binding>>).\r
- * Child classes should always make a call to super.deepEquals().\r
- */\r
- protected boolean deepEquals(Object obj, Set<IdentityPair<Binding, Binding>> compareHistory) {\r
- return baseEquals(obj);\r
- }\r
- \r
- @Override\r
- /**\r
- * Each child class implements #deepHashCode, #baseHashCode or neither, depending on whether it\r
- * includes child Binding references or other fields.\r
- */\r
- final public int hashCode() {\r
- return deepHashCode(new IdentityHashMap<Object,Object>());\r
- }\r
- \r
- /**\r
- * Calculate a deep hash code for this Binding instance.\r
- * Child classes should implement either deepHashCode or baseHashCode, or neither, if there is no new data.\r
- */\r
- final protected int hashCode(IdentityHashMap<Object, Object> hashedObjects) {\r
- if (hashedObjects.containsKey(this)) return 0;\r
- hashedObjects.put(this, null);\r
- return deepHashCode(hashedObjects);\r
- }\r
- \r
- /**\r
- * Calculate a hash code based on the fields of this Binding instance. Child classes must always make a call to super.baseHashCode(). \r
- */\r
- protected int baseHashCode() {\r
- return getClass().hashCode() + (type != null ? 3 * type.hashCode() : 0);\r
- }\r
- \r
- /**\r
- * Perform deep hash code calculation for this Binding instance.\r
- * Child instance hash codes must be calculated with #hashCode(IdentityHashMap<Object, Object>),\r
- * passing on the value provided to #deepHashCode.\r
- */\r
- protected int deepHashCode(IdentityHashMap<Object, Object> hashedObjects) {\r
- return baseHashCode();\r
- }\r
-}\r
+ }
+
+ public String toString(Object value) throws BindingException {
+ BindingPrintContext ctx = new BindingPrintContext();
+ toString(value, ctx);
+ return ctx.b.toString();
+ }
+
+ public String toStringUnchecked(Object value) {
+ try {
+ BindingPrintContext ctx = new BindingPrintContext();
+ toString(value, ctx);
+ return ctx.b.toString();
+ } catch ( BindingException e ) {
+ return e.toString();
+ }
+ }
+
+ public String toString(Object value, boolean singleLine) throws BindingException {
+ BindingPrintContext ctx = new BindingPrintContext();
+ ctx.singleLine = singleLine;
+ toString(value, ctx);
+ return ctx.b.toString();
+ }
+
+ protected abstract void toString(Object value, BindingPrintContext ctx) throws BindingException;
+
+
+ /**
+ * Get component binding count
+ *
+ * @return component count
+ */
+ public abstract int getComponentCount();
+
+ /**
+ * Get a component value of a structured data object.
+ * @param object The structured data object
+ * @param ref The child component reference
+ * @return The value of the data component
+ * @throws BindingException
+ */
+ public Object getComponent(Object object, ChildReference ref) throws BindingException {
+ Variant value = new MutableVariant(this, object);
+ try {
+ return value.getComponent(ref).getValue();
+ } catch ( AccessorConstructionException e ) {
+ throw new BindingException("Component access failed.", e);
+ }
+ }
+
+ /**
+ * Get a component value of a structured data object.
+ * @param object The structured data object
+ * @param ref The child component reference
+ * @param binding The output data binding for the component value
+ * @return The value of the data component
+ * @throws BindingException
+ */
+ public Object getComponent(Object object, ChildReference ref, Binding binding) throws BindingException {
+ Binding componentBinding = getComponentBinding( ref );
+ Variant value = new MutableVariant(this, object);
+ try {
+ return Bindings.adapt( value.getComponent( ref ), componentBinding, binding );
+ } catch ( AdaptException | AccessorConstructionException e ) {
+ throw new BindingException("Component access failed.", e);
+ }
+ }
+
+ /**
+ * Set the value of a component in a structured data object.
+ * @param object The structured data object
+ * @param ref The child component reference
+ * @param binding Data type binding for the component value
+ * @param componentValue The new child component value
+ * @throws BindingException
+ */
+ public void setComponent( Object object, ChildReference ref, Binding binding, Object componentValue ) throws BindingException {
+ MutableVariant value = new MutableVariant( this, object );
+ try {
+ value.setComponent( ref, binding, componentValue );
+ } catch ( AccessorException | AccessorConstructionException e ) {
+ throw new BindingException("Component access failed.", e );
+ }
+ }
+
+ /**
+ * Get component binding
+ * @param index
+ * @return binding
+ */
+ public abstract Binding getComponentBinding(int index);
+
+ /**
+ * Get component binding
+ * @param path child path or <tt>null</tt> to return this.
+ * @return binding
+ * @throws IllegalArgumentException if path cannot be applied to this binding
+ */
+ public abstract Binding getComponentBinding(ChildReference path);
+
+ @Override
+ /**
+ * Each child class implements #deepEquals or #baseEquals or neither, depending on
+ * whether it includes references to child Binding instances or other fields.
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ final public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (this.getClass() != obj.getClass()) return false;
+
+ return equals(obj, new HashSet<IdentityPair<Binding, Binding>>());
+ }
+
+ /**
+ * Perform a deep equality check between this Binding object and another,
+ * with a memory for recursive references. Child classes should implement either the
+ * #deepEquals or #baseEquals method, or neither if there is no new data to compare.
+ */
+ final protected boolean equals(Object obj, Set<IdentityPair<Binding, Binding>> compareHistory) {
+ if (this == obj) return true;
+ if (this.getClass() != obj.getClass()) return false;
+
+ IdentityPair<Binding, Binding> pair = new IdentityPair<Binding, Binding>(this, (Binding)obj);
+ if (compareHistory.contains(pair)) return true;
+
+ compareHistory.add(pair);
+ return deepEquals(obj, compareHistory);
+ }
+
+ /**
+ * Perform a comparison of the fields of this Binding instance. Always make a call to super.baseEquals().
+ */
+ protected boolean baseEquals(Object obj) {
+ return type == null ? ((Binding)obj).type == null : type.equals(((Binding)obj).type);
+ }
+
+ /**
+ * Perform a deep comparison of this Binding object with another.
+ * Matching child Binding instances must be compared with #equals(Object, Set<IdentityPair<Binding, Binding>>).
+ * Child classes should always make a call to super.deepEquals().
+ */
+ protected boolean deepEquals(Object obj, Set<IdentityPair<Binding, Binding>> compareHistory) {
+ return baseEquals(obj);
+ }
+
+ @Override
+ /**
+ * Each child class implements #deepHashCode, #baseHashCode or neither, depending on whether it
+ * includes child Binding references or other fields.
+ */
+ final public int hashCode() {
+ return deepHashCode(new IdentityHashMap<Object,Object>());
+ }
+
+ /**
+ * Calculate a deep hash code for this Binding instance.
+ * Child classes should implement either deepHashCode or baseHashCode, or neither, if there is no new data.
+ */
+ final protected int hashCode(IdentityHashMap<Object, Object> hashedObjects) {
+ if (hashedObjects.containsKey(this)) return 0;
+ hashedObjects.put(this, null);
+ return deepHashCode(hashedObjects);
+ }
+
+ /**
+ * Calculate a hash code based on the fields of this Binding instance. Child classes must always make a call to super.baseHashCode().
+ */
+ protected int baseHashCode() {
+ return getClass().hashCode() + (type != null ? 3 * type.hashCode() : 0);
+ }
+
+ /**
+ * Perform deep hash code calculation for this Binding instance.
+ * Child instance hash codes must be calculated with #hashCode(IdentityHashMap<Object, Object>),
+ * passing on the value provided to #deepHashCode.
+ */
+ protected int deepHashCode(IdentityHashMap<Object, Object> hashedObjects) {
+ return baseHashCode();
+ }
+}