]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/UnionClassBinding.java
Fixing several binding-related bugs
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / reflection / UnionClassBinding.java
1 /*******************************************************************************
2  *  Copyright (c) 2010 Association for Decentralized Information Management in
3  *  Industry THTH ry.
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
8  *
9  *  Contributors:
10  *      VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard.binding.reflection;
13
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;
23
24 /**
25  * Bindings an abstract class with @Union annotation to a DataBoard's UnionType.
26  * 
27  * Example of usage:
28  *  @Union({Rectangle.class, Circle.class, Triangle.class}) class Shape {}
29  *      
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; }             
33  *
34  * @author Toni Kalajainen
35  */
36 class UnionClassBinding extends UnionBinding implements SpecializedSerializerProvider {
37
38         Class<?>[] componentClasses;
39         Serializer specializedSerializer;
40         
41         public UnionClassBinding(UnionType type) 
42         throws BindingConstructionException {
43                 this.type = type;
44         }
45         
46         @Override
47         public Object create(int tag, Object value) {
48                 return value;
49         }
50
51     @Override
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);
57     }
58         
59         @Override
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");
64         }
65         @Override
66         public Object getValue(Object obj) {
67                 return obj;
68         }
69         @Override
70         public boolean isInstance(Object obj) {
71                 for (Class<?> c : componentClasses) 
72                         if (c.isInstance(obj)) return true;                                     
73                 return false;
74         }
75
76     @Override
77     public Serializer getSpecializedSerializer() {
78         return specializedSerializer;
79     }
80
81
82         transient Boolean isImmutable;
83         
84         @Override
85         public synchronized boolean isImmutable() {
86                 if ( isImmutable == null ) {
87                         boolean b = true;
88                         for ( Binding cb : getComponentBindings() ) {
89                                 b &= cb.isImmutable();
90                                 if (!b) break;
91                         }
92                         isImmutable = b;
93                 }
94                 return isImmutable;
95         }
96
97         @Override
98     public Object readFromTry(Binding srcBinding, Object src, Object dst) throws BindingException
99     {
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);
105                 
106                 
107                 if (st==dt) {
108                         // Same Tag
109                         Object dv = getValue(dst);
110                         Binding dcb = getComponentBinding(dt);
111                         dcb.readFrom(scb, sv, dv);
112                         return dv;
113                 } else {
114                         // Different Tag -> return cloned or (same, if immutable) value
115                         try {
116                                 Binding dcb = getComponentBinding(st);
117                                 return Bindings.adapt(src, scb, dcb);
118                         } catch(AdaptException e) {
119                                 throw new BindingException(e);
120                         }
121                 }
122                 
123         }       
124         
125         /**
126          * Returns true if the tag of this union type can be modified
127          *  
128          * @return
129          */
130         public boolean isTagMutable() {
131                 return true;
132         }
133  
134         @Override
135         protected boolean baseEquals(Object obj) {
136                 if (!super.baseEquals(obj)) return false;       
137
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;
142                 
143                 for (int i = 0; i < componentClasses.length; i++) {
144                         if (!componentClasses[i].equals(o.componentClasses[i]))
145                                 return false;
146                 }
147                 
148                 return true;
149         }
150         
151         @Override
152         public int baseHashCode() {
153                 int code = super.baseHashCode();
154                 for (int i = 0; i < componentClasses.length; i++)
155                         code = 23 * code + componentClasses.hashCode();
156                 
157                 return code;
158         }
159 }