--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.binding.reflection;
+
+import java.lang.reflect.Field;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.lang.reflect.Modifier;\r
+import java.lang.reflect.Type;\r
+\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.BooleanBinding;\r
+import org.simantics.databoard.binding.ByteBinding;\r
+import org.simantics.databoard.binding.DoubleBinding;\r
+import org.simantics.databoard.binding.FloatBinding;\r
+import org.simantics.databoard.binding.IntegerBinding;\r
+import org.simantics.databoard.binding.LongBinding;\r
+import org.simantics.databoard.binding.error.BindingConstructionException;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.type.RecordType;\r
+
+/**
+ * ReflectionRecordBinding binding of a Record Type and Java Class.
+ * If binds Record Values to Java Objects. <p>
+ *
+ *
+ * There are three types of classes supported:
+ * 1) record-like class
+ * - All fields are public
+ * - No-argument public constructor
+ *
+ * 2) immutable-like class
+ * - All fields are set in constructor
+ *
+ * 3) bean-like class
+ * - All fields are set with getter/setter
+ */
+class RecordClassBinding extends ClassBinding {
+\r
+ private static final Object[] NO_ARGS = new Object[0]; \r
+ \r
+ /**
+ * Create a Reflection Record Bindings.
+ *
+ * There is a 2-phase construction.
+ *
+ * @param ci
+ * @param type
+ * @throws BindingConstructionException
+ */
+ public RecordClassBinding(ClassInfo ci, RecordType type)
+ {\r
+ super(ci);\r
+ if ( ci == null ) throw new IllegalArgumentException("null ClassInfo");\r
+ this.type = type;\r
+ componentBindings = new Binding[ ci.fields.length ]; \r
+ }\r
+ \r
+ @Override
+ public Object createPartial() throws BindingException {
+ try {
+ if (ci.noArgsConstructor!=null)
+ return ci.noArgsConstructor.newInstance();
+ else if (ci.argsConstructor!=null) {\r
+ \r
+ // Create default values \r
+ Object values[] = new Object[ci.fields.length];\r
+ for (int i=0; i<values.length; i++) {\r
+ Binding fb = componentBindings[i];\r
+ values[i] = fb.createDefault();\r
+ } \r
+ return ci.argsConstructor.newInstance((Object[])values);
+// return clazz.newInstance();\r
+ } else throw new BindingException("Class "+ci.clazz.getName()+" doesn't support construction. No no-args or args(fields) constructor.");
+ } catch (InstantiationException e) {
+ throw new BindingException(e);
+ } catch (IllegalAccessException e) {
+ throw new BindingException(e);
+ } catch (IllegalArgumentException e) {
+ throw new BindingException(e);
+ } catch (InvocationTargetException e) {
+ throw new BindingException(e);
+ }
+ }
+
+ @Override
+ public Object create(Object... values)
+ throws BindingException {
+
+ // Case 2
+ if (ci.argsConstructor != null)
+ {
+ try {
+ return ci.argsConstructor.newInstance(values);
+ } catch (IllegalArgumentException e) {
+ throw new BindingException(e);
+ } catch (InstantiationException e) {
+ throw new BindingException(e);
+ } catch (IllegalAccessException e) {
+ throw new BindingException(e);
+ } catch (InvocationTargetException e) {
+ throw new BindingException(e);
+ }
+ }
+
+ // Case 1 or 3
+ try {
+ Object result = null;
+ if (ci.noArgsConstructor!=null)
+ result = ci.noArgsConstructor.newInstance();
+ else
+ result = ci.clazz.newInstance();
+// Object result = clazz.newInstance();
+ for (int i=0; i<ci.fields.length; i++) {
+ Object value = values[i];
+ Field f = ci.fields[i];
+ Class<?> type = f.getType();
+
+ Method setter = ci.setters[i];
+ if (setter!=null) {
+ // Case 3
+ if (type==int.class)
+ setter.invoke(result, (Integer)value);
+ else if (type==long.class)
+ setter.invoke(result, (Long)value);
+ else if (type==float.class)
+ setter.invoke(result, (Float)value);
+ else if (type==double.class)
+ setter.invoke(result, (Double)value);
+ else if (type==boolean.class)
+ setter.invoke(result, (Boolean)value);
+ else setter.invoke(result, value);
+
+ } else {
+ // Case 1
+ if (type==int.class)
+ f.setInt(result, (Integer)value);
+ else if (type==long.class)
+ f.setLong(result, (Long)value);
+ else if (type==float.class)
+ f.setFloat(result, (Float)value);
+ else if (type==double.class)
+ f.setDouble(result, (Double)value);
+ else if (type==boolean.class)
+ f.setBoolean(result, (Boolean)value);
+ else f.set(result, value);
+ }
+
+ }
+ return result;
+ } catch (InstantiationException e) {\r
+ boolean isPublic = (ci.clazz.getModifiers() & Modifier.PUBLIC)!=0;\r
+ if (!isPublic) throw new BindingException("Failed to instantiate "+ci.clazz.getName()+", maybe it should be public class.");
+ throw new BindingException("Failed to instantiate "+ci.clazz.getName());
+ } catch (IllegalAccessException e) {
+ throw new BindingException(e);
+ } catch (IllegalArgumentException e) {
+ throw new BindingException(e);
+ } catch (InvocationTargetException e) {
+ throw new BindingException(e);
+ }
+
+ }
+ @Override
+ public Object getComponent(Object obj, int index) throws BindingException {
+ /*
+ Field getter = fields[index];
+ if (getter!=null) {
+ try {
+ return getter.get(obj);
+ } catch (IllegalArgumentException e) {
+ throw new BindingException(e);
+ } catch (IllegalAccessException e) {
+ throw new BindingException(e);
+ }
+ }
+ */
+ try {
+ Field f = ci.fields[index];
+ Class<?> type = f.getType();
+ if (type.isPrimitive()) {
+ if (type==int.class) return (Integer) f.getInt(obj);
+ else if (type==byte.class) return (Byte) f.getByte(obj);
+ else if (type==boolean.class) return (Boolean) f.getBoolean(obj);
+ else if (type==float.class) return (Float) f.getFloat(obj);
+ else if (type==double.class) return (Double) f.getDouble(obj);
+ else if (type==long.class) return (Long) f.getLong(obj);
+ return f.get(obj);
+ } else
+ return f.get(obj);
+ } catch (IllegalArgumentException e) {
+ throw new BindingException(e);
+ } catch (IllegalAccessException e) {
+ Field getter = ci.fields[index];
+ if (getter!=null) {
+ try {
+ return getter.get(obj);
+ } catch (IllegalArgumentException e2) {
+ } catch (IllegalAccessException e2) {
+ }
+ }
+ throw new BindingException(e);
+ }
+ }
+
+ @Override
+ public boolean isInstance(Object obj) {
+ return ci.clazz.isInstance(obj);
+ }
+
+ @Override
+ public boolean isImmutable() {\r
+ return false;
+ }
+
+ public Class<?> getComponentClass(int index) {
+ return ci.fields[index].getDeclaringClass();
+ }
+
+ @Override
+ public void setComponent(Object obj, int index, Object value) throws BindingException {
+ try {
+ Method setter = ci.setters[index];
+ if (setter!=null) {
+ setter.invoke(obj, value);
+ } else {
+ Field f = ci.fields[index];
+ Class<?> type = f.getType();
+ if (type.isPrimitive()) {
+ if (type==int.class) f.setInt(obj, (Integer) value);
+ else if (type==byte.class) f.setByte(obj, (Byte) value);
+ else if (type==boolean.class) f.setBoolean(obj, (Boolean) value);
+ else if (type==float.class) f.setFloat(obj, (Float) value);
+ else if (type==double.class) f.setDouble(obj, (Double) value);
+ else if (type==long.class) f.setLong(obj, (Long) value);
+ else f.set(obj, value);
+ } else {
+ f.set(obj, value);
+ }
+ }
+ } catch (IllegalAccessException e) {
+ throw new BindingException(e);
+ } catch (IllegalArgumentException e) {
+ throw new BindingException(e);
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ throw new BindingException(e);
+ }
+ }
+ @Override
+ public void setComponents(Object obj, Object... value) throws BindingException {
+ try {
+ for(int i = 0;i<ci.fields.length;++i) {
+ Method setter = ci.setters[i];
+ if (setter!=null) {
+ setter.invoke(obj, value[i]);
+ } else {
+ Field f = ci.fields[i];
+ Class<?> type = f.getType();
+ if (type.isPrimitive()) {
+ if (type==int.class) f.setInt(obj, (Integer) value[i]);
+ else if (type==byte.class) f.setByte(obj, (Byte) value[i]);
+ else if (type==boolean.class) f.setBoolean(obj, (Boolean) value[i]);
+ else if (type==float.class) f.setFloat(obj, (Float) value[i]);
+ else if (type==double.class) f.setDouble(obj, (Double) value[i]);
+ else if (type==long.class) f.setLong(obj, (Long) value[i]);
+ else f.set(obj, value[i]);
+ } else {
+ f.set(obj, value[i]);
+ }
+ }
+ }
+ } catch (IllegalAccessException e) {
+ throw new BindingException(e);
+ } catch (IllegalArgumentException e) {
+ throw new BindingException(e);
+ } catch (InvocationTargetException e) {
+ throw new BindingException(e);\r
+ }
+ }\r
+ \r
+ public void setBoolean(Object r, int index, boolean z) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f.getType();\r
+ if ( cl==boolean.class || cl==Boolean.class ) {\r
+ f.setBoolean(r, z); \r
+ } else { \r
+ BooleanBinding b = (BooleanBinding) getComponentBinding(index);\r
+ setComponent(r, index, b.create(z));\r
+ }\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public boolean getBoolean(Object r, int index) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f==null?null:f.getType();\r
+ if ( cl==boolean.class || cl==Boolean.class ) return f.getBoolean(r);\r
+ Object o = getComponent(r, index);\r
+ BooleanBinding b = (BooleanBinding) getComponentBinding(index); \r
+ return b.getValue_(o);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public void setByte(Object r, int index, byte x) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f.getType();\r
+ if ( cl==byte.class || cl==Byte.class ) {\r
+ f.setByte(r, x); \r
+ } else { \r
+ ByteBinding b = (ByteBinding) getComponentBinding(index);\r
+ setComponent(r, index, b.create(x));\r
+ }\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public byte getByte(Object r, int index) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f==null?null:f.getType();\r
+ if ( cl==byte.class || cl==Byte.class ) return f.getByte(r);\r
+ Object o = getComponent(r, index);\r
+ ByteBinding b = (ByteBinding) getComponentBinding(index); \r
+ return b.getValue_(o);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+\r
+ public void setInt(Object r, int index, int x) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f.getType();\r
+ if ( cl==int.class || cl==Integer.class ) {\r
+ f.setInt(r, x); \r
+ } else { \r
+ IntegerBinding b = (IntegerBinding) getComponentBinding(index);\r
+ setComponent(r, index, b.create(x));\r
+ }\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public int getInt(Object r, int index) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f==null?null:f.getType();\r
+ if ( cl==int.class || cl==Integer.class ) return f.getInt(r);\r
+ Object o = getComponent(r, index);\r
+ IntegerBinding b = (IntegerBinding) getComponentBinding(index); \r
+ return b.getValue_(o);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public void setLong(Object r, int index, long x) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f.getType();\r
+ if ( cl==long.class || cl==Long.class ) {\r
+ f.setLong(r, x); \r
+ } else { \r
+ LongBinding b = (LongBinding) getComponentBinding(index);\r
+ setComponent(r, index, b.create(x));\r
+ }\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public long getLong(Object r, int index) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f==null?null:f.getType();\r
+ if ( cl==long.class || cl==Long.class ) return f.getLong(r);\r
+ Object o = getComponent(r, index);\r
+ LongBinding b = (LongBinding) getComponentBinding(index); \r
+ return b.getValue_(o);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public void setFloat(Object r, int index, float x) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f.getType();\r
+ if ( cl==float.class || cl==Float.class ) {\r
+ f.setFloat(r, x); \r
+ } else { \r
+ FloatBinding b = (FloatBinding) getComponentBinding(index);\r
+ setComponent(r, index, b.create(x));\r
+ }\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public float getFloat(Object r, int index) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f==null?null:f.getType();\r
+ if ( cl==float.class || cl==Float.class ) return f.getFloat(r);\r
+ Object o = getComponent(r, index);\r
+ FloatBinding b = (FloatBinding) getComponentBinding(index); \r
+ return b.getValue_(o);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public void setDouble(Object r, int index, double x) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f.getType();\r
+ if ( cl==double.class || cl==Double.class ) {\r
+ f.setDouble(r, x); \r
+ } else { \r
+ DoubleBinding b = (DoubleBinding) getComponentBinding(index);\r
+ setComponent(r, index, b.create(x));\r
+ }\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+ \r
+ public double getDouble(Object r, int index) throws BindingException\r
+ {\r
+ try {\r
+ Field f = ci.fields[index];\r
+ Class<?> cl = f==null?null:f.getType();\r
+ if ( cl==double.class || cl==Double.class ) return f.getDouble(r);\r
+ Object o = getComponent(r, index);\r
+ DoubleBinding b = (DoubleBinding) getComponentBinding(index); \r
+ return b.getValue_(o);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new BindingException(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new BindingException(e);\r
+ }\r
+ }\r
+\r
+}
+