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

net.amygdalum.xrayinterface.XRayInterface 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 static java.util.stream.Collectors.toList;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * XRay is a Decorator for any object (or class) that should get a new public interface. Usage:
 * 
 * 

* InterfaceOfTheDecorator unlocked = XRayInterface.xray(object).to(InterfaceOfTheDecorator.class); * *

* After that the variable unlocked contains an object of type InterfaceOfTheDecorator, where each method is mapped according to the xrayinterface conventions: * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
mapping conventions
MethodMaps to
void setProperty([sometype] t)void setProperty([sometype] t)if exists
property = t;if there is a property [sometype] property;
[sometype] getProperty()[sometype] getProperty()if exists
return property;if there is a property [sometype] property;
[booleantype] isProperty()[booleantype] getProperty()if exists
return property;if there is a property [booleantype] property;
[return type] methodname([signature])[return type] methodname([signature])
* * @author Stefan Mandel */ public class XRayInterface extends InvocationResolver implements InvocationHandler { private Map methods; private Object object; public XRayInterface(Object object) { super(object.getClass()); this.methods = new HashMap(); this.object = object; } public XRayInterface(Class clazz) { super(clazz); this.methods = new HashMap(); } public Map getInterfaceMethods() { return methods; } public List getConstructors() { return methods.values().stream() .filter(value -> value instanceof ConstructorInvoker) .map(value -> (ConstructorInvoker) value) .collect(toList()); } public List getFieldProperties() { Map properties = new LinkedHashMap<>(); for (FieldSetter setter : getFieldSetters()) { String field = setter.getFieldName(); FieldProperty property = properties.computeIfAbsent(field, key -> new FieldProperty()); property.setSetter(setter); } for (FieldGetter getter : getFieldGetters()) { String field = getter.getFieldName(); FieldProperty property = properties.computeIfAbsent(field, key -> new FieldProperty()); property.setGetter(getter); } return new ArrayList<>(properties.values()); } public List getFieldSetters() { return filteredMethods(FieldSetter.class); } public List getFieldGetters() { return filteredMethods(FieldGetter.class); } public List getStaticProperties() { Map properties = new LinkedHashMap<>(); for (StaticSetter setter : getStaticSetters()) { String field = setter.getFieldName(); StaticProperty property = properties.computeIfAbsent(field, key -> new StaticProperty()); property.setSetter(setter); } for (StaticGetter getter : getStaticGetters()) { String field = getter.getFieldName(); StaticProperty property = properties.computeIfAbsent(field, key -> new StaticProperty()); property.setGetter(getter); } return new ArrayList<>(properties.values()); } public List getStaticSetters() { return filteredMethods(StaticSetter.class); } public List getStaticGetters() { return filteredMethods(StaticGetter.class); } public List getMethods() { return filteredMethods(MethodInvoker.class); } public List getStaticMethods() { return filteredMethods(StaticMethodInvoker.class); } private List filteredMethods(Class clazz) { return methods.values().stream() .filter(value -> clazz.isInstance(value)) .map(value -> clazz.cast(value)) .collect(toList()); } public Object getObject() { return object; } /** * wraps the given object. The result of this method will be decoratable with the new interface * * @param object the object to unlock/decorate * @return the wrapped object */ public static XRayInterface xray(Object object) { if (object instanceof Class) { return new XRayInterface((Class) object); } else { return new XRayInterface(object); } } /** * maps the given interface to the wrapped object * * @param interfaceClass the given interface class (defining the type of the result) * @param the type to wrap the object in * @return an object of the type of interfaceClass (mapped to the members of the wrapped object) */ @SuppressWarnings("unchecked") public T to(Class interfaceClass) { try { List> todo = new ArrayList>(); Set> done = new HashSet>(); todo.add(interfaceClass); while (!todo.isEmpty()) { Class currentClass = todo.remove(0); done.add(currentClass); for (Method method : currentClass.getDeclaredMethods()) { if (!methods.containsKey(method)) { methods.put(method, findInvocationHandler(method)); } for (Class superInterfaceClazz : currentClass.getInterfaces()) { if (!done.contains(superInterfaceClazz)) { todo.add(superInterfaceClazz); } } } } return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[] { interfaceClass }, this); } catch (NoSuchFieldException e) { throw new InterfaceMismatchException("cannot resolve property " + e.getMessage() + " on " + getType()); } catch (NoSuchMethodException e) { throw new InterfaceMismatchException("cannot resolve method/property " + e.getMessage() + " on " + getType()); } } /** * collects all methods of the given interface conflicting with the wrapped object * * @param interfaceClazz the interface to check on conflicts * @return a list of methods conflicting */ public List unMappable(Class interfaceClazz) { List conflicts = new LinkedList(); for (Method method : interfaceClazz.getDeclaredMethods()) { try { findInvocationHandler(method); } catch (NoSuchFieldException | NoSuchMethodException e) { conflicts.add(method); } } return conflicts; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocationHandler handler = methods.get(method); if (handler != null) { return handler.invoke(object, args); } else { return method.invoke(this, args); } } @Override public int hashCode() { return object.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof Proxy) { return obj.equals(this); } else { return super.equals(obj); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy