All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.whaka.util.reflection.properties.GetterClassProperty Maven / Gradle / Ivy

package org.whaka.util.reflection.properties;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.Objects;

import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Primitives;
import org.whaka.util.reflection.Visibility;

/**
 * @see #isTypeCompatible(Method, Method)
 */
public class GetterClassProperty implements ClassProperty {

	private final Method getter;
	private final Method setter;
	private final ClassPropertyKey key;
	private final Visibility visibility;
	
	public GetterClassProperty(Method getter) {
		this(getter, null);
	}
	
	public GetterClassProperty(Method getter, Method setter) {
		this.getter = assertGetter(getter);
		this.setter = assertSetter(getter, setter);
		key = new ClassPropertyKey(getter.getName() + "()", getter.getDeclaringClass());
		visibility = Visibility.getFromModifiers(getter.getModifiers());
	}
	
	private static Method assertGetter(Method getter) {
		Objects.requireNonNull(getter, "Getter method cannot be null!");
		Preconditions.checkArgument(getter.getReturnType() != void.class, "Getter cannot have return type 'void'!");
		Preconditions.checkArgument(getter.getParameterCount() == 0, "Getter cannot have any arguments!");
		return getter;
	}
	
	private static Method assertSetter(Method getter, Method setter) {
		if (setter != null) {
			assertConsistentlyStatic(getter, setter);
			assertSetterArguments(setter);
			assertSetterTypeCompatible(getter, setter);
		}
		return setter;
	}
	
	private static void assertConsistentlyStatic(Method getter, Method setter) {
		boolean getterStatic = Modifier.isStatic(getter.getModifiers());
		boolean setterStatic = Modifier.isStatic(setter.getModifiers());
		Preconditions.checkArgument(getterStatic == setterStatic,
				"Getter and setter should be either both static or both NOT static!");
	}
	
	private static void assertSetterArguments(Method setter) {
		Preconditions.checkArgument(setter.getParameterCount() == 1, "Setter method should have exactly one argument");
	}
	
	private static void assertSetterTypeCompatible(Method getter, Method setter) {
		Preconditions.checkArgument(isTypeCompatible(getter, setter), "Setter and getter are not type compatible!");
	}

	/**
	 * Checks if return type of the specified getter is compatible with the type of the first argument of the
	 * specified setter. Types compatible if next conditions are satisfied:
	 * 
    *
  • If setter type is a primitive - then getter type is equal *
  • If getter type is a primitive - then setter type is the corresponding wrapper or its ancestor *
  • Setter type is assignable from getter type *
* @throws IndexOutOfBoundsException if specified setter has no arguments */ public static boolean isTypeCompatible(Method getter, Method setter) { Class getterType = getter.getReturnType(); Class setterType = setter.getParameterTypes()[0]; return isTypesCompatible(getterType, setterType); } private static boolean isTypesCompatible(Class getterType, Class setterType) { if (setterType.isPrimitive()) return getterType == setterType; if (getterType.isPrimitive()) getterType = Primitives.wrap(getterType); return setterType.isAssignableFrom(getterType); } @Override public ClassPropertyKey getKey() { return key; } @Override @SuppressWarnings("unchecked") public Class getType() { return (Class) getter.getReturnType(); } @Override public ParameterizedType getGenericType() { return (ParameterizedType) getter.getGenericReturnType(); } @Override public boolean isStatic() { return Modifier.isStatic(getter.getModifiers()); } @Override public Visibility getVisibility() { return visibility; } public Method getGetter() { return getter; } public Method getSetter() { return setter; } /** * @throws SecurityException if property getter cannot be accessed * @throws IllegalAccessException if property getter is inaccessible. * @throws IllegalArgumentException if property getter is an * instance method and the specified object argument * is not an instance of the class or interface * declaring the underlying method (or of a subclass * or implementor thereof); * @throws InvocationTargetException if the underlying method throws an exception. * @throws NullPointerException if the specified object is null and the method is an instance method. * @throws ExceptionInInitializerError if the initialization provoked by this method fails. * @see Method#invoke(Object, Object...) */ @Override @SuppressWarnings("unchecked") public Type getValue(TargetType target) throws Exception { getter.setAccessible(true); return (Type) getter.invoke(target); } /** * @throws UnsupportedOperationException is {@link #isMutable()} returns false. * @throws SecurityException if property getter cannot be accessed * @throws IllegalAccessException if property getter is inaccessible. * @throws IllegalArgumentException if property getter is an * instance method and the specified object argument * is not an instance of the class or interface * declaring the underlying method (or of a subclass * or implementor thereof); * @throws InvocationTargetException if the underlying method throws an exception. * @throws NullPointerException if the specified object is null and the method is an instance method. * @throws ExceptionInInitializerError if the initialization provoked by this method fails. * @see Method#invoke(Object, Object...) */ @Override public void setValue(TargetType target, Type value) throws Exception, UnsupportedOperationException, IllegalArgumentException { if (!isMutable()) throw new UnsupportedOperationException("Cannot set new value! Setter is not present!"); setter.setAccessible(true); try { setter.invoke(target, value); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Illegal argument: " + value + "! Expected type: " + getType(), e); } } /** * Returns false if setter wasn't specified for this property. */ @Override public boolean isMutable() { return setter != null; } @Override public int hashCode() { return Objects.hash(getGetter(), getSetter()); } @Override public boolean equals(Object object) { if (object != null && getClass() == object.getClass()) { GetterClassProperty that = (GetterClassProperty) object; return Objects.equals(getGetter(), that.getGetter()) && Objects.equals(getSetter(), that.getSetter()); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .omitNullValues() .add("getter", getGetter()) .add("setter", getSetter()) .toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy