]> gerrit.simantics Code Review - simantics/platform.git/blob
c84e76a4a1048261903d7089f60e60c3b74baf2a
[simantics/platform.git] /
1 /*******************************************************************************\r
2  *  Copyright (c) 2010 Association for Decentralized Information Management in\r
3  *  Industry THTH ry.\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
8  *\r
9  *  Contributors:\r
10  *      VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard.binding.reflection;
13
14 import java.lang.reflect.Field;\r
15 import java.lang.reflect.InvocationTargetException;\r
16 import java.lang.reflect.Method;\r
17 import java.lang.reflect.Modifier;\r
18 import java.lang.reflect.Type;\r
19 \r
20 import org.simantics.databoard.binding.Binding;\r
21 import org.simantics.databoard.binding.BooleanBinding;\r
22 import org.simantics.databoard.binding.ByteBinding;\r
23 import org.simantics.databoard.binding.DoubleBinding;\r
24 import org.simantics.databoard.binding.FloatBinding;\r
25 import org.simantics.databoard.binding.IntegerBinding;\r
26 import org.simantics.databoard.binding.LongBinding;\r
27 import org.simantics.databoard.binding.error.BindingConstructionException;\r
28 import org.simantics.databoard.binding.error.BindingException;\r
29 import org.simantics.databoard.type.RecordType;\r
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 \r
49         private static final Object[] NO_ARGS = new Object[0];  \r
50         \r
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         {\r
62                 super(ci);\r
63                 if ( ci == null ) throw new IllegalArgumentException("null ClassInfo");\r
64                 this.type = type;\r
65         componentBindings = new Binding[ ci.fields.length ];            \r
66         }\r
67         \r
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) {\r
74                                 \r
75                                 // Create default values \r
76                                 Object values[] = new Object[ci.fields.length];\r
77                                 for (int i=0; i<values.length; i++) {\r
78                                         Binding fb = componentBindings[i];\r
79                                         values[i] = fb.createDefault();\r
80                                 }                               \r
81                                 return ci.argsConstructor.newInstance((Object[])values);
82 //                              return clazz.newInstance();\r
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);
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);
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) {\r
161                         boolean isPublic = (ci.clazz.getModifiers() & Modifier.PUBLIC)!=0;\r
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);
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() {\r
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.printStackTrace();
256                         throw new BindingException(e);
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);\r
288                 }                                       
289         }\r
290         \r
291         public void setBoolean(Object r, int index, boolean z) throws BindingException\r
292         {\r
293                 try {\r
294                         Field f = ci.fields[index];\r
295                         Class<?> cl = f.getType();\r
296                         if ( cl==boolean.class || cl==Boolean.class ) {\r
297                                 f.setBoolean(r, z); \r
298                         } else { \r
299                                 BooleanBinding b = (BooleanBinding) getComponentBinding(index);\r
300                                 setComponent(r, index, b.create(z));\r
301                         }\r
302                 } catch (IllegalArgumentException e) {\r
303                         throw new BindingException(e);\r
304                 } catch (IllegalAccessException e) {\r
305                         throw new BindingException(e);\r
306                 }\r
307         }\r
308         \r
309         public boolean getBoolean(Object r, int index) throws BindingException\r
310         {\r
311                 try {\r
312                         Field f = ci.fields[index];\r
313                         Class<?> cl = f==null?null:f.getType();\r
314                         if ( cl==boolean.class || cl==Boolean.class ) return f.getBoolean(r);\r
315                         Object o = getComponent(r, index);\r
316                         BooleanBinding b = (BooleanBinding) getComponentBinding(index); \r
317                         return b.getValue_(o);\r
318                 } catch (IllegalArgumentException e) {\r
319                         throw new BindingException(e);\r
320                 } catch (IllegalAccessException e) {\r
321                         throw new BindingException(e);\r
322                 }\r
323         }\r
324         \r
325         public void setByte(Object r, int index, byte x) throws BindingException\r
326         {\r
327                 try {\r
328                         Field f = ci.fields[index];\r
329                         Class<?> cl = f.getType();\r
330                         if ( cl==byte.class || cl==Byte.class ) {\r
331                                 f.setByte(r, x); \r
332                         } else { \r
333                                 ByteBinding b = (ByteBinding) getComponentBinding(index);\r
334                                 setComponent(r, index, b.create(x));\r
335                         }\r
336                 } catch (IllegalArgumentException e) {\r
337                         throw new BindingException(e);\r
338                 } catch (IllegalAccessException e) {\r
339                         throw new BindingException(e);\r
340                 }\r
341         }\r
342         \r
343         public byte getByte(Object r, int index) throws BindingException\r
344         {\r
345                 try {\r
346                         Field f = ci.fields[index];\r
347                         Class<?> cl = f==null?null:f.getType();\r
348                         if ( cl==byte.class || cl==Byte.class ) return f.getByte(r);\r
349                         Object o = getComponent(r, index);\r
350                         ByteBinding b = (ByteBinding) getComponentBinding(index); \r
351                         return b.getValue_(o);\r
352                 } catch (IllegalArgumentException e) {\r
353                         throw new BindingException(e);\r
354                 } catch (IllegalAccessException e) {\r
355                         throw new BindingException(e);\r
356                 }\r
357         }\r
358 \r
359         public void setInt(Object r, int index, int x) throws BindingException\r
360         {\r
361                 try {\r
362                         Field f = ci.fields[index];\r
363                         Class<?> cl = f.getType();\r
364                         if ( cl==int.class || cl==Integer.class ) {\r
365                                 f.setInt(r, x); \r
366                         } else { \r
367                                 IntegerBinding b = (IntegerBinding) getComponentBinding(index);\r
368                                 setComponent(r, index, b.create(x));\r
369                         }\r
370                 } catch (IllegalArgumentException e) {\r
371                         throw new BindingException(e);\r
372                 } catch (IllegalAccessException e) {\r
373                         throw new BindingException(e);\r
374                 }\r
375         }\r
376         \r
377         public int getInt(Object r, int index) throws BindingException\r
378         {\r
379                 try {\r
380                         Field f = ci.fields[index];\r
381                         Class<?> cl = f==null?null:f.getType();\r
382                         if ( cl==int.class || cl==Integer.class ) return f.getInt(r);\r
383                         Object o = getComponent(r, index);\r
384                         IntegerBinding b = (IntegerBinding) getComponentBinding(index); \r
385                         return b.getValue_(o);\r
386                 } catch (IllegalArgumentException e) {\r
387                         throw new BindingException(e);\r
388                 } catch (IllegalAccessException e) {\r
389                         throw new BindingException(e);\r
390                 }\r
391         }\r
392         \r
393         public void setLong(Object r, int index, long x) throws BindingException\r
394         {\r
395                 try {\r
396                         Field f = ci.fields[index];\r
397                         Class<?> cl = f.getType();\r
398                         if ( cl==long.class || cl==Long.class ) {\r
399                                 f.setLong(r, x); \r
400                         } else { \r
401                                 LongBinding b = (LongBinding) getComponentBinding(index);\r
402                                 setComponent(r, index, b.create(x));\r
403                         }\r
404                 } catch (IllegalArgumentException e) {\r
405                         throw new BindingException(e);\r
406                 } catch (IllegalAccessException e) {\r
407                         throw new BindingException(e);\r
408                 }\r
409         }\r
410         \r
411         public long getLong(Object r, int index) throws BindingException\r
412         {\r
413                 try {\r
414                         Field f = ci.fields[index];\r
415                         Class<?> cl = f==null?null:f.getType();\r
416                         if ( cl==long.class || cl==Long.class ) return f.getLong(r);\r
417                         Object o = getComponent(r, index);\r
418                         LongBinding b = (LongBinding) getComponentBinding(index); \r
419                         return b.getValue_(o);\r
420                 } catch (IllegalArgumentException e) {\r
421                         throw new BindingException(e);\r
422                 } catch (IllegalAccessException e) {\r
423                         throw new BindingException(e);\r
424                 }\r
425         }\r
426         \r
427         public void setFloat(Object r, int index, float x) throws BindingException\r
428         {\r
429                 try {\r
430                         Field f = ci.fields[index];\r
431                         Class<?> cl = f.getType();\r
432                         if ( cl==float.class || cl==Float.class ) {\r
433                                 f.setFloat(r, x); \r
434                         } else { \r
435                                 FloatBinding b = (FloatBinding) getComponentBinding(index);\r
436                                 setComponent(r, index, b.create(x));\r
437                         }\r
438                 } catch (IllegalArgumentException e) {\r
439                         throw new BindingException(e);\r
440                 } catch (IllegalAccessException e) {\r
441                         throw new BindingException(e);\r
442                 }\r
443         }\r
444         \r
445         public float getFloat(Object r, int index) throws BindingException\r
446         {\r
447                 try {\r
448                         Field f = ci.fields[index];\r
449                         Class<?> cl = f==null?null:f.getType();\r
450                         if ( cl==float.class || cl==Float.class ) return f.getFloat(r);\r
451                         Object o = getComponent(r, index);\r
452                         FloatBinding b = (FloatBinding) getComponentBinding(index); \r
453                         return b.getValue_(o);\r
454                 } catch (IllegalArgumentException e) {\r
455                         throw new BindingException(e);\r
456                 } catch (IllegalAccessException e) {\r
457                         throw new BindingException(e);\r
458                 }\r
459         }\r
460         \r
461         public void setDouble(Object r, int index, double x) throws BindingException\r
462         {\r
463                 try {\r
464                         Field f = ci.fields[index];\r
465                         Class<?> cl = f.getType();\r
466                         if ( cl==double.class || cl==Double.class ) {\r
467                                 f.setDouble(r, x); \r
468                         } else { \r
469                                 DoubleBinding b = (DoubleBinding) getComponentBinding(index);\r
470                                 setComponent(r, index, b.create(x));\r
471                         }\r
472                 } catch (IllegalArgumentException e) {\r
473                         throw new BindingException(e);\r
474                 } catch (IllegalAccessException e) {\r
475                         throw new BindingException(e);\r
476                 }\r
477         }\r
478         \r
479         public double getDouble(Object r, int index) throws BindingException\r
480         {\r
481                 try {\r
482                         Field f = ci.fields[index];\r
483                         Class<?> cl = f==null?null:f.getType();\r
484                         if ( cl==double.class || cl==Double.class ) return f.getDouble(r);\r
485                         Object o = getComponent(r, index);\r
486                         DoubleBinding b = (DoubleBinding) getComponentBinding(index); \r
487                         return b.getValue_(o);\r
488                 } catch (IllegalArgumentException e) {\r
489                         throw new BindingException(e);\r
490                 } catch (IllegalAccessException e) {\r
491                         throw new BindingException(e);\r
492                 }\r
493         }\r
494 \r
495 }
496