Update Dependencies Injections | Add possibility to give differente object's instance for the same object's type

This commit is contained in:
jeffcheasey88 2024-06-28 21:01:15 +02:00
parent 2c9897a7c5
commit b1575e5b52
3 changed files with 95 additions and 25 deletions

View file

@ -0,0 +1,66 @@
package dev.peerat.framework;
import java.lang.reflect.Constructor;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
public class DependencyInjector{
private Map<String, Object> map;
private List<BiFunction<Constructor<?>, Parameter, Object>> builders;
private Object[] injections;
public DependencyInjector(){
this.map = new HashMap<>();
this.builders = new ArrayList<>();
}
public DependencyInjector of(String name, Object value){
this.map.put(name, value);
return this;
}
public DependencyInjector of(BiFunction<Constructor<?>, Parameter, Object> builder){
this.builders.add(builder);
return this;
}
public DependencyInjector of(Object... injections){
if(this.injections == null){
this.injections = injections;
return this;
}
Object[] copy = new Object[this.injections.length+injections.length];
System.arraycopy(this.injections, 0, copy, 0, this.injections.length);
System.arraycopy(injections, 0, copy, this.injections.length, injections.length);
this.injections = copy;
return this;
}
Object applyDependency(Constructor<?> constructor, Parameter parameter, Map<Class<?>, Object> cache){
Injection annotation = parameter.getAnnotation(Injection.class);
if(annotation != null) return this.map.get(annotation.name());
for(BiFunction<Constructor<?>, Parameter, Object> function : builders){
Object result = function.apply(constructor, parameter);
if(result != null) return result;
}
if(this.injections == null) return null;
Class<?> type = parameter.getType();
Object result = null;
for(Object injection : injections){
if(type.isAssignableFrom(injection.getClass())){
if(cache.containsKey(type)){
throw new IllegalArgumentException("Double dependency for type "+type);
}else{
cache.put(type, injection);
result = injection;
}
}
}
return result;
}
}

View file

@ -0,0 +1,7 @@
package dev.peerat.framework;
public @interface Injection{
String name();
}

View file

@ -6,6 +6,7 @@ import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.Key;
@ -111,17 +112,25 @@ public class Router<U extends User>{
}
public Router<U> registerPackages(Object... injections){
return registerPackages(new DependencyInjector().of(injections));
}
public Router<U> registerPackages(DependencyInjector injector){
String clazz = Thread.currentThread().getStackTrace()[2].getClassName();
String pack = clazz.substring(0, clazz.lastIndexOf('.'));
return registerPackages(pack, injections);
return registerPackages(pack, injector);
}
public Router<U> registerPackages(String name, Object... injections){
return registerPackages(name, new DependencyInjector().of(injections));
}
public Router<U> registerPackages(String name, DependencyInjector injector){
InputStream stream = ClassLoader.getSystemClassLoader().getResourceAsStream(name.replace(".", "/"));
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line;
Map<Class<?>, Object> cache = new HashMap<>();
Map<Class<?>, Object> cache = new HashMap<>();
while((line = reader.readLine()) != null){
if(line.endsWith(".class")){
Class<?> clazz = Class.forName(name+"."+line.substring(0, line.lastIndexOf('.')));
@ -129,10 +138,10 @@ public class Router<U extends User>{
if(clazz.equals(Response.class)) continue;
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
if(constructors.length != 1) continue;
injectDependencies(constructors[0], cache, injections);
injectDependencies(constructors[0], cache, injector);
}
}else{
registerPackages(name+"."+line);
registerPackages(name+"."+line, injector);
}
}
reader.close();
@ -142,30 +151,18 @@ public class Router<U extends User>{
return this;
}
private void injectDependencies(Constructor<?> constructor, Map<Class<?>, Object> cache, Object... injections){
Class<?>[] parameterTypes = constructor.getParameterTypes();
Object[] parameters = new Object[parameterTypes.length];
for(int i = 0; i < parameterTypes.length; i++){
Class<?> type = parameterTypes[i];
private void injectDependencies(Constructor<?> constructor, Map<Class<?>, Object> cache, DependencyInjector injector){
Parameter[] parameters = constructor.getParameters();
Object[] injections = new Object[parameters.length];
for(int i = 0; i < parameters.length; i++){
Parameter parameter = parameters[i];
Class<?> type = parameter.getType();
Object dependency = cache.get(type);
if(dependency != null){
parameters[i] = dependency;
}else{
for(Object injection : injections){
if(type.isAssignableFrom(injection.getClass())){
if(cache.containsKey(type)){
throw new IllegalArgumentException("Double dependency for type "+type);
}else{
cache.put(type, injection);
parameters[i] = injection;
}
}
}
if(parameters[i] == null) throw new IllegalArgumentException("No dependency for type "+type);
}
if(dependency != null) injections[i] = dependency;
else if((injections[i] = injector.applyDependency(constructor, parameter, cache)) == null) throw new IllegalArgumentException("No dependency for type "+type);
}
try {
Response response = (Response) constructor.newInstance(parameters);
Response response = (Response) constructor.newInstance(injections);
register(response);
System.out.println("registerd "+response.getClass());
} catch (Exception e){