package org.pulloid; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Map; /** * Allows to set a public field's value or a non-public field's value through a setter method. * * @author Romain Laboisse labrom@gmail.com */ public class DefaultFieldSetter implements FieldSetter { @SuppressWarnings("unchecked") private static final Collection> SUPPORTED_TYPES = new ArrayList>(Arrays.asList(int.class, Integer.class, long.class, Long.class, float.class, Float.class, double.class, Double.class)); private Field field; private Class fieldType; private String fieldName; protected Method setterMethod; /** * * @param targetType * @param fieldName */ DefaultFieldSetter(Class targetType, String fieldName) { this(targetType, fieldName, null); } /** * * @param targetType * @param fieldName * @param targetFieldType The actual type of the field to set. It can be null. */ DefaultFieldSetter(Class targetType, String fieldName, Class targetFieldType) { // If this is a Map, we'll just call put(String, Object) - we support Map only if(targetType == null || Map.class.isAssignableFrom(targetType)) { this.fieldName = fieldName; this.fieldType = targetFieldType != null ? targetFieldType : String.class; // If not type specified, String is assumed return; } try { // We don't need to know the field type since we're just looking for the member field with the right name this.field = targetType.getField(fieldName); this.fieldType = field.getType(); // If value is not a number and field is a number, the setter will try to convert return; } catch(NoSuchFieldException nsfe) { // No such field, trying setter method // First search, with the specified field type or String String setterMethodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); this.fieldType = targetFieldType != null ? targetFieldType : String.class; // If not type specified, String is assumed try { this.setterMethod = targetType.getMethod(setterMethodName, this.fieldType); return; } catch (SecurityException se) { throw new CursorException(se); } catch (NoSuchMethodException nsme) { // Second search, on all methods, filter using name and number of params (1) for(Method m : targetType.getMethods()) { if(m.getName().equals(setterMethodName)) { Class[] params = m.getParameterTypes(); if(params.length == 1 && SUPPORTED_TYPES.contains(params[0])) { // Guess we found the right setter method this.setterMethod = m; this.fieldType = params[0]; return; } } } } throw new CursorException(String.format("Unable to find a field or a setter method for field %1$s in class %2$s", fieldName, targetType.getName())); } } final Object parseValue(Object value) { if(fieldType == null) return value; if(fieldType == Integer.class) return new Integer(String.valueOf(value)); if(fieldType == Long.class) return new Long(String.valueOf(value)); if(fieldType == Float.class) return new Float(String.valueOf(value)); if(fieldType == Double.class) return new Double(String.valueOf(value)); if(fieldType == int.class) return Integer.parseInt(String.valueOf(value)); if(fieldType == long.class) return Long.parseLong(String.valueOf(value)); if(fieldType == float.class) return Float.parseFloat(String.valueOf(value)); if(fieldType == double.class) return Double.parseDouble(String.valueOf(value)); return value; } @Override @SuppressWarnings("unchecked") public boolean set(T target, Object value) { if(fieldName != null) { ((Map)target).put(fieldName, parseValue(value)); return true; } if(field != null) { // TODO Transform value is needed try { field.set(target, parseValue(value)); return true; } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else if(setterMethod != null) { // TODO Transform value is needed try { setterMethod.invoke(target, parseValue(value)); return true; } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return false; } String getFieldName() { if(fieldName != null) return fieldName; if(field != null) return field.getName(); String field = setterMethod.getName().substring(3); field = field.substring(0, 1).toLowerCase() + field.substring(1); return field; } }