Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
d76db0ba61 | |||
8d24604707 | |||
28d991f17c | |||
4c800cfd89 | |||
e425989106 | |||
eccad71837 | |||
cad019e44a | |||
79dcc25afc | |||
dd4e048ce5 | |||
deabaaf22f | |||
7f5c242173 | |||
7ec05d4e8a | |||
535a0dad58 | |||
2a6eba871d | |||
c44b874b41 | |||
8842e9d8e1 | |||
1891037ed7 | |||
c0da5ee75d | |||
3deee2fd5d |
@ -6,7 +6,7 @@ plugins {
|
|||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "net.tomatentum.cutin"
|
group = "net.tomatentum.cutin"
|
||||||
version = "0.1.0" + (if (!project.hasProperty("release")) ("-" + getGitHash()) else "")
|
version = "0.2.0" + (if (!project.hasProperty("release")) ("-" + getGitHash()) else "")
|
||||||
description = "A lightweight Reflection abstraction specifically but not exclusively made for tueem/Marinara."
|
description = "A lightweight Reflection abstraction specifically but not exclusively made for tueem/Marinara."
|
||||||
plugins.withType<JavaPlugin> {
|
plugins.withType<JavaPlugin> {
|
||||||
tasks.withType<Jar>().configureEach {
|
tasks.withType<Jar>().configureEach {
|
||||||
|
@ -8,3 +8,4 @@ slf4j = "2.0.17"
|
|||||||
[libraries]
|
[libraries]
|
||||||
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
|
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
|
||||||
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j"}
|
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j"}
|
||||||
|
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j"}
|
||||||
|
@ -20,6 +20,8 @@ dependencies {
|
|||||||
testImplementation(libs.junit.jupiter)
|
testImplementation(libs.junit.jupiter)
|
||||||
|
|
||||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
|
testImplementation(libs.slf4j.simple)
|
||||||
|
|
||||||
implementation(libs.slf4j)
|
implementation(libs.slf4j)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
package net.tomatentum.cutin;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import net.tomatentum.cutin.util.ReflectionUtil;
|
|
||||||
|
|
||||||
public class BestCandidateMethod<I> extends ReflectedMethod<I> {
|
|
||||||
|
|
||||||
private String methodName;
|
|
||||||
private I identifier;
|
|
||||||
private List<Object> additionalParameters;
|
|
||||||
|
|
||||||
protected BestCandidateMethod(String methodName, Object containingObject, I identifer, Object... additionalParameters) {
|
|
||||||
super(getMethod(containingObject, methodName), containingObject);
|
|
||||||
this.methodName = methodName;
|
|
||||||
this.identifier = identifer;
|
|
||||||
this.additionalParameters = Arrays.asList(additionalParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getParameter(Object context, int index) {
|
|
||||||
return additionalParameters.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public I identifier() {
|
|
||||||
return this.identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object run(Object context) {
|
|
||||||
Method[] methods = Arrays.stream(containingObject.getClass().getDeclaredMethods())
|
|
||||||
.filter(x -> x.getName().equals(methodName))
|
|
||||||
.filter(x -> !x.isBridge())
|
|
||||||
.toArray(Method[]::new);
|
|
||||||
Class<?>[] parameters = Stream.concat(
|
|
||||||
Stream.of(context.getClass()),
|
|
||||||
additionalParameters.stream().map(Object::getClass)
|
|
||||||
).toArray(Class<?>[]::new);
|
|
||||||
super.method = ReflectionUtil.getMostSpecificMethod(methods, parameters);
|
|
||||||
return super.run(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Method getMethod(Object containingMethod, String methodName) {
|
|
||||||
return Arrays.stream(containingMethod.getClass().getDeclaredMethods())
|
|
||||||
.filter(m -> m.getName().equals(methodName))
|
|
||||||
.findFirst().orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
package net.tomatentum.cutin;
|
package net.tomatentum.cutin;
|
||||||
|
|
||||||
public interface MethodExecutor {
|
public interface MethodExecutor<C extends Object> {
|
||||||
|
|
||||||
void handle(Object context);
|
void handle(C context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.tomatentum.cutin;
|
package net.tomatentum.cutin;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public interface MethodParser {
|
public interface MethodParser {
|
||||||
void parse();
|
Object parse(Method method, Object containingObject);
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ package net.tomatentum.cutin;
|
|||||||
|
|
||||||
import net.tomatentum.cutin.container.MethodContainer;
|
import net.tomatentum.cutin.container.MethodContainer;
|
||||||
|
|
||||||
public interface MethodProcessor<I extends Object> {
|
public interface MethodProcessor<I extends Object, C extends Object> {
|
||||||
|
|
||||||
void process(Object context, MethodContainer<I> methodContainer);
|
void process(Object context, MethodContainer<I, C> methodContainer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@ package net.tomatentum.cutin;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public interface ProcessorContainer<I> {
|
public interface ProcessorContainer<I extends Object, C extends Object> {
|
||||||
|
|
||||||
ProcessorContainer<I> addProcessor(MethodProcessor<I> processor);
|
ProcessorContainer<I, C> addProcessor(MethodProcessor<I, C> processor);
|
||||||
|
|
||||||
Collection<MethodProcessor<I>> processor();
|
Collection<MethodProcessor<I, C>> processor();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,26 +9,26 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import net.tomatentum.cutin.container.MethodContainer;
|
import net.tomatentum.cutin.container.MethodContainer;
|
||||||
|
|
||||||
public class ProcessorMethodExecutor<I extends Object> implements MethodExecutor, ProcessorContainer<I> {
|
public class ProcessorMethodExecutor<I extends Object, C extends Object> implements MethodExecutor<C>, ProcessorContainer<I, C> {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private MethodContainer<I> methodContainer;
|
private MethodContainer<I, C> methodContainer;
|
||||||
private Set<MethodProcessor<I>> processors;
|
private Set<MethodProcessor<I, C>> processors;
|
||||||
|
|
||||||
public ProcessorMethodExecutor(MethodContainer<I> methodContainer) {
|
public ProcessorMethodExecutor(MethodContainer<I, C> methodContainer) {
|
||||||
this.methodContainer = methodContainer;
|
this.methodContainer = methodContainer;
|
||||||
this.processors = new HashSet<>();
|
this.processors = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcessorContainer<I> addProcessor(MethodProcessor<I> processor) {
|
public ProcessorContainer<I, C> addProcessor(MethodProcessor<I, C> processor) {
|
||||||
processors.add(processor);
|
processors.add(processor);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MethodProcessor<I>> processor() {
|
public Collection<MethodProcessor<I, C>> processor() {
|
||||||
return this.processors;
|
return this.processors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,40 @@
|
|||||||
package net.tomatentum.cutin;
|
package net.tomatentum.cutin;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.List;
|
import java.util.HashMap;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.tomatentum.cutin.method.ReflectedMethod;
|
||||||
|
|
||||||
|
|
||||||
public interface ReflectedMethodFactory {
|
public interface ReflectedMethodFactory<I extends Object, C extends Object> {
|
||||||
Optional<ReflectedMethod> produce(Method method, Object containingClass);
|
Optional<ReflectedMethod<I, C>> produce(Method method, Object containingClass);
|
||||||
ReflectedMethodFactory addFactory(Factory factory);
|
ReflectedMethodFactory<I, C> addFactory(Factory<I, C> factory);
|
||||||
|
|
||||||
public interface Factory {
|
public interface Factory<I extends Object, C extends Object> {
|
||||||
|
|
||||||
Optional<ReflectedMethod> produce(Method method, Object containingObject);
|
Optional<ReflectedMethod<I, C>> produce(Method method, Object containingObject, ParserResults parserResults);
|
||||||
void addParser(ReflectedMethod method, List<MethodParser> parser);
|
void addParser(Set<MethodParser> parser);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ParserResults extends HashMap<Class<? extends MethodParser>, Object> {
|
||||||
|
|
||||||
|
public static ParserResults create(Set<MethodParser> parser, Method method, Object containingObject) {
|
||||||
|
ParserResults results = new ParserResults();
|
||||||
|
for (MethodParser p : parser) {
|
||||||
|
results.put(p.getClass(), p.parse(method, containingObject));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParserResults() {}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends Object> T get(Class<? extends MethodParser> key) {
|
||||||
|
return (T) super.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,58 +2,60 @@ package net.tomatentum.cutin;
|
|||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.tomatentum.cutin.method.ReflectedMethod;
|
||||||
import net.tomatentum.cutin.util.ReflectionUtil;
|
import net.tomatentum.cutin.util.ReflectionUtil;
|
||||||
|
|
||||||
|
|
||||||
public class ReflectedMethodFactoryImpl implements ReflectedMethodFactory {
|
public class ReflectedMethodFactoryImpl<I extends Object, C extends Object> implements ReflectedMethodFactory<I, C> {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private List<Factory> factories;
|
private List<Factory<I, C>> factories;
|
||||||
|
|
||||||
public ReflectedMethodFactoryImpl() {
|
public ReflectedMethodFactoryImpl() {
|
||||||
this(new ArrayList<>());
|
this(new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReflectedMethodFactoryImpl(List<Factory> factories) {
|
public ReflectedMethodFactoryImpl(List<Factory<I, C>> factories) {
|
||||||
this.factories = factories;
|
this.factories = factories;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ReflectedMethod> produce(Method method, Object containingClass) {
|
public Optional<ReflectedMethod<I, C>> produce(Method method, Object containingClass) {
|
||||||
Optional<ReflectedMethod> rmethod = this.factories.stream()
|
Optional<ReflectedMethod<I, C>> rmethod = this.factories.stream()
|
||||||
.map(f -> factoryProduce(f, method, containingClass))
|
.map(f -> factoryProduce(f, method, containingClass))
|
||||||
.filter(Optional::isPresent)
|
.filter(Optional::isPresent)
|
||||||
.map(Optional::get)
|
.map(Optional::get)
|
||||||
.findFirst();
|
.findFirst();
|
||||||
|
|
||||||
if (rmethod.isEmpty()) {
|
if (rmethod.isEmpty())
|
||||||
logger.debug("Could not produce a ReflectedMethod for Method {}", ReflectionUtil.getFullMethodName(method));
|
logger.warn("Could not produce a ReflectedMethod for Method {} in {}", ReflectionUtil.getFullMethodName(method), this);
|
||||||
}
|
else
|
||||||
|
logger.debug("Produced {} for Method {} in {}", rmethod.get(), ReflectionUtil.getFullMethodName(method), this);
|
||||||
|
|
||||||
return rmethod;
|
return rmethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReflectedMethodFactory addFactory(Factory factory) {
|
public ReflectedMethodFactory<I, C> addFactory(Factory<I, C> factory) {
|
||||||
this.factories.add(factory);
|
this.factories.add(factory);
|
||||||
|
logger.trace("Added Factory {} to {}", factory, this);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ReflectedMethod> factoryProduce(Factory factory, Method method, Object containingClass) {
|
private Optional<ReflectedMethod<I, C>> factoryProduce(Factory<I, C> factory, Method method, Object containingClass) {
|
||||||
List<MethodParser> parser = new ArrayList<>();
|
Set<MethodParser> parser = new HashSet<>();
|
||||||
Optional<ReflectedMethod> m = factory.produce(method, containingClass);
|
factory.addParser(parser);
|
||||||
m.ifPresent(x -> {
|
ParserResults results = ParserResults.create(parser, method, containingClass);
|
||||||
factory.addParser(x, parser);
|
return factory.produce(method, containingClass, results);
|
||||||
parser.forEach(MethodParser::parse);
|
|
||||||
});
|
|
||||||
return m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,48 +3,68 @@ package net.tomatentum.cutin.container;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import net.tomatentum.cutin.ReflectedMethod;
|
|
||||||
import net.tomatentum.cutin.ReflectedMethodFactory;
|
import net.tomatentum.cutin.ReflectedMethodFactory;
|
||||||
|
import net.tomatentum.cutin.method.ReflectedMethod;
|
||||||
|
|
||||||
public class LoneMethodContainer<I extends Object> implements MethodContainer<I> {
|
public class LoneMethodContainer<I extends Object, C extends Object> implements MethodContainer<I, C> {
|
||||||
|
|
||||||
private Map<I, ReflectedMethod<I>> methodStore;
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
private ReflectedMethodFactory factory;
|
|
||||||
|
|
||||||
public LoneMethodContainer(ReflectedMethodFactory factory) {
|
private Map<I, ReflectedMethod<I, C>> methodStore;
|
||||||
|
private ReflectedMethodFactory<I, C> factory;
|
||||||
|
|
||||||
|
public LoneMethodContainer(ReflectedMethodFactory<I, C> factory) {
|
||||||
this.methodStore = new HashMap<>();
|
this.methodStore = new HashMap<>();
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMethods(ReflectedMethod<I>... methods) {
|
public MethodContainer<I, C> addMethod(ReflectedMethod<I, C> method) {
|
||||||
for (ReflectedMethod<I> reflectedMethod : methods)
|
this.methodStore.put(method.identifier(), method);
|
||||||
this.methodStore.put(reflectedMethod.identifier(), reflectedMethod);
|
logger.debug("Added {} to container", method);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMethods(Object containingObject, Method... methods) {
|
public MethodContainer<I, C> addMethods(Object containingObject, Method... methods) {
|
||||||
for (Method method : methods)
|
for (Method method : methods)
|
||||||
this.addMethods(this.factory.produce(method, containingObject));
|
this.factory.produce(method, containingObject)
|
||||||
|
.ifPresent(this::addMethod);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ReflectedMethod<I>> methods() {
|
public Set<I> identifiers() {
|
||||||
|
return methodStore.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ReflectedMethod<I, C>> methods() {
|
||||||
return this.methodStore.values();
|
return this.methodStore.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ReflectedMethod<I>> findFor(I identifier) {
|
public Collection<ReflectedMethod<I, C>> findFor(I identifier) {
|
||||||
return Arrays.asList(this.methodStore.get(identifier));
|
ReflectedMethod<I, C> result = this.methodStore.get(identifier);
|
||||||
|
return result != null ? Arrays.asList(result) : Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ReflectedMethod<I>> findFirstFor(I identifier) {
|
public Optional<ReflectedMethod<I, C>> findFirstFor(I identifier) {
|
||||||
return findFor(identifier).stream().findFirst();
|
return findFor(identifier).stream().findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReflectedMethodFactory<I, C> factory() {
|
||||||
|
return this.factory;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,28 @@ package net.tomatentum.cutin.container;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import net.tomatentum.cutin.ReflectedMethod;
|
import net.tomatentum.cutin.method.ReflectedMethod;
|
||||||
|
|
||||||
public interface MethodContainer<I extends Object> {
|
public interface MethodContainer<I extends Object, C extends Object> {
|
||||||
|
|
||||||
void addMethods(ReflectedMethod<I>... methods);
|
MethodContainer<I, C> addMethod(ReflectedMethod<I, C> method);
|
||||||
void addMethods(Object containingObject, Method... methods);
|
default MethodContainer<I, C> addMethods(ReflectedMethod<I, C>[] methods) {
|
||||||
default void addAllMethods(Object containingObject) {
|
for (ReflectedMethod<I, C> reflectedMethod : methods) {
|
||||||
|
this.addMethod(reflectedMethod);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
MethodContainer<I, C> addMethods(Object containingObject, Method... methods);
|
||||||
|
default MethodContainer<I, C> addAllMethods(Object containingObject) {
|
||||||
this.addMethods(containingObject, containingObject.getClass().getDeclaredMethods());
|
this.addMethods(containingObject, containingObject.getClass().getDeclaredMethods());
|
||||||
};
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
Collection<ReflectedMethod<I>> methods();
|
Set<I> identifiers();
|
||||||
Collection<ReflectedMethod<I>> findFor(I identifier);
|
Collection<ReflectedMethod<I, C>> methods();
|
||||||
Optional<ReflectedMethod<I>> findFirstFor(I identifier);
|
Collection<ReflectedMethod<I, C>> findFor(I identifier);
|
||||||
|
Optional<ReflectedMethod<I, C>> findFirstFor(I identifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,50 +5,59 @@ import java.util.Collection;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import net.tomatentum.cutin.ReflectedMethod;
|
|
||||||
import net.tomatentum.cutin.ReflectedMethodFactory;
|
import net.tomatentum.cutin.ReflectedMethodFactory;
|
||||||
|
import net.tomatentum.cutin.method.ReflectedMethod;
|
||||||
import net.tomatentum.cutin.util.ReflectionUtil;
|
import net.tomatentum.cutin.util.ReflectionUtil;
|
||||||
|
|
||||||
public class MultiMethodContainer<I extends Object> implements MethodContainer<I> {
|
public class MultiMethodContainer<I extends Object, C extends Object> implements MethodContainer<I, C> {
|
||||||
|
|
||||||
private Set<Entry<I>> entries;
|
private Set<Entry<I, C>> entries;
|
||||||
private ReflectedMethodFactory factory;
|
private ReflectedMethodFactory<I, C> factory;
|
||||||
|
|
||||||
public MultiMethodContainer(ReflectedMethodFactory factory) {
|
public MultiMethodContainer(ReflectedMethodFactory<I, C> factory) {
|
||||||
this.entries = new HashSet<>();
|
this.entries = new HashSet<>();
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMethods(ReflectedMethod<I>... methods) {
|
public MethodContainer<I, C> addMethod(ReflectedMethod<I, C> method) {
|
||||||
for (ReflectedMethod<I> rMethod : methods) {
|
Optional<Entry<I, C>> oentry = this.entries.stream()
|
||||||
Optional<Entry<I>> oentry = this.entries.stream()
|
.filter(e -> method.identifier().equals(e.identifier()))
|
||||||
.filter(e -> rMethod.identifier().equals(e.identifier()))
|
|
||||||
.findFirst();
|
.findFirst();
|
||||||
Entry<I> entry = oentry.orElse(new Entry<>(rMethod.identifier())).addMethod(rMethod);
|
Entry<I, C> entry = oentry.orElse(new Entry<>(method.identifier())).addMethod(method);
|
||||||
if (oentry.isEmpty()) this.entries.add(entry);
|
if (oentry.isEmpty()) this.entries.add(entry);
|
||||||
}
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMethods(Object containingObject, Method... methods) {
|
public MethodContainer<I, C> addMethods(Object containingObject, Method... methods) {
|
||||||
for (Method method : methods)
|
for (Method method : methods)
|
||||||
this.addMethods(this.factory.produce(method, containingObject));
|
this.factory.produce(method, containingObject)
|
||||||
|
.ifPresent(this::addMethod);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ReflectedMethod<I>> methods() {
|
public Set<I> identifiers() {
|
||||||
|
return entries().stream()
|
||||||
|
.map(Entry::identifier)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ReflectedMethod<I, C>> methods() {
|
||||||
return this.entries.stream()
|
return this.entries.stream()
|
||||||
.flatMap(e -> e.methods.stream())
|
.flatMap(e -> e.methods.stream())
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ReflectedMethod<I>> findFor(I identifier) {
|
public Collection<ReflectedMethod<I, C>> findFor(I identifier) {
|
||||||
return this.entries.stream()
|
return this.entries.stream()
|
||||||
.filter(e -> e.identifier().equals(identifier))
|
.filter(e -> e.identifier().equals(identifier))
|
||||||
.flatMap(e -> e.methods.stream())
|
.flatMap(e -> e.methods.stream())
|
||||||
@ -56,14 +65,22 @@ public class MultiMethodContainer<I extends Object> implements MethodContainer<I
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ReflectedMethod<I>> findFirstFor(I identifier) {
|
public Optional<ReflectedMethod<I, C>> findFirstFor(I identifier) {
|
||||||
return this.entries.stream()
|
return this.entries.stream()
|
||||||
.filter(e -> e.identifier().equals(identifier))
|
.filter(e -> e.identifier().equals(identifier))
|
||||||
.flatMap(e -> e.methods.stream())
|
.flatMap(e -> e.methods.stream())
|
||||||
.findFirst();
|
.findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static record Entry<I extends Object>(I identifier, Set<ReflectedMethod<I>> methods) {
|
protected Set<Entry<I, C>> entries() {
|
||||||
|
return this.entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReflectedMethodFactory<I, C> factory() {
|
||||||
|
return this.factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static record Entry<I extends Object, C extends Object>(I identifier, Set<ReflectedMethod<I, C>> methods) {
|
||||||
|
|
||||||
public Entry(I identifier) {
|
public Entry(I identifier) {
|
||||||
this(identifier, new HashSet<>());
|
this(identifier, new HashSet<>());
|
||||||
@ -71,33 +88,22 @@ public class MultiMethodContainer<I extends Object> implements MethodContainer<I
|
|||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(Entry.class);
|
private static Logger logger = LoggerFactory.getLogger(Entry.class);
|
||||||
|
|
||||||
public Entry<I> addMethod(ReflectedMethod<I> method) {
|
public Entry<I, C> addMethod(ReflectedMethod<I, C> method) {
|
||||||
I midentifier = method.identifier();
|
I midentifier = method.identifier();
|
||||||
|
|
||||||
if (!this.identifier().equals(midentifier))
|
if (!this.identifier().equals(midentifier))
|
||||||
throw new IllegalArgumentException("Method's identifier did not equal the entry's identifier");
|
throw new IllegalArgumentException("Method's identifier did not equal the entry's identifier");
|
||||||
|
|
||||||
this.methods.add(method);
|
this.methods.add(method);
|
||||||
logger.debug("Added method {} to entry {}", method.method().getName(), this);
|
logger.debug("Added method {} to entry {}", ReflectionUtil.getFullMethodName(method.method()), this);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object[] runAll(Object context) {
|
|
||||||
logger.trace("Running all Methods from {} with context {}", this, context);
|
|
||||||
return this.methods.stream()
|
|
||||||
.map(x -> {
|
|
||||||
logger.debug("Running Method {} from {} with context {}", x, this, context);
|
|
||||||
return x.run(context);
|
|
||||||
})
|
|
||||||
.flatMap(ReflectionUtil::getReturnAsStream)
|
|
||||||
.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!(obj instanceof Entry))
|
if (!(obj instanceof Entry))
|
||||||
return false;
|
return false;
|
||||||
Entry<?> other = (Entry<?>) obj;
|
Entry<?, ?> other = (Entry<?, ?>) obj;
|
||||||
return other.identifier().equals(identifier());
|
return other.identifier().equals(identifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +114,7 @@ public class MultiMethodContainer<I extends Object> implements MethodContainer<I
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Content(%s)".formatted(identifier().toString());
|
return "Ident(%s)".formatted(identifier().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
package net.tomatentum.cutin.method;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.tomatentum.cutin.ReflectedMethodFactory;
|
||||||
|
import net.tomatentum.cutin.ReflectedMethodFactory.ParserResults;
|
||||||
|
import net.tomatentum.cutin.container.MethodContainer;
|
||||||
|
import net.tomatentum.cutin.util.ReflectionUtil;
|
||||||
|
|
||||||
|
public abstract class BestCandidateMethod<I extends Object, C extends Object> extends ReflectedMethod<I, C> {
|
||||||
|
|
||||||
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
private String methodName;
|
||||||
|
|
||||||
|
protected BestCandidateMethod(String methodName, Object containingObject) {
|
||||||
|
super(getMethod(containingObject, methodName), containingObject);
|
||||||
|
this.methodName = methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object run(C context) {
|
||||||
|
Method[] methods = Arrays.stream(containingObject.getClass().getDeclaredMethods())
|
||||||
|
.filter(x -> x.getName().equals(methodName))
|
||||||
|
.filter(x -> !x.isBridge())
|
||||||
|
.toArray(Method[]::new);
|
||||||
|
Class<?>[] parameters = getCurrentParameterList(context).stream()
|
||||||
|
.map(Object::getClass)
|
||||||
|
.toArray(Class<?>[]::new);
|
||||||
|
super.method = ReflectionUtil.getMostSpecificMethod(methods, parameters);
|
||||||
|
logger.trace("Found {} for {}({}) in {}", ReflectionUtil.getFullMethodName(method()), this.methodName, String.join(", ", Arrays.stream(parameters).map(Object::toString).toList()), this);
|
||||||
|
return super.run(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Method getMethod(Object containingMethod, String methodName) {
|
||||||
|
return Arrays.stream(containingMethod.getClass().getDeclaredMethods())
|
||||||
|
.filter(m -> m.getName().equals(methodName))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof BestCandidateMethod<?, ?> bcMethod) {
|
||||||
|
return this.containingObject().getClass().equals(bcMethod.containingObject().getClass()) &&
|
||||||
|
this.methodName.equals(bcMethod.methodName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(containingObject.getClass(), methodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Object> getCurrentParameterList(C context) {
|
||||||
|
List<Object> parameters = new ArrayList<>();
|
||||||
|
int c = 0;
|
||||||
|
Object last;
|
||||||
|
while ((last = getParameter(context, c)) != null) {
|
||||||
|
parameters.add(last);
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class Factory<I extends Object, C extends Object> implements ReflectedMethodFactory.Factory<I, C> {
|
||||||
|
|
||||||
|
private MethodContainer<I, C> methodContainer;
|
||||||
|
private String methodName;
|
||||||
|
|
||||||
|
protected Factory(MethodContainer<I, C> methodContainer, String methodName) {
|
||||||
|
this.methodContainer = methodContainer;
|
||||||
|
this.methodName = methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ReflectedMethod<I, C>> produce(Method method, Object containingObject, ParserResults results) {
|
||||||
|
Optional<BestCandidateMethod<I, C>> bcMethod = bcProduce(methodName, containingObject, results);
|
||||||
|
if (bcMethod.isEmpty() || methodContainer.methods().contains(bcMethod.get()))
|
||||||
|
return Optional.empty();
|
||||||
|
return Optional.of(bcMethod.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Optional<BestCandidateMethod<I, C>> bcProduce(String methodName, Object containingObject, ParserResults results);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package net.tomatentum.cutin;
|
package net.tomatentum.cutin.method;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@ -12,7 +12,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import net.tomatentum.cutin.util.ReflectionUtil;
|
import net.tomatentum.cutin.util.ReflectionUtil;
|
||||||
|
|
||||||
public abstract class ReflectedMethod<I extends Object> {
|
public abstract class ReflectedMethod<I extends Object, C extends Object> {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
@ -26,16 +26,17 @@ public abstract class ReflectedMethod<I extends Object> {
|
|||||||
this.containingObject = containingObject;
|
this.containingObject = containingObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Object getParameter(Object context, int index);
|
public abstract Object getParameter(C context, int index);
|
||||||
|
|
||||||
public abstract I identifier();
|
public abstract I identifier();
|
||||||
|
|
||||||
public Object run(Object context) {
|
public Object run(C context) {
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
try {
|
try {
|
||||||
|
logger.debug("Invoking method {} from {}", ReflectionUtil.getFullMethodName(method), this);
|
||||||
return method.invoke(containingObject, getParameters(context));
|
return method.invoke(containingObject, getParameters(context));
|
||||||
}catch (IllegalAccessException | InvocationTargetException ex) {
|
}catch (IllegalAccessException | InvocationTargetException ex) {
|
||||||
logger.error("ReflectedMethod failed to run", ex);
|
logger.error("ReflectedMethod %s failed to run".formatted(this), ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,18 +49,18 @@ public abstract class ReflectedMethod<I extends Object> {
|
|||||||
return this.containingObject;
|
return this.containingObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object[] getParameters(Object context) {
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ReflectedMethod(%s)".formatted(identifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object[] getParameters(C context) {
|
||||||
int parameterCount = method.getParameterCount();
|
int parameterCount = method.getParameterCount();
|
||||||
List<Object> parameters = new ArrayList<>();
|
List<Object> parameters = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = 0; i < parameterCount; i++) {
|
for (int i = 0; i < parameterCount; i++) {
|
||||||
Object parameter;
|
Object parameter = getParameter(context, i);
|
||||||
if (i == 0) {
|
logger.trace("Found parameter {}={} for method {} in {}", parameter != null ? parameter.getClass().toString() : " ", parameter, ReflectionUtil.getFullMethodName(method), this);
|
||||||
parameter = context;
|
|
||||||
}else
|
|
||||||
parameter = getParameter(context, i-1);
|
|
||||||
|
|
||||||
logger.trace("Found parameter {}={} for method {}", parameter != null ? parameter.getClass().toString() : " ", parameter, ReflectionUtil.getFullMethodName(method));
|
|
||||||
parameters.add(parameter);
|
parameters.add(parameter);
|
||||||
}
|
}
|
||||||
return parameters.toArray();
|
return parameters.toArray();
|
@ -135,6 +135,7 @@ public final class ReflectionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getFullMethodName(Method method) {
|
public static String getFullMethodName(Method method) {
|
||||||
return method.getDeclaringClass().getName() + "." + method.getName();
|
List<String> parameters = Arrays.stream(method.getParameterTypes()).map(Object::toString).toList();
|
||||||
|
return String.format("%s.%s(%s)", method.getDeclaringClass().getName(), method.getName(), String.join(", ", parameters));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,23 +4,25 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import net.tomatentum.cutin.method.ReflectedMethod;
|
||||||
|
|
||||||
class ReflectedMethodTest {
|
class ReflectedMethodTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void methodTest() {
|
void methodTest() {
|
||||||
ReflectedMethod<String> method = new TestReflectedMethod(new TestMethodClass());
|
ReflectedMethod<String, String> method = new TestReflectedMethod(new TestMethodClass());
|
||||||
Object result = method.run("testContext");
|
Object result = method.run("testContext");
|
||||||
assertTrue((boolean)result);
|
assertTrue((boolean)result);
|
||||||
|
System.out.println("Success");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBCMethod() {
|
void testBCMethod() {
|
||||||
ReflectedMethod<?> method = new BestCandidateMethod<String>(
|
ReflectedMethod<String, Double> method = new TestBestCandidateMethod(
|
||||||
"test",
|
"test",
|
||||||
new TestMethodClass(),
|
new TestMethodClass());
|
||||||
"ident",
|
|
||||||
"testString");
|
|
||||||
Object result = method.run((double)4);
|
Object result = method.run((double)4);
|
||||||
assertTrue((boolean)result);
|
assertTrue((boolean)result);
|
||||||
|
System.out.println("Success");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package net.tomatentum.cutin;
|
||||||
|
|
||||||
|
import net.tomatentum.cutin.method.BestCandidateMethod;
|
||||||
|
|
||||||
|
public class TestBestCandidateMethod extends BestCandidateMethod<String, Double> {
|
||||||
|
|
||||||
|
protected TestBestCandidateMethod(String methodName, Object containingObject) {
|
||||||
|
super(methodName, containingObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getParameter(Double context, int index) {
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return context;
|
||||||
|
case 1:
|
||||||
|
return "testString";
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String identifier() {
|
||||||
|
return "ident";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,7 +2,9 @@ package net.tomatentum.cutin;
|
|||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public class TestReflectedMethod extends ReflectedMethod<String> {
|
import net.tomatentum.cutin.method.ReflectedMethod;
|
||||||
|
|
||||||
|
public class TestReflectedMethod extends ReflectedMethod<String, String> {
|
||||||
|
|
||||||
protected TestReflectedMethod(Object containingObject) {
|
protected TestReflectedMethod(Object containingObject) {
|
||||||
super(getMethod(containingObject), containingObject);
|
super(getMethod(containingObject), containingObject);
|
||||||
@ -10,8 +12,15 @@ public class TestReflectedMethod extends ReflectedMethod<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getParameter(Object context, int index) {
|
public Object getParameter(String context, int index) {
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return context;
|
||||||
|
case 1:
|
||||||
return 2;
|
return 2;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
7
lib/src/test/resources/simplelogger.properties
Normal file
7
lib/src/test/resources/simplelogger.properties
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# SLF4J's SimpleLogger configuration file
|
||||||
|
# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err.
|
||||||
|
|
||||||
|
# Default logging detail level for all instances of SimpleLogger.
|
||||||
|
# Must be one of ("trace", "debug", "info", "warn", or "error").
|
||||||
|
# If not specified, defaults to "info".
|
||||||
|
org.slf4j.simpleLogger.defaultLogLevel=trace
|
Loading…
x
Reference in New Issue
Block a user