]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/RecordClassBinding.java
Fixing several binding-related bugs
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / reflection / RecordClassBinding.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 java.lang.reflect.Field;
15 import java.lang.reflect.InvocationTargetException;
16 import java.lang.reflect.Method;
17 import java.lang.reflect.Modifier;
18 import java.lang.reflect.Type;
19
20 import org.simantics.databoard.binding.Binding;
21 import org.simantics.databoard.binding.BooleanBinding;
22 import org.simantics.databoard.binding.ByteBinding;
23 import org.simantics.databoard.binding.DoubleBinding;
24 import org.simantics.databoard.binding.FloatBinding;
25 import org.simantics.databoard.binding.IntegerBinding;
26 import org.simantics.databoard.binding.LongBinding;
27 import org.simantics.databoard.binding.error.BindingConstructionException;
28 import org.simantics.databoard.binding.error.BindingException;
29 import org.simantics.databoard.type.RecordType;
30
31 /**
32  * ReflectionRecordBinding binding of a Record Type and Java Class.
33  * If binds Record Values to Java Objects. <p>
34  *  
35  * 
36  * There are three types of classes supported:
37  *  1) record-like class 
38  *     - All fields are public
39  *     - No-argument public constructor
40  *     
41  *  2) immutable-like class
42  *     - All fields are set in constructor
43  * 
44  *  3) bean-like class
45  *     - All fields are set with getter/setter
46  */
47 class RecordClassBinding extends ClassBinding {
48
49         private static final Object[] NO_ARGS = new Object[0];  
50         
51         /**
52          * Create a Reflection Record Bindings. 
53          * 
54          * There is a 2-phase construction.
55          * 
56          * @param ci
57          * @param type
58          * @throws BindingConstructionException
59          */
60         public RecordClassBinding(ClassInfo ci, RecordType type)
61         {
62                 super(ci);
63                 if ( ci == null ) throw new IllegalArgumentException("null ClassInfo");
64                 this.type = type;
65         componentBindings = new Binding[ ci.fields.length ];            
66         }
67         
68         @Override
69         public Object createPartial() throws BindingException {
70                 try {
71                         if (ci.noArgsConstructor!=null)
72                                 return ci.noArgsConstructor.newInstance();
73                         else if (ci.argsConstructor!=null) {
74                                 
75                                 // Create default values 
76                                 Object values[] = new Object[ci.fields.length];
77                                 for (int i=0; i<values.length; i++) {
78                                         Binding fb = componentBindings[i];
79                                         values[i] = fb.createDefault();
80                                 }                               
81                                 return ci.argsConstructor.newInstance((Object[])values);
82 //                              return clazz.newInstance();
83                         } else throw new BindingException("Class "+ci.clazz.getName()+" doesn't support construction. No no-args or args(fields) constructor.");
84                 } catch (InstantiationException e) {
85                         throw new BindingException(e);
86                 } catch (IllegalAccessException e) {
87                         throw new BindingException(e);
88                 } catch (IllegalArgumentException e) {
89                         throw new BindingException(e);
90                 } catch (InvocationTargetException e) {
91                         throw new BindingException(e.getCause());
92                 }
93         }
94
95         @Override
96         public Object create(Object... values) 
97         throws BindingException {
98
99                 // Case 2
100                 if (ci.argsConstructor != null) 
101                 {
102                         try {
103                                 return ci.argsConstructor.newInstance(values);
104                         } catch (IllegalArgumentException e) {
105                     throw new BindingException(e);
106                         } catch (InstantiationException e) {
107                     throw new BindingException(e);
108                         } catch (IllegalAccessException e) {
109                     throw new BindingException(e);
110                         } catch (InvocationTargetException e) {
111                     throw new BindingException(e.getCause());
112                         }
113                 }
114
115                 // Case 1 or 3
116                 try {
117                         Object result = null;
118                         if (ci.noArgsConstructor!=null)
119                                 result = ci.noArgsConstructor.newInstance();
120                         else
121                                 result = ci.clazz.newInstance();
122 //                      Object result = clazz.newInstance();
123                         for (int i=0; i<ci.fields.length; i++) {
124                                 Object value = values[i];
125                                 Field f = ci.fields[i];
126                                 Class<?> type = f.getType();
127                                 
128                                 Method setter = ci.setters[i];
129                                 if (setter!=null) {
130                                         // Case 3
131                                         if (type==int.class)
132                                                 setter.invoke(result, (Integer)value);
133                                         else if (type==long.class)
134                                                 setter.invoke(result, (Long)value);
135                                         else if (type==float.class)
136                                                 setter.invoke(result, (Float)value);
137                                         else if (type==double.class)
138                                                 setter.invoke(result, (Double)value);
139                                         else if (type==boolean.class)
140                                                 setter.invoke(result, (Boolean)value);
141                                         else setter.invoke(result, value);
142                                         
143                                 } else {
144                                         // Case 1
145                                         if (type==int.class)
146                                                 f.setInt(result, (Integer)value);
147                                         else if (type==long.class)
148                                                 f.setLong(result, (Long)value);
149                                         else if (type==float.class)
150                                                 f.setFloat(result, (Float)value);
151                                         else if (type==double.class)
152                                                 f.setDouble(result, (Double)value);
153                                         else if (type==boolean.class)
154                                                 f.setBoolean(result, (Boolean)value);
155                                         else f.set(result, value);
156                                 }
157                                 
158                         }
159                         return result;
160                 } catch (InstantiationException e) {
161                         boolean isPublic = (ci.clazz.getModifiers() & Modifier.PUBLIC)!=0;
162                         if (!isPublic) throw new BindingException("Failed to instantiate "+ci.clazz.getName()+", maybe it should be public class.");
163                         throw new BindingException("Failed to instantiate "+ci.clazz.getName());
164                 } catch (IllegalAccessException e) {
165                         throw new BindingException(e);
166                 } catch (IllegalArgumentException e) {
167                         throw new BindingException(e);
168                 } catch (InvocationTargetException e) {
169                         throw new BindingException(e.getCause());
170                 }
171                 
172         }
173         @Override
174         public Object getComponent(Object obj, int index) throws BindingException {
175                 /*
176                 Field getter = fields[index];           
177                 if (getter!=null) {
178                         try {
179                                 return getter.get(obj);
180                         } catch (IllegalArgumentException e) {
181                                 throw new BindingException(e);
182                         } catch (IllegalAccessException e) {
183                                 throw new BindingException(e);
184                         }
185                 }
186                 */
187                 try {                                           
188                         Field f = ci.fields[index];
189                         Class<?> type = f.getType();
190                         if (type.isPrimitive()) {
191                                 if (type==int.class) return (Integer) f.getInt(obj);
192                                 else if (type==byte.class) return (Byte) f.getByte(obj);
193                                 else if (type==boolean.class) return (Boolean) f.getBoolean(obj);                                               
194                                 else if (type==float.class) return (Float) f.getFloat(obj);                                             
195                                 else if (type==double.class) return (Double) f.getDouble(obj);                                          
196                                 else if (type==long.class) return (Long) f.getLong(obj);                                                
197                                 return f.get(obj);
198                         } else 
199                         return f.get(obj);
200                 } catch (IllegalArgumentException e) {
201                         throw new BindingException(e);
202                 } catch (IllegalAccessException e) {
203                         Field getter = ci.fields[index];                
204                         if (getter!=null) {
205                                 try {
206                                         return getter.get(obj);
207                                 } catch (IllegalArgumentException e2) {
208                                 } catch (IllegalAccessException e2) {
209                                 }
210                         }
211                         throw new BindingException(e);
212                 }
213         }
214
215         @Override
216         public boolean isInstance(Object obj) {                                 
217                 return ci.clazz.isInstance(obj);
218         }
219         
220         @Override
221         public boolean isImmutable() {
222                 return false;
223         }
224         
225         public Class<?> getComponentClass(int index) {
226                 return ci.fields[index].getDeclaringClass();
227         }
228         
229         @Override
230         public void setComponent(Object obj, int index, Object value) throws BindingException {
231                 try {
232                         Method setter = ci.setters[index];
233                         if (setter!=null) {
234                                 setter.invoke(obj, value);
235                         } else {
236                                 Field f = ci.fields[index];
237                                 Class<?> type = f.getType();
238                                 if (type.isPrimitive()) {
239                                         if (type==int.class) f.setInt(obj, (Integer) value);
240                                         else if (type==byte.class) f.setByte(obj, (Byte) value);
241                                         else if (type==boolean.class) f.setBoolean(obj, (Boolean) value);                                               
242                                         else if (type==float.class) f.setFloat(obj, (Float) value);                                             
243                                         else if (type==double.class) f.setDouble(obj, (Double) value);                                          
244                                         else if (type==long.class) f.setLong(obj, (Long) value);                                                
245                                         else f.set(obj, value);
246                                 } else {
247                                         f.set(obj, value);
248                                 }
249                         }
250                 } catch (IllegalAccessException e) {
251                         throw new BindingException(e);
252                 } catch (IllegalArgumentException e) {
253                         throw new BindingException(e);
254                 } catch (InvocationTargetException e) {
255                         e.getCause().printStackTrace();
256                         throw new BindingException(e.getCause());
257                 }                                       
258         }               
259         @Override
260         public void setComponents(Object obj, Object... value) throws BindingException {
261                 try {
262                         for(int i = 0;i<ci.fields.length;++i) {
263                                 Method setter = ci.setters[i];
264                                 if (setter!=null) {
265                                         setter.invoke(obj, value[i]);
266                                 } else {
267                                         Field f = ci.fields[i];
268                                         Class<?> type = f.getType();
269                                         if (type.isPrimitive()) {
270                                                 if (type==int.class) f.setInt(obj, (Integer) value[i]);
271                                                 else if (type==byte.class) f.setByte(obj, (Byte) value[i]);
272                                                 else if (type==boolean.class) f.setBoolean(obj, (Boolean) value[i]);                                            
273                                                 else if (type==float.class) f.setFloat(obj, (Float) value[i]);                                          
274                                                 else if (type==double.class) f.setDouble(obj, (Double) value[i]);                                               
275                                                 else if (type==long.class) f.setLong(obj, (Long) value[i]);                                             
276                                                 else f.set(obj, value[i]);
277                                         } else {
278                                                 f.set(obj, value[i]);
279                                         }
280                                 }
281                         }
282                 } catch (IllegalAccessException e) {
283                         throw new BindingException(e);
284                 } catch (IllegalArgumentException e) {
285                         throw new BindingException(e);
286                 } catch (InvocationTargetException e) {
287                         throw new BindingException(e.getCause());
288                 }                                       
289         }
290         
291         public void setBoolean(Object r, int index, boolean z) throws BindingException
292         {
293                 try {
294                         Field f = ci.fields[index];
295                         Class<?> cl = f.getType();
296                         if ( cl==boolean.class || cl==Boolean.class ) {
297                                 f.setBoolean(r, z); 
298                         } else { 
299                                 BooleanBinding b = (BooleanBinding) getComponentBinding(index);
300                                 setComponent(r, index, b.create(z));
301                         }
302                 } catch (IllegalArgumentException e) {
303                         throw new BindingException(e);
304                 } catch (IllegalAccessException e) {
305                         throw new BindingException(e);
306                 }
307         }
308         
309         public boolean getBoolean(Object r, int index) throws BindingException
310         {
311                 try {
312                         Field f = ci.fields[index];
313                         Class<?> cl = f==null?null:f.getType();
314                         if ( cl==boolean.class || cl==Boolean.class ) return f.getBoolean(r);
315                         Object o = getComponent(r, index);
316                         BooleanBinding b = (BooleanBinding) getComponentBinding(index); 
317                         return b.getValue_(o);
318                 } catch (IllegalArgumentException e) {
319                         throw new BindingException(e);
320                 } catch (IllegalAccessException e) {
321                         throw new BindingException(e);
322                 }
323         }
324         
325         public void setByte(Object r, int index, byte x) throws BindingException
326         {
327                 try {
328                         Field f = ci.fields[index];
329                         Class<?> cl = f.getType();
330                         if ( cl==byte.class || cl==Byte.class ) {
331                                 f.setByte(r, x); 
332                         } else { 
333                                 ByteBinding b = (ByteBinding) getComponentBinding(index);
334                                 setComponent(r, index, b.create(x));
335                         }
336                 } catch (IllegalArgumentException e) {
337                         throw new BindingException(e);
338                 } catch (IllegalAccessException e) {
339                         throw new BindingException(e);
340                 }
341         }
342         
343         public byte getByte(Object r, int index) throws BindingException
344         {
345                 try {
346                         Field f = ci.fields[index];
347                         Class<?> cl = f==null?null:f.getType();
348                         if ( cl==byte.class || cl==Byte.class ) return f.getByte(r);
349                         Object o = getComponent(r, index);
350                         ByteBinding b = (ByteBinding) getComponentBinding(index); 
351                         return b.getValue_(o);
352                 } catch (IllegalArgumentException e) {
353                         throw new BindingException(e);
354                 } catch (IllegalAccessException e) {
355                         throw new BindingException(e);
356                 }
357         }
358
359         public void setInt(Object r, int index, int x) throws BindingException
360         {
361                 try {
362                         Field f = ci.fields[index];
363                         Class<?> cl = f.getType();
364                         if ( cl==int.class || cl==Integer.class ) {
365                                 f.setInt(r, x); 
366                         } else { 
367                                 IntegerBinding b = (IntegerBinding) getComponentBinding(index);
368                                 setComponent(r, index, b.create(x));
369                         }
370                 } catch (IllegalArgumentException e) {
371                         throw new BindingException(e);
372                 } catch (IllegalAccessException e) {
373                         throw new BindingException(e);
374                 }
375         }
376         
377         public int getInt(Object r, int index) throws BindingException
378         {
379                 try {
380                         Field f = ci.fields[index];
381                         Class<?> cl = f==null?null:f.getType();
382                         if ( cl==int.class || cl==Integer.class ) return f.getInt(r);
383                         Object o = getComponent(r, index);
384                         IntegerBinding b = (IntegerBinding) getComponentBinding(index); 
385                         return b.getValue_(o);
386                 } catch (IllegalArgumentException e) {
387                         throw new BindingException(e);
388                 } catch (IllegalAccessException e) {
389                         throw new BindingException(e);
390                 }
391         }
392         
393         public void setLong(Object r, int index, long x) throws BindingException
394         {
395                 try {
396                         Field f = ci.fields[index];
397                         Class<?> cl = f.getType();
398                         if ( cl==long.class || cl==Long.class ) {
399                                 f.setLong(r, x); 
400                         } else { 
401                                 LongBinding b = (LongBinding) getComponentBinding(index);
402                                 setComponent(r, index, b.create(x));
403                         }
404                 } catch (IllegalArgumentException e) {
405                         throw new BindingException(e);
406                 } catch (IllegalAccessException e) {
407                         throw new BindingException(e);
408                 }
409         }
410         
411         public long getLong(Object r, int index) throws BindingException
412         {
413                 try {
414                         Field f = ci.fields[index];
415                         Class<?> cl = f==null?null:f.getType();
416                         if ( cl==long.class || cl==Long.class ) return f.getLong(r);
417                         Object o = getComponent(r, index);
418                         LongBinding b = (LongBinding) getComponentBinding(index); 
419                         return b.getValue_(o);
420                 } catch (IllegalArgumentException e) {
421                         throw new BindingException(e);
422                 } catch (IllegalAccessException e) {
423                         throw new BindingException(e);
424                 }
425         }
426         
427         public void setFloat(Object r, int index, float x) throws BindingException
428         {
429                 try {
430                         Field f = ci.fields[index];
431                         Class<?> cl = f.getType();
432                         if ( cl==float.class || cl==Float.class ) {
433                                 f.setFloat(r, x); 
434                         } else { 
435                                 FloatBinding b = (FloatBinding) getComponentBinding(index);
436                                 setComponent(r, index, b.create(x));
437                         }
438                 } catch (IllegalArgumentException e) {
439                         throw new BindingException(e);
440                 } catch (IllegalAccessException e) {
441                         throw new BindingException(e);
442                 }
443         }
444         
445         public float getFloat(Object r, int index) throws BindingException
446         {
447                 try {
448                         Field f = ci.fields[index];
449                         Class<?> cl = f==null?null:f.getType();
450                         if ( cl==float.class || cl==Float.class ) return f.getFloat(r);
451                         Object o = getComponent(r, index);
452                         FloatBinding b = (FloatBinding) getComponentBinding(index); 
453                         return b.getValue_(o);
454                 } catch (IllegalArgumentException e) {
455                         throw new BindingException(e);
456                 } catch (IllegalAccessException e) {
457                         throw new BindingException(e);
458                 }
459         }
460         
461         public void setDouble(Object r, int index, double x) throws BindingException
462         {
463                 try {
464                         Field f = ci.fields[index];
465                         Class<?> cl = f.getType();
466                         if ( cl==double.class || cl==Double.class ) {
467                                 f.setDouble(r, x); 
468                         } else { 
469                                 DoubleBinding b = (DoubleBinding) getComponentBinding(index);
470                                 setComponent(r, index, b.create(x));
471                         }
472                 } catch (IllegalArgumentException e) {
473                         throw new BindingException(e);
474                 } catch (IllegalAccessException e) {
475                         throw new BindingException(e);
476                 }
477         }
478         
479         public double getDouble(Object r, int index) throws BindingException
480         {
481                 try {
482                         Field f = ci.fields[index];
483                         Class<?> cl = f==null?null:f.getType();
484                         if ( cl==double.class || cl==Double.class ) return f.getDouble(r);
485                         Object o = getComponent(r, index);
486                         DoubleBinding b = (DoubleBinding) getComponentBinding(index); 
487                         return b.getValue_(o);
488                 } catch (IllegalArgumentException e) {
489                         throw new BindingException(e);
490                 } catch (IllegalAccessException e) {
491                         throw new BindingException(e);
492                 }
493         }
494
495 }
496