Compare commits
	
		
			16 Commits
		
	
	
		
			v0.1.0
			...
			4c800cfd89
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 4c800cfd89 | |||
| e425989106 | |||
| eccad71837 | |||
| cad019e44a | |||
| 79dcc25afc | |||
| dd4e048ce5 | |||
| deabaaf22f | |||
| 7f5c242173 | |||
| 7ec05d4e8a | |||
| 535a0dad58 | |||
| 2a6eba871d | |||
| c44b874b41 | |||
| 8842e9d8e1 | |||
| 1891037ed7 | |||
| c0da5ee75d | |||
| 3deee2fd5d | 
| @@ -6,7 +6,7 @@ plugins { | ||||
|  | ||||
| allprojects { | ||||
|     group = "net.tomatentum.cutin" | ||||
|     version = "0.1.0" + (if (!project.hasProperty("release")) ("-" + getGitHash()) else "") | ||||
|     version = "0.1.1" + (if (!project.hasProperty("release")) ("-" + getGitHash()) else "") | ||||
|     description = "A lightweight Reflection abstraction specifically but not exclusively made for tueem/Marinara." | ||||
|     plugins.withType<JavaPlugin> { | ||||
|         tasks.withType<Jar>().configureEach { | ||||
|   | ||||
| @@ -8,3 +8,4 @@ slf4j = "2.0.17" | ||||
| [libraries] | ||||
| junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" } | ||||
| 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) | ||||
|  | ||||
|     testRuntimeOnly("org.junit.platform:junit-platform-launcher") | ||||
|     testImplementation(libs.slf4j.simple) | ||||
|  | ||||
|     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; | ||||
|  | ||||
| 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; | ||||
|  | ||||
| import java.lang.reflect.Method; | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 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 MethodContainer<I> methodContainer; | ||||
|     private Set<MethodProcessor<I>> processors; | ||||
|     private MethodContainer<I, C> methodContainer; | ||||
|     private Set<MethodProcessor<I, C>> processors; | ||||
|  | ||||
|     public ProcessorMethodExecutor(MethodContainer<I> methodContainer) { | ||||
|     public ProcessorMethodExecutor(MethodContainer<I, C> methodContainer) { | ||||
|         this.methodContainer = methodContainer; | ||||
|         this.processors = new HashSet<>(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public ProcessorContainer<I> addProcessor(MethodProcessor<I> processor) { | ||||
|     public ProcessorContainer<I, C> addProcessor(MethodProcessor<I, C> processor) { | ||||
|         processors.add(processor); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Collection<MethodProcessor<I>> processor() { | ||||
|     public Collection<MethodProcessor<I, C>> processor() { | ||||
|         return this.processors; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,18 +1,35 @@ | ||||
| package net.tomatentum.cutin; | ||||
|  | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.List; | ||||
| import java.util.HashMap; | ||||
| import java.util.Optional; | ||||
| import java.util.Set; | ||||
|  | ||||
| import net.tomatentum.cutin.method.ReflectedMethod; | ||||
|  | ||||
|  | ||||
| public interface ReflectedMethodFactory { | ||||
|     Optional<ReflectedMethod> produce(Method method, Object containingClass); | ||||
|     ReflectedMethodFactory addFactory(Factory factory); | ||||
| public interface ReflectedMethodFactory<I extends Object, C extends Object> { | ||||
|     Optional<ReflectedMethod<I, C>> produce(Method method, Object containingClass); | ||||
|     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); | ||||
|         void addParser(ReflectedMethod method, List<MethodParser> parser); | ||||
|         Optional<ReflectedMethod<I, C>> produce(Method method, Object containingObject, ParserResults parserResults); | ||||
|         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() {} | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -2,58 +2,60 @@ package net.tomatentum.cutin; | ||||
|  | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashSet; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| import java.util.Set; | ||||
|  | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import net.tomatentum.cutin.method.ReflectedMethod; | ||||
| 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 List<Factory> factories; | ||||
|     private List<Factory<I, C>> factories; | ||||
|  | ||||
|     public ReflectedMethodFactoryImpl() { | ||||
|         this(new ArrayList<>()); | ||||
|     } | ||||
|  | ||||
|     public ReflectedMethodFactoryImpl(List<Factory> factories) { | ||||
|     public ReflectedMethodFactoryImpl(List<Factory<I, C>> factories) { | ||||
|         this.factories = factories; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Optional<ReflectedMethod> produce(Method method, Object containingClass) { | ||||
|         Optional<ReflectedMethod> rmethod = this.factories.stream() | ||||
|     public Optional<ReflectedMethod<I, C>> produce(Method method, Object containingClass) { | ||||
|         Optional<ReflectedMethod<I, C>> rmethod = this.factories.stream() | ||||
|             .map(f -> factoryProduce(f, method, containingClass)) | ||||
|             .filter(Optional::isPresent) | ||||
|             .map(Optional::get) | ||||
|             .findFirst(); | ||||
|  | ||||
|         if (rmethod.isEmpty()) { | ||||
|             logger.debug("Could not produce a ReflectedMethod for Method {}", ReflectionUtil.getFullMethodName(method)); | ||||
|         } | ||||
|         if (rmethod.isEmpty())  | ||||
|             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; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public ReflectedMethodFactory addFactory(Factory factory) { | ||||
|     public ReflectedMethodFactory<I, C> addFactory(Factory<I, C> factory) { | ||||
|         this.factories.add(factory); | ||||
|         logger.trace("Added Factory {} to {}", factory, this); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     private Optional<ReflectedMethod> factoryProduce(Factory factory, Method method, Object containingClass) { | ||||
|         List<MethodParser> parser = new ArrayList<>(); | ||||
|         Optional<ReflectedMethod> m = factory.produce(method, containingClass); | ||||
|         m.ifPresent(x -> { | ||||
|             factory.addParser(x, parser);  | ||||
|             parser.forEach(MethodParser::parse); | ||||
|         }); | ||||
|         return m; | ||||
|     private Optional<ReflectedMethod<I, C>> factoryProduce(Factory<I, C> factory, Method method, Object containingClass) { | ||||
|         Set<MethodParser> parser = new HashSet<>(); | ||||
|         factory.addParser(parser);  | ||||
|         ParserResults results = ParserResults.create(parser, method, containingClass); | ||||
|         return factory.produce(method, containingClass, results); | ||||
|     } | ||||
|      | ||||
| } | ||||
|   | ||||
| @@ -3,48 +3,68 @@ package net.tomatentum.cutin.container; | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.Arrays; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 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.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 ReflectedMethodFactory factory; | ||||
|     private Logger logger = LoggerFactory.getLogger(getClass()); | ||||
|  | ||||
|     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.factory = factory; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void addMethods(ReflectedMethod<I>... methods) { | ||||
|         for (ReflectedMethod<I> reflectedMethod : methods) | ||||
|             this.methodStore.put(reflectedMethod.identifier(), reflectedMethod); | ||||
|     public MethodContainer<I, C> addMethod(ReflectedMethod<I, C> method) { | ||||
|         this.methodStore.put(method.identifier(), method); | ||||
|         logger.debug("Added {} to container", method); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void addMethods(Object containingObject, Method... methods) { | ||||
|     public MethodContainer<I, C> addMethods(Object containingObject, Method... methods) { | ||||
|         for (Method method : methods) | ||||
|             this.addMethods(this.factory.produce(method, containingObject)); | ||||
|             this.factory.produce(method, containingObject) | ||||
|                 .ifPresent(this::addMethod); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Collection<ReflectedMethod<I>> methods() { | ||||
|     public Set<I> identifiers() { | ||||
|         return methodStore.keySet(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Collection<ReflectedMethod<I, C>> methods() { | ||||
|         return this.methodStore.values(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Collection<ReflectedMethod<I>> findFor(I identifier) { | ||||
|         return Arrays.asList(this.methodStore.get(identifier)); | ||||
|     public Collection<ReflectedMethod<I, C>> findFor(I identifier) { | ||||
|         ReflectedMethod<I, C> result = this.methodStore.get(identifier); | ||||
|         return result != null ? Arrays.asList(result) : Collections.emptyList(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Optional<ReflectedMethod<I>> findFirstFor(I identifier) { | ||||
|     public Optional<ReflectedMethod<I, C>> findFirstFor(I identifier) { | ||||
|         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.util.Collection; | ||||
| 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); | ||||
|     void addMethods(Object containingObject, Method... methods); | ||||
|     default void addAllMethods(Object containingObject) { | ||||
|     MethodContainer<I, C> addMethod(ReflectedMethod<I, C> method); | ||||
|     default MethodContainer<I, C> addMethods(ReflectedMethod<I, C>[] methods) { | ||||
|         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()); | ||||
|     }; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     Collection<ReflectedMethod<I>> methods(); | ||||
|     Collection<ReflectedMethod<I>> findFor(I identifier); | ||||
|     Optional<ReflectedMethod<I>> findFirstFor(I identifier); | ||||
|     Set<I> identifiers(); | ||||
|     Collection<ReflectedMethod<I, C>> methods(); | ||||
|     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.Optional; | ||||
| import java.util.Set; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import net.tomatentum.cutin.ReflectedMethod; | ||||
| import net.tomatentum.cutin.ReflectedMethodFactory; | ||||
| import net.tomatentum.cutin.method.ReflectedMethod; | ||||
| 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 ReflectedMethodFactory factory; | ||||
|     private Set<Entry<I, C>> entries; | ||||
|     private ReflectedMethodFactory<I, C> factory; | ||||
|  | ||||
|     public MultiMethodContainer(ReflectedMethodFactory factory) { | ||||
|     public MultiMethodContainer(ReflectedMethodFactory<I, C> factory) { | ||||
|         this.entries = new HashSet<>(); | ||||
|         this.factory = factory; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void addMethods(ReflectedMethod<I>... methods) { | ||||
|         for (ReflectedMethod<I> rMethod : methods) { | ||||
|             Optional<Entry<I>> oentry = this.entries.stream() | ||||
|                 .filter(e -> rMethod.identifier().equals(e.identifier())) | ||||
|     public MethodContainer<I, C> addMethod(ReflectedMethod<I, C> method) { | ||||
|             Optional<Entry<I, C>> oentry = this.entries.stream() | ||||
|                 .filter(e -> method.identifier().equals(e.identifier())) | ||||
|                 .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); | ||||
|         }    | ||||
|             return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void addMethods(Object containingObject, Method... methods) { | ||||
|     public MethodContainer<I, C> addMethods(Object containingObject, Method... methods) { | ||||
|         for (Method method : methods) | ||||
|             this.addMethods(this.factory.produce(method, containingObject)); | ||||
|             this.factory.produce(method, containingObject) | ||||
|                 .ifPresent(this::addMethod); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @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() | ||||
|             .flatMap(e -> e.methods.stream()) | ||||
|             .toList(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Collection<ReflectedMethod<I>> findFor(I identifier) { | ||||
|     public Collection<ReflectedMethod<I, C>> findFor(I identifier) { | ||||
|         return this.entries.stream() | ||||
|             .filter(e -> e.identifier().equals(identifier)) | ||||
|             .flatMap(e -> e.methods.stream()) | ||||
| @@ -56,14 +65,22 @@ public class MultiMethodContainer<I extends Object> implements MethodContainer<I | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Optional<ReflectedMethod<I>> findFirstFor(I identifier) { | ||||
|     public Optional<ReflectedMethod<I, C>> findFirstFor(I identifier) { | ||||
|         return this.entries.stream() | ||||
|             .filter(e -> e.identifier().equals(identifier)) | ||||
|             .flatMap(e -> e.methods.stream()) | ||||
|             .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) { | ||||
|             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); | ||||
|          | ||||
|         public Entry<I> addMethod(ReflectedMethod<I> method) { | ||||
|         public Entry<I, C> addMethod(ReflectedMethod<I, C> method) { | ||||
|             I midentifier = method.identifier(); | ||||
|  | ||||
|             if (!this.identifier().equals(midentifier)) | ||||
|                 throw new IllegalArgumentException("Method's identifier did not equal the entry's identifier"); | ||||
|  | ||||
|             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; | ||||
|         } | ||||
|  | ||||
|         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 | ||||
|         public boolean equals(Object obj) { | ||||
|             if (!(obj instanceof Entry)) | ||||
|                 return false; | ||||
|             Entry<?> other = (Entry<?>) obj; | ||||
|             Entry<?, ?> other = (Entry<?, ?>) obj; | ||||
|             return other.identifier().equals(identifier()); | ||||
|         } | ||||
|  | ||||
| @@ -108,7 +114,7 @@ public class MultiMethodContainer<I extends Object> implements MethodContainer<I | ||||
|  | ||||
|         @Override | ||||
|         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.Method; | ||||
| @@ -12,7 +12,7 @@ import org.slf4j.LoggerFactory; | ||||
| 
 | ||||
| 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()); | ||||
| 
 | ||||
| @@ -26,16 +26,17 @@ public abstract class ReflectedMethod<I extends Object> { | ||||
|         this.containingObject = containingObject; | ||||
|     } | ||||
| 
 | ||||
|     public abstract Object getParameter(Object context, int index); | ||||
|     public abstract Object getParameter(C context, int index); | ||||
| 
 | ||||
|     public abstract I identifier(); | ||||
| 
 | ||||
|     public Object run(Object context) { | ||||
|     public Object run(C context) { | ||||
|         method.setAccessible(true); | ||||
|         try { | ||||
|             logger.debug("Invoking method {} from {}", ReflectionUtil.getFullMethodName(method), this); | ||||
|             return method.invoke(containingObject, getParameters(context)); | ||||
|         }catch (IllegalAccessException | InvocationTargetException ex) { | ||||
|             logger.error("ReflectedMethod failed to run", ex); | ||||
|             logger.error("ReflectedMethod %s failed to run".formatted(this), ex); | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| @@ -48,18 +49,18 @@ public abstract class ReflectedMethod<I extends Object> { | ||||
|         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(); | ||||
|         List<Object> parameters = new ArrayList<>(); | ||||
|          | ||||
|         for (int i = 0; i < parameterCount; i++) { | ||||
|             Object parameter; | ||||
|             if (i == 0) { | ||||
|                 parameter = context; | ||||
|             }else | ||||
|                 parameter = getParameter(context, i-1); | ||||
| 
 | ||||
|             logger.trace("Found parameter {}={} for method {}", parameter != null ? parameter.getClass().toString() : " ", parameter, ReflectionUtil.getFullMethodName(method)); | ||||
|             Object parameter = getParameter(context, i); | ||||
|             logger.trace("Found parameter {}={} for method {} in {}", parameter != null ? parameter.getClass().toString() : " ", parameter, ReflectionUtil.getFullMethodName(method), this); | ||||
|             parameters.add(parameter);    | ||||
|         } | ||||
|         return parameters.toArray(); | ||||
| @@ -135,6 +135,7 @@ public final class ReflectionUtil { | ||||
|     } | ||||
|  | ||||
|     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 net.tomatentum.cutin.method.ReflectedMethod; | ||||
|  | ||||
| class ReflectedMethodTest { | ||||
|      | ||||
|     @Test | ||||
|     void methodTest() { | ||||
|         ReflectedMethod<String> method = new TestReflectedMethod(new TestMethodClass()); | ||||
|         ReflectedMethod<String, String> method = new TestReflectedMethod(new TestMethodClass()); | ||||
|         Object result = method.run("testContext"); | ||||
|         assertTrue((boolean)result); | ||||
|         System.out.println("Success"); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void testBCMethod() { | ||||
|         ReflectedMethod<?> method = new BestCandidateMethod<String>( | ||||
|         ReflectedMethod<String, Double> method = new TestBestCandidateMethod( | ||||
|             "test",  | ||||
|             new TestMethodClass(), | ||||
|             "ident", | ||||
|              "testString"); | ||||
|             new TestMethodClass()); | ||||
|         Object result = method.run((double)4); | ||||
|         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; | ||||
|  | ||||
| public class TestReflectedMethod extends ReflectedMethod<String> { | ||||
| import net.tomatentum.cutin.method.ReflectedMethod; | ||||
|  | ||||
| public class TestReflectedMethod extends ReflectedMethod<String, String> { | ||||
|  | ||||
|     protected TestReflectedMethod(Object containingObject) { | ||||
|         super(getMethod(containingObject), containingObject); | ||||
| @@ -10,8 +12,15 @@ public class TestReflectedMethod extends ReflectedMethod<String> { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Object getParameter(Object context, int index) { | ||||
|         return 2; | ||||
|     public Object getParameter(String context, int index) { | ||||
|         switch (index) { | ||||
|             case 0: | ||||
|                 return context; | ||||
|             case 1: | ||||
|                 return 2; | ||||
|             default: | ||||
|                 return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @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 | ||||
		Reference in New Issue
	
	Block a user