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.binding.mutable;
\r
14 import java.io.IOException;
\r
16 import org.simantics.databoard.Accessors;
\r
17 import org.simantics.databoard.Bindings;
\r
18 import org.simantics.databoard.accessor.VariantAccessor;
\r
19 import org.simantics.databoard.accessor.error.AccessorConstructionException;
\r
20 import org.simantics.databoard.accessor.java.JavaObject;
\r
21 import org.simantics.databoard.accessor.reference.ChildReference;
\r
22 import org.simantics.databoard.adapter.AdaptException;
\r
23 import org.simantics.databoard.binding.Binding;
\r
24 import org.simantics.databoard.binding.error.BindingException;
\r
25 import org.simantics.databoard.binding.error.RuntimeBindingException;
\r
26 import org.simantics.databoard.binding.reflection.VoidBinding;
\r
27 import org.simantics.databoard.parser.DataValuePrinter;
\r
28 import org.simantics.databoard.parser.PrintFormat;
\r
29 import org.simantics.databoard.parser.repository.DataValueRepository;
\r
30 import org.simantics.databoard.parser.unparsing.DataTypePrinter;
\r
31 import org.simantics.databoard.type.Datatype;
\r
34 * Variant is a container to a data value of any type.
\r
35 * This very class is immutable, the value and type cannot be changed, but the
\r
36 * sub-class {@link MutableVariant} is not. <p>
\r
38 * Variant is hash-equals-comparable, even variants of bindings (and types).
\r
39 * The hash function and comparison rules are defined in the manual. <p>
\r
41 * @see ImmutableVariantBinding is binding for Variant-class
\r
42 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
\r
44 public class Variant implements Comparable<Variant>, Cloneable {
\r
46 public static Variant ofInstance(Object instance) {
\r
47 Binding binding = Bindings.getBindingUnchecked( instance.getClass() );
\r
48 return new Variant(binding, instance);
\r
55 * Constract a variant with a default value of empty record {}
\r
58 binding = VoidBinding.VOID_BINDING;
\r
62 public Variant(Variant v) {
\r
63 //assert(isValid(binding, value));
\r
64 this.binding = v.getBinding();
\r
65 this.value = v.getValue();
\r
68 public Variant(Binding binding, Object value) {
\r
69 //assert(isValid(binding, value));
\r
70 this.binding = binding;
\r
74 public Object getValue() {
\r
79 * Get and if necessary and possible, type-adapt the value.
\r
82 * @return the value in given binding
\r
83 * @throws AdaptException
\r
85 public Object getValue(Binding binding) throws AdaptException {
\r
86 return Bindings.adapt(value, this.binding, binding);
\r
89 public VariantAccessor getAccessor() {
\r
91 return (VariantAccessor) Accessors.getAccessor( Bindings.VARIANT, this);
\r
92 } catch (AccessorConstructionException e) {
\r
94 throw new RuntimeException(e);
\r
98 public Datatype type() {
\r
99 return binding.type();
\r
102 public Binding getBinding() {
\r
107 public int hashCode() {
\r
109 return binding.hashValue(value);
\r
110 } catch (BindingException e) {
\r
111 throw new RuntimeBindingException(e);
\r
116 public boolean equals(Object obj) {
\r
121 if(!(obj instanceof Variant))
\r
124 Variant o = (Variant) obj;
\r
125 if (o.binding==binding && o.value == value) return true;
\r
126 return Bindings.equals(binding, value, o.binding, o.value);
\r
127 } catch (BindingException e) {
\r
128 throw new RuntimeBindingException(e);
\r
132 public boolean valueEquals(Binding binding, Object obj)
\r
134 if (this.binding == binding) return binding.equals(obj, this.value);
\r
137 adapted = Bindings.adapt(obj, binding, this.binding);
\r
138 return this.binding.equals(adapted, this.value);
\r
139 } catch (AdaptException e) {
\r
145 public int compareTo(Variant o) {
\r
147 if (o.binding==binding && o.value == value) return 0;
\r
148 return Bindings.compare(binding, value, o.binding, o.value);
\r
149 } catch (BindingException e) {
\r
150 throw new RuntimeBindingException(e);
\r
155 public String toString() {
\r
157 StringBuilder sb = new StringBuilder();
\r
158 DataValueRepository repo = new DataValueRepository();
\r
159 DataValuePrinter printer = new DataValuePrinter(sb, repo);
\r
160 printer.setFormat(PrintFormat.SINGLE_LINE);
\r
161 printer.print(binding, value);
\r
163 DataTypePrinter printer2 = new DataTypePrinter(sb);
\r
164 printer2.print(binding.type());
\r
165 return sb.toString();
\r
166 } catch (IOException e) {
\r
167 throw new RuntimeException(e);
\r
168 } catch (BindingException e) {
\r
169 throw new RuntimeBindingException(e);
\r
173 public Variant clone() {
\r
174 if (binding.isImmutable()) return new Variant(binding, value);
\r
175 Object newValue = Bindings.cloneUnchecked(value, binding, binding);
\r
176 return new Variant(binding, newValue);
\r
179 boolean isValid(Binding binding, Object obj) throws RuntimeBindingException {
\r
181 binding.assertInstaceIsValid(obj);
\r
183 } catch (BindingException e) {
\r
184 throw new RuntimeBindingException(e);
\r
190 * Open a variant to a component object.
\r
192 * @param ref child reference, if null then this object is returned
\r
193 * @return variant to this or new variant that refers to actual child object
\r
194 * @throws AccessorConstructionException
\r
196 public Variant getComponent(ChildReference ref) throws AccessorConstructionException {
\r
197 if ( ref == null ) return this;
\r
198 JavaObject jo = (JavaObject) Accessors.getAccessor(this, ref);
\r
199 return new Variant( jo.getBinding(), jo.getObject() );
\r