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.reflection;
14 import org.simantics.databoard.Bindings;
15 import org.simantics.databoard.adapter.AdaptException;
16 import org.simantics.databoard.binding.Binding;
17 import org.simantics.databoard.binding.UnionBinding;
18 import org.simantics.databoard.binding.error.BindingConstructionException;
19 import org.simantics.databoard.binding.error.BindingException;
20 import org.simantics.databoard.serialization.Serializer;
21 import org.simantics.databoard.serialization.SpecializedSerializerProvider;
22 import org.simantics.databoard.type.UnionType;
25 * Bindings an abstract class with @Union annotation to a DataBoard's UnionType.
28 * @Union({Rectangle.class, Circle.class, Triangle.class}) class Shape {}
30 * class Rectangle extends Shape { public int width, height; }
31 * class Circle extends Shape { public int radius; }
32 * class Triangle extends Shape { public int sideLength; }
34 * @author Toni Kalajainen
36 class UnionClassBinding extends UnionBinding implements SpecializedSerializerProvider {
38 Class<?>[] componentClasses;
39 Serializer specializedSerializer;
41 public UnionClassBinding(UnionType type)
42 throws BindingConstructionException {
47 public Object create(int tag, Object value) {
52 public void setValue(Object union, int tag, Object value)
53 throws BindingException {
54 if (tag != getTag(union)) throw new BindingException("Cannot change the class of an instance");
55 Binding cb = getComponentBinding(tag);
56 cb.readFrom(cb, value, union);
60 public int getTag(Object obj) throws BindingException {
61 for (int i=0; i<componentClasses.length; i++)
62 if (componentClasses[i].isInstance(obj)) return i;
63 throw new BindingException(obj.getClass().getSimpleName()+" is not a known component class");
66 public Object getValue(Object obj) {
70 public boolean isInstance(Object obj) {
71 for (Class<?> c : componentClasses)
72 if (c.isInstance(obj)) return true;
77 public Serializer getSpecializedSerializer() {
78 return specializedSerializer;
82 transient Boolean isImmutable;
85 public synchronized boolean isImmutable() {
86 if ( isImmutable == null ) {
88 for ( Binding cb : getComponentBindings() ) {
89 b &= cb.isImmutable();
98 public Object readFromTry(Binding srcBinding, Object src, Object dst) throws BindingException
100 UnionBinding sb = (UnionBinding) srcBinding;
101 int st = sb.getTag(src);
102 int dt = getTag(dst);
103 Binding scb = sb.getComponentBinding(st);
104 Object sv = sb.getValue(src);
109 Object dv = getValue(dst);
110 Binding dcb = getComponentBinding(dt);
111 dcb.readFrom(scb, sv, dv);
114 // Different Tag -> return cloned or (same, if immutable) value
116 Binding dcb = getComponentBinding(st);
117 return Bindings.adapt(src, scb, dcb);
118 } catch(AdaptException e) {
119 throw new BindingException(e);
126 * Returns true if the tag of this union type can be modified
130 public boolean isTagMutable() {
135 protected boolean baseEquals(Object obj) {
136 if (!super.baseEquals(obj)) return false;
138 UnionClassBinding o = (UnionClassBinding)obj;
139 if (isImmutable != o.isImmutable) return false;
140 if (specializedSerializer != o.specializedSerializer) return false;
141 if (componentClasses.length != o.componentClasses.length) return false;
143 for (int i = 0; i < componentClasses.length; i++) {
144 if (!componentClasses[i].equals(o.componentClasses[i]))
152 public int baseHashCode() {
153 int code = super.baseHashCode();
154 for (int i = 0; i < componentClasses.length; i++)
155 code = 23 * code + componentClasses.hashCode();