MutatorByField.java

package org.codefilarete.reflection;

import java.lang.reflect.Field;

import org.codefilarete.tool.Reflections;

/**
 * Property writer through its {@link Field}
 *
 * @author Guillaume Mary
 */
public class MutatorByField<C, T> extends AbstractMutator<C, T>
		implements MutatorByMember<C, T, Field>, ReversibleMutator<C, T>, ValueAccessPointByField {
	
	private final Field field;
	private final Accessor<C, T> accessor;
	
	public MutatorByField(Field field) {
		Reflections.ensureAccessible(field);
		this.field = field;
		// since MutatorByField instantiation has no cost we do it now to avoid lazy initialization which is always tricky
		this.accessor = new AccessorByField<>(field, this);
	}
	
	/**
	 * Internal (package private) constructor that doesn't ensure field accessibility.
	 * Made to avoid lazy initialization in {@link AccessorByField}.
	 *
	 * @param field the field to write to
	 */
	MutatorByField(Field field, Accessor<C, T> accessor) {
		this.field = field;
		this.accessor = accessor;
	}
	
	@Override
	public Field getSetter() {
		return this.field;
	}
	
	@Override
	public Field getField() {
		return getSetter();
	}
	
	@Override
	public Class<T> getPropertyType() {
		return (Class<T>) field.getType();
	}
	
	@Override
	protected void doSet(C c, T t) throws IllegalAccessException {
		getSetter().set(c, t);
	}
	
	@Override
	protected String getSetterDescription() {
		return "mutator for field " + Reflections.toString(getSetter());
	}
	
	@Override
	public Accessor<C, T> toAccessor() {
		return this.accessor;
	}
	
	@Override
	public boolean equals(Object other) {
		// we base our implementation on the setter description because a setAccessible() call on the member changes its internal state
		// and I don't think it sould be taken into account for comparison
		return this == other
				|| (other instanceof MutatorByField && getSetterDescription().equals(((MutatorByField) other).getSetterDescription()));
	}
	
	@Override
	public int hashCode() {
		return getSetter().hashCode();
	}
}