/*******************************************************************************
* Copyright (c) 2010 Association for Decentralized Information Management in
* Industry THTH ry.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
*******************************************************************************/
package org.simantics.databoard.binding.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import org.simantics.databoard.binding.Binding;
import org.simantics.databoard.binding.BooleanBinding;
import org.simantics.databoard.binding.ByteBinding;
import org.simantics.databoard.binding.DoubleBinding;
import org.simantics.databoard.binding.FloatBinding;
import org.simantics.databoard.binding.IntegerBinding;
import org.simantics.databoard.binding.LongBinding;
import org.simantics.databoard.binding.error.BindingConstructionException;
import org.simantics.databoard.binding.error.BindingException;
import org.simantics.databoard.type.RecordType;
/**
* ReflectionRecordBinding binding of a Record Type and Java Class.
* If binds Record Values to Java Objects.
*
*
* 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 {
private static final Object[] NO_ARGS = new Object[0];
/**
* Create a Reflection Record Bindings.
*
* There is a 2-phase construction.
*
* @param ci
* @param type
* @throws BindingConstructionException
*/
public RecordClassBinding(ClassInfo ci, RecordType type)
{
super(ci);
if ( ci == null ) throw new IllegalArgumentException("null ClassInfo");
this.type = type;
componentBindings = new Binding[ ci.fields.length ];
}
@Override
public Object createPartial() throws BindingException {
try {
if (ci.noArgsConstructor!=null)
return ci.noArgsConstructor.newInstance();
else if (ci.argsConstructor!=null) {
// Create default values
Object values[] = new Object[ci.fields.length];
for (int i=0; i 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) {
boolean isPublic = (ci.clazz.getModifiers() & Modifier.PUBLIC)!=0;
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.getCause());
}
}
@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() {
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.getCause().printStackTrace();
throw new BindingException(e.getCause());
}
}
@Override
public void setComponents(Object obj, Object... value) throws BindingException {
try {
for(int i = 0;i 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.getCause());
}
}
public void setBoolean(Object r, int index, boolean z) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f.getType();
if ( cl==boolean.class || cl==Boolean.class ) {
f.setBoolean(r, z);
} else {
BooleanBinding b = (BooleanBinding) getComponentBinding(index);
setComponent(r, index, b.create(z));
}
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public boolean getBoolean(Object r, int index) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f==null?null:f.getType();
if ( cl==boolean.class || cl==Boolean.class ) return f.getBoolean(r);
Object o = getComponent(r, index);
BooleanBinding b = (BooleanBinding) getComponentBinding(index);
return b.getValue_(o);
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public void setByte(Object r, int index, byte x) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f.getType();
if ( cl==byte.class || cl==Byte.class ) {
f.setByte(r, x);
} else {
ByteBinding b = (ByteBinding) getComponentBinding(index);
setComponent(r, index, b.create(x));
}
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public byte getByte(Object r, int index) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f==null?null:f.getType();
if ( cl==byte.class || cl==Byte.class ) return f.getByte(r);
Object o = getComponent(r, index);
ByteBinding b = (ByteBinding) getComponentBinding(index);
return b.getValue_(o);
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public void setInt(Object r, int index, int x) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f.getType();
if ( cl==int.class || cl==Integer.class ) {
f.setInt(r, x);
} else {
IntegerBinding b = (IntegerBinding) getComponentBinding(index);
setComponent(r, index, b.create(x));
}
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public int getInt(Object r, int index) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f==null?null:f.getType();
if ( cl==int.class || cl==Integer.class ) return f.getInt(r);
Object o = getComponent(r, index);
IntegerBinding b = (IntegerBinding) getComponentBinding(index);
return b.getValue_(o);
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public void setLong(Object r, int index, long x) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f.getType();
if ( cl==long.class || cl==Long.class ) {
f.setLong(r, x);
} else {
LongBinding b = (LongBinding) getComponentBinding(index);
setComponent(r, index, b.create(x));
}
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public long getLong(Object r, int index) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f==null?null:f.getType();
if ( cl==long.class || cl==Long.class ) return f.getLong(r);
Object o = getComponent(r, index);
LongBinding b = (LongBinding) getComponentBinding(index);
return b.getValue_(o);
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public void setFloat(Object r, int index, float x) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f.getType();
if ( cl==float.class || cl==Float.class ) {
f.setFloat(r, x);
} else {
FloatBinding b = (FloatBinding) getComponentBinding(index);
setComponent(r, index, b.create(x));
}
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public float getFloat(Object r, int index) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f==null?null:f.getType();
if ( cl==float.class || cl==Float.class ) return f.getFloat(r);
Object o = getComponent(r, index);
FloatBinding b = (FloatBinding) getComponentBinding(index);
return b.getValue_(o);
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public void setDouble(Object r, int index, double x) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f.getType();
if ( cl==double.class || cl==Double.class ) {
f.setDouble(r, x);
} else {
DoubleBinding b = (DoubleBinding) getComponentBinding(index);
setComponent(r, index, b.create(x));
}
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
public double getDouble(Object r, int index) throws BindingException
{
try {
Field f = ci.fields[index];
Class> cl = f==null?null:f.getType();
if ( cl==double.class || cl==Double.class ) return f.getDouble(r);
Object o = getComponent(r, index);
DoubleBinding b = (DoubleBinding) getComponentBinding(index);
return b.getValue_(o);
} catch (IllegalArgumentException e) {
throw new BindingException(e);
} catch (IllegalAccessException e) {
throw new BindingException(e);
}
}
}