Index: java/main/src/main/java/com/framsticks/params/ReflectionAccess.java
===================================================================
--- java/main/src/main/java/com/framsticks/params/ReflectionAccess.java	(revision 85)
+++ java/main/src/main/java/com/framsticks/params/ReflectionAccess.java	(revision 86)
@@ -3,10 +3,13 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.log4j.Logger;
 
-import com.framsticks.util.lang.Containers;
-
+import com.framsticks.util.FramsticksException;
+
+import static com.framsticks.util.lang.Containers.*;
 
 /**
@@ -19,48 +22,138 @@
  */
 public class ReflectionAccess extends SimpleAbstractAccess {
-	private final static Logger log = Logger.getLogger(ReflectionAccess.class.getName());
+	private final static Logger log = Logger.getLogger(ReflectionAccess.class
+			.getName());
 
 	protected final Class<?> reflectedClass;
 	private Object object;
 
-	public ReflectionAccess(Class<?> reflectedClass, FramsClass framsClass) {
+
+	protected interface ReflectedSetter {
+		public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
+	}
+
+	protected interface ReflectedGetter {
+		public abstract <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
+	}
+
+	protected static class ReflectedValueParam {
+		public ReflectedSetter setter;
+		public ReflectedGetter getter;
+	}
+
+	protected final Map<ValueParam, ReflectedValueParam> reflectedValueParams = new HashMap<>();
+
+	public ReflectionAccess(Class<?> reflectedClass) throws ConstructionException {
+		this(reflectedClass, FramsClassBuilder.buildForClass(reflectedClass));
+	}
+
+	public static boolean typeMatch(Class<?> a, Class<?> b) {
+		assert !b.isPrimitive();
+		if (!a.isPrimitive()) {
+			return a.equals(b);
+		}
+
+		if (a.equals(int.class)) {
+			return b.equals(Integer.class);
+		}
+		if (a.equals(double.class)) {
+			return b.equals(Double.class);
+		}
+		if (a.equals(boolean.class)) {
+			return b.equals(Boolean.class);
+		}
+		assert false;
+		return false;
+	}
+
+	public ReflectionAccess(Class<?> reflectedClass, FramsClass framsClass) throws ConstructionException {
 		this.reflectedClass = reflectedClass;
 		setFramsClass(framsClass);
-	}
-
-	private static String accessorName(boolean get, String id) {
-		return (get ? "get"  : "set") + id.substring(0, 1).toUpperCase() + id.substring(1);
-	}
+
+		Map<String, ParamCandidate> candidates = ParamCandidate.getAllCandidates(reflectedClass);
+
+		try {
+			for (final ValueParam vp : filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) {
+				if (!candidates.containsKey(vp.getId())) {
+					throw new ConstructionException().msg("missing candidate for param").arg("param", vp);
+				}
+				ParamCandidate pc = candidates.get(vp.getId());
+				if (pc.isReadOnly() && !vp.hasFlag(Flags.READONLY)) {
+					throw new ConstructionException().msg("readonly state conflict").arg("param", vp);
+				}
+				if (!typeMatch(pc.getRawType(), vp.getStorageType())) {
+					throw new ConstructionException().msg("types mismatch for param").arg("param", vp).arg("candidate", pc.getType()).arg("storage", vp.getStorageType());
+				}
+
+				ReflectedValueParam rvp = new ReflectedValueParam();
+				reflectedValueParams.put(vp, rvp);
+				final boolean primitive = pc.isPrimitive();
+				if (pc.getField() != null) {
+					final Field f = pc.getField();
+					rvp.getter = new ReflectedGetter() {
+						@Override
+						public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException {
+							return type.cast(f.get(object));
+						}
+					};
+					if (!pc.isFinal()) {
+						rvp.setter = new ReflectedSetter() {
+							@Override
+							public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException {
+								if (value == null && primitive) {
+									throw new FramsticksException().msg("setting null to primitive value");
+								}
+								f.set(object, value);
+							}
+						};
+					}
+				} else {
+					final Method g = pc.getGetter();
+
+					rvp.getter = new ReflectedGetter() {
+						@Override
+						public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+							return type.cast(g.invoke(object));
+						}
+					};
+
+					if (!pc.isFinal()) {
+						final Method s = pc.getSetter();
+						rvp.setter = new ReflectedSetter() {
+							@Override
+							public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+								if (value == null && primitive) {
+									throw new FramsticksException().msg("setting null to primitive value");
+								}
+								s.invoke(object, value);
+							}
+						};
+					}
+				}
+			}
+		} catch (ConstructionException e) {
+			throw e.arg("java class", reflectedClass).arg("framsClass", framsClass);
+		}
+	}
+
+	// private static String accessorName(boolean get, String id) {
+	//	return (get ? "get" : "set") + id.substring(0, 1).toUpperCase() + id.substring(1);
+	// }
 
 	@Override
 	public <T> T get(ValueParam param, Class<T> type) {
-		if (object == null) {
-			return null;
-		}
-		try {
-			//TODO: use internal id, if present
-			String id = param.getId();
+		try {
 			try {
-				return type.cast(reflectedClass.getField(id).get(object));
-			} catch (NoSuchFieldException ignored) {
-			}
-			try {
-				return type.cast(reflectedClass.getMethod(accessorName(true, id)).invoke(object));
-			} catch (NoSuchMethodException | InvocationTargetException ex) {
-				//e.printStackTrace();
-			}
-			try {
-				return type.cast(reflectedClass.getMethod(id).invoke(object));
-			} catch (NoSuchMethodException | InvocationTargetException ex) {
-				//e.printStackTrace();
-			}
-
-		} catch (IllegalAccessException e) {
-			log.warn("illegal access error occurred while trying to access returnedObject");
-			e.printStackTrace();
-		} catch (ClassCastException ignored) {
-
-		}
-		return null;
+				if (object == null) {
+					throw new FramsticksException().msg("no object set");
+				}
+
+				return reflectedValueParams.get(param).getter.get(object, type);
+			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+				throw new FramsticksException().msg("failed to get").cause(e);
+			}
+		} catch (FramsticksException e) {
+			throw e.arg("param", param).arg("type", type).arg("access", this);
+		}
 	}
 
