net.amygdalum.xrayinterface.IsEquivalent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xrayinterface Show documentation
Show all versions of xrayinterface Show documentation
An application to get controlled access to private fields and methods of Java classes
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