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

net.amygdalum.xrayinterface.IsEquivalent Maven / Gradle / Ivy

Go to download

An application to get controlled access to private fields and methods of Java classes

There is a newer version: 0.3.5
Show newest version
package net.amygdalum.xrayinterface;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
import org.hamcrest.core.IsEqual;
import org.hamcrest.core.IsNull;

public class IsEquivalent> extends BaseMatcher {

	private static final String WITH = "with";

	private Class interfaceClazz;
	private Map properties;

	public IsEquivalent(Class interfaceClazz) {
		this.interfaceClazz = interfaceClazz;
		this.properties = new LinkedHashMap();
	}

	public static > T equivalentTo(Class interfaceClazz) {
		return new XRayInterfaceWith(new IsEquivalent(interfaceClazz)).to(interfaceClazz);
	}

	protected MethodInvocationHandler handle(final String name) {
		return new MethodInvocationHandler() {

			@SuppressWarnings("unchecked")
			@Override
			public Object invoke(Object object, Object... args) throws Throwable {
				((IsEquivalent) object).properties.put(name, args[0]);
				return new XRayInterfaceWith(IsEquivalent.this).to(interfaceClazz);
			}
		};
	}

	@Override
	public boolean matches(Object item) {
		if (item == null) {
			return false;
		}
		for (Map.Entry property : properties.entrySet()) {
			String name = property.getKey();
			Object value = property.getValue();
			try {
				Object itemValue = propertyValueFor(item, name);
				Matcher matcher = matcherFor(value);
				if (!matcher.matches(itemValue)) {
					return false;
				}
			} catch (NoSuchFieldException e) {
				return false;
			}
		}
		return true;
	}

	private Object propertyValueFor(Object item, String name) throws NoSuchFieldException {
		Class currentClass = item.getClass();
		while (currentClass != null) {
			for (String fieldName : SignatureUtil.computeFieldNames(name)) {
				try {
					Field field = currentClass.getDeclaredField(fieldName);
					field.setAccessible(true);
					return field.get(item);
				} catch (Exception e) {
					continue;
				}
			}
			currentClass = currentClass.getSuperclass();
		}
		throw new NoSuchFieldException(name);
	}

	private Matcher matcherFor(Object value) {
		if (value instanceof Matcher) {
			return (Matcher) value;
		} else if (value == null) {
			return IsNull.nullValue();
		} else {
			return IsEqual.equalTo(value);
		}
	}

	@Override
	public void describeTo(Description description) {
		description.appendText("with properties ").appendValueList("", ", ", "", properties.entrySet());
	}

	@Override
	public void describeMismatch(Object item, Description description) {
		Map mismatchedProperties = new LinkedHashMap<>();
		for (Map.Entry entry : properties.entrySet()) {
			String property = entry.getKey();
			Object expected = entry.getValue();
			try {
				Object value = propertyValueFor(item, property);
				if (expected instanceof Matcher) {
					value = describe((Matcher) expected, value);
				}
				mismatchedProperties.put(property, value);
			} catch (NoSuchFieldException e) {
				mismatchedProperties.put(property, "");
			}
		}
		description.appendText("with properties ").appendValueList("", ", ", "", mismatchedProperties.entrySet());
	}

	private String describe(Matcher expected, Object value) {
		StringDescription description = new StringDescription();
		expected.describeMismatch(value, description);
		return description.toString();
	}
	
	@Override
	public boolean equals(Object obj) {
		return super.equals(obj);
	}

	private static final class XRayInterfaceWith> extends XRayInterface {
		private XRayInterfaceWith(Object object) {
			super(object);
		}

		@SuppressWarnings("unchecked")
		@Override
		protected MethodInvocationHandler findInvocationHandler(Method method) throws NoSuchMethodException, NoSuchFieldException {
			IsEquivalent satisfiesMatcher = (IsEquivalent) getObject();
			if (method.getName().startsWith(WITH) && method.getParameterTypes().length == 1 && method.getReturnType() == satisfiesMatcher.interfaceClazz) {
				return satisfiesMatcher.handle(method.getName().substring(4));
			}
			return super.findInvocationHandler(method);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy