FieldValueReference.java

package org.cyclopsgroup.caff.ref;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * Implementation of value reference that based on a public field
 *
 * @author <a href="mailto:jiaqi@cyclopsgroup.org">Jiaqi Guo</a>
 * @param <T> Type of value
 */
class FieldValueReference<T> extends ValueReference<T> {
  private final Field field;
  private final boolean publicField;

  /**
   * @param field Reflection field object
   */
  FieldValueReference(Field field) {
    this.field = Preconditions.checkNotNull(field, "An input field is required.");
    this.publicField = (field.getModifiers() & Modifier.PUBLIC) > 0;
  }

  @Override
  public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
    return field.getAnnotation(annotationType);
  }

  @Override
  public ImmutableList<AnnotatedElement> getAnontatedElements() {
    return ImmutableList.of(field);
  }

  @Override
  public String getName() {
    return field.getName();
  }

  @Override
  public Class<?> getType() {
    return field.getType();
  }

  @Override
  public boolean isReadable() {
    return true;
  }

  @Override
  public boolean isWritable() {
    return !Modifier.isFinal(field.getModifiers());
  }

  @Override
  public Object readValue(final T owner) throws AccessFailureException {
    if (!publicField && !field.isAccessible()) {
      field.setAccessible(true);
    }
    try {
      return field.get(owner);
    } catch (IllegalAccessException e) {
      throw new AccessFailureException("Can't get field " + field + " of " + owner, e);
    }
  }

  @Override
  public void writeValue(Object value, T owner) throws AccessFailureException {
    if (value == null && field.getType().isPrimitive()) {
      return;
    }
    if (!publicField && !field.isAccessible()) {
      field.setAccessible(true);
    }
    try {
      field.set(owner, value);
    } catch (IllegalAccessException e) {
      throw new AccessFailureException(
          "Can't set field " + field + " of " + owner + " to " + value, e);
    }
  }
}