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