Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.tectonica.util;
  
Simple reflection-based wrapper for a specific field in a specific instance. The field is identified by a dot-notation (e.g. "address.city.name") and can be manipulated conveniently via the various methods.

Author(s):
Zach Melamed
 
 public class FieldAccessor
 {
 	private FieldAccessor()
 	{}
 
 	private Object instance;
 	private String fieldPath;
 	private Field field;
 
 	public Object getInstance()
 	{
 		return ;
 	}
 
 	public String getPath()
 	{
 		return ;
 	}
 
 	public Class<?> getType()
 	{
 		if ( == null)
 			return null;
 		return .getType();
 	}
 
 	public static FieldAccessor of(Object instanceString fieldPathboolean ensurePath)
 	{
 //		System.out.println("Looking for '" + fieldPath + "' in " + object.getClass().getName());
 		FieldAccessor fa = new FieldAccessor();
 		fa.fieldPath = fieldPath;
 		fa.setFieldAndObject(instancefieldPathensurePath);
 		return fa;
 	}
 
 	private void setFieldAndObject(Object currentString fieldPathboolean ensurePath)
 	{
 		int i = fieldPath.indexOf('.');
 		if (i < 0)
 		{
 			// terminal field in the path, we initialize the internal values
 			 = getField(currentfieldPath);
 			 = current;
 			return;
 		}
 
 		// further drill-down is needed
 		String fieldName = fieldPath.substring(0, i);
 		String remainingPath = fieldPath.substring(i + 1);
 		Object memberInstance = getMemberInstance(currentfieldName);
 		if (memberInstance == null)
 		{
 			if (!ensurePath)
 				return// leaves the internal values uninitialized, setters won't work
 			memberInstance = createMemberInstance(currentfieldName);
 		}
 		setFieldAndObject(memberInstanceremainingPathensurePath);
 	}
 
 	private Field getField(Object instanceString fieldName)
 	{
 		try
 		{
 			Class<?> clz = instance.getClass();
 			while (!Object.class.equals(clz))
 			{
 				Field field = clz.getDeclaredField(fieldName);
 				if (field != null)
 					return field;
 				clz = clz.getSuperclass();
 			}
 			return null;
 		}
 		catch (Exception e)
 		{
 			throw new RuntimeException("couldn't extract '" + fieldName + "' from " + instancee);
 		}
 	}
 
 	private Object getMemberInstance(Object instanceString fieldName)
 	{
 		Field field = getField(instancefieldName);
 		try
 		{
 			field.setAccessible(true);
 			return field.get(instance);
 		}
 		catch (Exception e)
		{
			throw new RuntimeException("couldn't extract value of '" + fieldName + "' from " + instancee);
		}
	}
	private Object createMemberInstance(Object instanceString fieldName)
	{
		try
		{
			Field memberField = getField(instancefieldName);
			memberField.setAccessible(true);
			Object memberInstance = memberField.getType().newInstance();
			memberField.set(instancememberInstance);
			return memberInstance;
		}
		catch (Exception e)
		{
			throw new RuntimeException("couldn't create member '" + fieldName + "' in " + instancee);
		}
	}
	public Object getValue()
	{
		if ( == null)
			return null;
		try
		{
			return .get();
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}
	public void setValue(Object value)
	{
		if ( == null)
			throw new RuntimeException("Object containing " +  + " doesn't exist, use ensurePath=true");
		try
		{
			.set(value);
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

Similar to setValue(java.lang.Object), but doesn't require that the passed object is of the same class as the existing field. It will perform conversions where feasible. Specifically:
  • in enum fields, the method will accept any object whose toString() returns a value equal to the Enum's toString()
  • with primitives fields, the method will accept any object whose toString() returns a parseable value for the assigned primitive
	public void setValueFromAny(Object valuethrows IllegalAccessException
	{
		if (value == null)
		{
			if ( == null)
				return// nullifying a non-existing field isn't considered an error
			setValue(null);
			return;
		}
		if ( == null)
			throw new RuntimeException("Object containing " +  + " doesn't exist, use ensurePath=true");
		try
		{
			Class<?> assignFrom = value.getClass();
			Class<?> assignTo = getType();
			if (assignTo.isAssignableFrom(assignFrom))
				setValue(value);
			else
			{
				String valueAsStr = value.toString();
				if (!valueAsStr.isEmpty())
				{
					if (assignTo.isEnum())
						applyEnum(assignTovalueAsStr);
					else
					{
						Object primitive = strToPrimitive(valueAsStrassignTo);
						if (primitive != null)
							setValue(primitive);
						else
							throw new RuntimeException("Couldn't set field " +  + ": can't assign " + assignFrom.getName()
" to " + assignTo.getName());
					}
				}
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException("couldn't assign to '" +  + "' value of " + valuee);
		}
	}
	private void applyEnum(Class<?> enumTypeString enumValuethrows IllegalAccessException
	{
		for (Object e : enumType.getEnumConstants())
		{
			if (e.toString().equals(enumValue))
			{
				return;
			}
		}
		throw new RuntimeException("Value '" + enumValue + "' couldn't be assigned to enum " +  + " (of type "
enumType.getName() + ")");
	}
	private Object strToPrimitive(String valueClass<?> clz)
	{
		if (Integer.class == clz || int.class == clz)
			return Integer.parseInt(value);
		if (Double.class == clz || double.class == clz)
			return Double.parseDouble(value);
		if (Long.class == clz || long.class == clz)
			return Long.parseLong(value);
		if (Float.class == clz || float.class == clz)
			return Float.parseFloat(value);
		if (Boolean.class == clz || boolean.class == clz)
			return Boolean.parseBoolean(value);
		if (Byte.class == clz || byte.class == clz)
			return Byte.parseByte(value);
		if (Short.class == clz || short.class == clz)
			return Short.parseShort(value);
		return null;
	}
New to GrepCode? Check out our FAQ X