@@ -71,31 +164,19 @@
 
 	private <T> void setValue(ValueParam param, T value) {
-		if (object == null) {
-			return;
-		}
-		try {
-			String id = param.getId();
+		try {
 			try {
-				Field f = reflectedClass.getField(id);
-				Class<?> t = f.getType();
-				if (Modifier.isFinal(f.getModifiers())) {
-					return;
-				}
-				if (value != null || (!t.isPrimitive())) {
-					f.set(object, value);
-				}
-				return;
-			} catch (NoSuchFieldException ignored) {
-			}
-			try {
-				reflectedClass.getMethod(accessorName(false, id), new Class[]{param.getStorageType()}).invoke(object, value);
-			} catch (InvocationTargetException | NoSuchMethodException ignored) {
-			}
-			try {
-				reflectedClass.getMethod(id, new Class[]{param.getStorageType()}).invoke(object, value);
-			} catch (InvocationTargetException | NoSuchMethodException ignored) {
-			}
-		} catch (Exception ex) {
-			ex.printStackTrace();
+				if (object == null) {
+					throw new FramsticksException().msg("no object set");
+				}
+				ReflectedSetter s = reflectedValueParams.get(param).setter;
+				if (s == null) {
+					throw new FramsticksException().msg("trying to set final");
+				}
+				s.set(object, value);
+			} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
+				throw new FramsticksException().msg("failed to set").cause(e);
+			}
+		} catch (FramsticksException e) {
+			throw e.arg("param", param).arg("value", value).arg("access", this);
 		}
 	}
@@ -114,5 +195,5 @@
 
 		try {
-			for (ValueParam p : Containers.filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) {
+			for (ValueParam p : filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) {
 				setValue(p, p.getDef(Object.class));
 			}
@@ -159,5 +240,5 @@
 
 	@Override
-	public ReflectionAccess cloneAccess() {
+	public ReflectionAccess cloneAccess() throws ConstructionException {
 		return new ReflectionAccess(reflectedClass, framsClass);
 	}
@@ -173,3 +254,15 @@
 		return null;
 	}
+
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		b.append(framsClass);
+		if (object != null) {
+			b.append("(").append(object).append(")");
+		}
+		return b.toString();
+	}
+
 }
+
