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 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;
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;
32 * ReflectionRecordBinding binding of a Record Type and Java Class.
33 * If binds Record Values to Java Objects. <p>
36 * There are three types of classes supported:
37 * 1) record-like class
38 * - All fields are public
39 * - No-argument public constructor
41 * 2) immutable-like class
42 * - All fields are set in constructor
45 * - All fields are set with getter/setter
47 class RecordClassBinding extends ClassBinding {
49 private static final Object[] NO_ARGS = new Object[0];
52 * Create a Reflection Record Bindings.
54 * There is a 2-phase construction.
58 * @throws BindingConstructionException
60 public RecordClassBinding(ClassInfo ci, RecordType type)
63 if ( ci == null ) throw new IllegalArgumentException("null ClassInfo");
65 componentBindings = new Binding[ ci.fields.length ];
69 public Object createPartial() throws BindingException {
71 if (ci.noArgsConstructor!=null)
72 return ci.noArgsConstructor.newInstance();
73 else if (ci.argsConstructor!=null) {
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();
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());
96 public Object create(Object... values)
97 throws BindingException {
100 if (ci.argsConstructor != null)
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());
117 Object result = null;
118 if (ci.noArgsConstructor!=null)
119 result = ci.noArgsConstructor.newInstance();
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();
128 Method setter = ci.setters[i];
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);
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);
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());
174 public Object getComponent(Object obj, int index) throws BindingException {
176 Field getter = fields[index];
179 return getter.get(obj);
180 } catch (IllegalArgumentException e) {
181 throw new BindingException(e);
182 } catch (IllegalAccessException e) {
183 throw new BindingException(e);
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);
200 } catch (IllegalArgumentException e) {
201 throw new BindingException(e);
202 } catch (IllegalAccessException e) {
203 Field getter = ci.fields[index];
206 return getter.get(obj);
207 } catch (IllegalArgumentException e2) {
208 } catch (IllegalAccessException e2) {
211 throw new BindingException(e);
216 public boolean isInstance(Object obj) {
217 return ci.clazz.isInstance(obj);
221 public boolean isImmutable() {
225 public Class<?> getComponentClass(int index) {
226 return ci.fields[index].getDeclaringClass();
230 public void setComponent(Object obj, int index, Object value) throws BindingException {
232 Method setter = ci.setters[index];
234 setter.invoke(obj, value);
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);
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());
260 public void setComponents(Object obj, Object... value) throws BindingException {
262 for(int i = 0;i<ci.fields.length;++i) {
263 Method setter = ci.setters[i];
265 setter.invoke(obj, value[i]);
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]);
278 f.set(obj, value[i]);
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());
291 public void setBoolean(Object r, int index, boolean z) throws BindingException
294 Field f = ci.fields[index];
295 Class<?> cl = f.getType();
296 if ( cl==boolean.class || cl==Boolean.class ) {
299 BooleanBinding b = (BooleanBinding) getComponentBinding(index);
300 setComponent(r, index, b.create(z));
302 } catch (IllegalArgumentException e) {
303 throw new BindingException(e);
304 } catch (IllegalAccessException e) {
305 throw new BindingException(e);
309 public boolean getBoolean(Object r, int index) throws BindingException
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);
325 public void setByte(Object r, int index, byte x) throws BindingException
328 Field f = ci.fields[index];
329 Class<?> cl = f.getType();
330 if ( cl==byte.class || cl==Byte.class ) {
333 ByteBinding b = (ByteBinding) getComponentBinding(index);
334 setComponent(r, index, b.create(x));
336 } catch (IllegalArgumentException e) {
337 throw new BindingException(e);
338 } catch (IllegalAccessException e) {
339 throw new BindingException(e);
343 public byte getByte(Object r, int index) throws BindingException
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);
359 public void setInt(Object r, int index, int x) throws BindingException
362 Field f = ci.fields[index];
363 Class<?> cl = f.getType();
364 if ( cl==int.class || cl==Integer.class ) {
367 IntegerBinding b = (IntegerBinding) getComponentBinding(index);
368 setComponent(r, index, b.create(x));
370 } catch (IllegalArgumentException e) {
371 throw new BindingException(e);
372 } catch (IllegalAccessException e) {
373 throw new BindingException(e);
377 public int getInt(Object r, int index) throws BindingException
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);
393 public void setLong(Object r, int index, long x) throws BindingException
396 Field f = ci.fields[index];
397 Class<?> cl = f.getType();
398 if ( cl==long.class || cl==Long.class ) {
401 LongBinding b = (LongBinding) getComponentBinding(index);
402 setComponent(r, index, b.create(x));
404 } catch (IllegalArgumentException e) {
405 throw new BindingException(e);
406 } catch (IllegalAccessException e) {
407 throw new BindingException(e);
411 public long getLong(Object r, int index) throws BindingException
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);
427 public void setFloat(Object r, int index, float x) throws BindingException
430 Field f = ci.fields[index];
431 Class<?> cl = f.getType();
432 if ( cl==float.class || cl==Float.class ) {
435 FloatBinding b = (FloatBinding) getComponentBinding(index);
436 setComponent(r, index, b.create(x));
438 } catch (IllegalArgumentException e) {
439 throw new BindingException(e);
440 } catch (IllegalAccessException e) {
441 throw new BindingException(e);
445 public float getFloat(Object r, int index) throws BindingException
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);
461 public void setDouble(Object r, int index, double x) throws BindingException
464 Field f = ci.fields[index];
465 Class<?> cl = f.getType();
466 if ( cl==double.class || cl==Double.class ) {
469 DoubleBinding b = (DoubleBinding) getComponentBinding(index);
470 setComponent(r, index, b.create(x));
472 } catch (IllegalArgumentException e) {
473 throw new BindingException(e);
474 } catch (IllegalAccessException e) {
475 throw new BindingException(e);
479 public double getDouble(Object r, int index) throws BindingException
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);