diff --git a/util/di/build.gradle b/util/di/build.gradle deleted file mode 100644 index 874911d..0000000 --- a/util/di/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -plugins { - id 'groowt-conventions' - id 'groowt-testing' - id 'groowt-logging' - id 'groowt-publish' - id 'java-library' -} - -dependencies { - api libs.jakarta.inject - api libs.groovy - compileOnlyApi libs.jetbrains.anotations - implementation libs.slf4j.api, libs.groovy -} - -java { - withSourcesJar() -} - -jar { - archiveBaseName = 'groowt-util-di' -} - -publishing { - publications { - create('di', MavenPublication) { - artifactId = 'util-di' - from components.java - } - } -} diff --git a/util/di/src/main/java/groowt/util/di/AbstractInjectingObjectFactory.java b/util/di/src/main/java/groowt/util/di/AbstractInjectingObjectFactory.java deleted file mode 100644 index 1f9e718..0000000 --- a/util/di/src/main/java/groowt/util/di/AbstractInjectingObjectFactory.java +++ /dev/null @@ -1,357 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Inject; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.*; -import java.util.*; -import java.util.function.Consumer; -import java.util.stream.Collectors; - -import static groowt.util.di.ObjectFactoryUtil.toTypes; - -// TODO: maybe inject fields -public abstract class AbstractInjectingObjectFactory implements ObjectFactory { - - protected record CachedInjectConstructor(Class clazz, Constructor constructor) {} - - protected record CachedNonInjectConstructor( - Class clazz, - Constructor constructor, - Class[] paramTypes - ) {} - - protected record Resolved(Class type, Object object) {} - - private static final class DeferredSetters { - - private final Class forType; - private final List> actions = new ArrayList<>(); - - public DeferredSetters(Class forType) { - this.forType = forType; - } - - public Class getForType() { - return this.forType; - } - - public List> getActions() { - return this.actions; - } - - } - - protected static class CreateContext { - - private final Deque> constructionStack = new LinkedList<>(); - private final Deque deferredSettersStack = new LinkedList<>(); - private final List allResolved = new ArrayList<>(); - - public CreateContext(Class targetType) { - this.pushConstruction(targetType); - } - - public void checkForCircularDependency(Class typeToConstruct) { - if (constructionStack.contains(typeToConstruct)) { - throw new IllegalStateException( - "Detected a circular constructor dependency for " + typeToConstruct.getName() - + " . Please use setter methods instead. Current construction stack: " - + constructionStack.stream() - .map(Class::getName) - .collect(Collectors.joining(", ")) - ); - } - } - - public void pushConstruction(Class type) { - this.constructionStack.push(type); - this.deferredSettersStack.push(new DeferredSetters(type)); - } - - public void popConstruction() { - this.constructionStack.pop(); - this.deferredSettersStack.pop(); - } - - public boolean containsConstruction(Class type) { - return this.constructionStack.contains(type); - } - - public void addDeferredSetterAction(Class forType, Consumer action) { - boolean found = false; - for (final DeferredSetters deferredSetters : this.deferredSettersStack) { - if (deferredSetters.getForType().equals(forType)) { - found = true; - deferredSetters.getActions().add(action); - break; - } - } - if (!found) { - throw new IllegalArgumentException( - "There is no construction for type " + forType.getName() + " which should be deferred." - ); - } - } - - public List> getDeferredSetterActions() { - return this.deferredSettersStack.getFirst().getActions(); - } - - public List getAllResolved() { - return this.allResolved; - } - - } - - private final Map, Constructor[]> cachedAllConstructors = new HashMap<>(); - private final Collection> cachedInjectConstructors = new ArrayList<>(); - private final Collection> cachedNonInjectConstructors = new ArrayList<>(); - private final Map, Collection> cachedSetters = new HashMap<>(); - private final Map cachedSetterParameters = new HashMap<>(); - - @SuppressWarnings("unchecked") - private @Nullable Constructor findCachedInjectConstructor(Class clazz) { - for (final CachedInjectConstructor cachedConstructor : this.cachedInjectConstructors) { - if (clazz.equals(cachedConstructor.clazz())) { - return (Constructor) cachedConstructor.constructor(); - } - } - return null; - } - - /** - * @implNote If overridden, please cache any found inject constructors using {@link #putCachedInjectConstructor}. - * - * @param clazz the {@link Class} in which to search for an {@literal @}Inject annotated constructor. - * @return the inject constructor, or {@code null} if none found. - * @param the type of the class - */ - @SuppressWarnings("unchecked") - protected @Nullable Constructor findInjectConstructor(Class clazz) { - final Constructor cachedInjectConstructor = this.findCachedInjectConstructor(clazz); - if (cachedInjectConstructor != null) { - return cachedInjectConstructor; - } - - final Constructor[] constructors = this.cachedAllConstructors.computeIfAbsent(clazz, Class::getConstructors); - - final List> injectConstructors = Arrays.stream(constructors) - .filter(constructor -> constructor.isAnnotationPresent(Inject.class)) - .toList(); - - if (injectConstructors.size() > 1) { - // one day maybe support multiple inject constructors - throw new UnsupportedOperationException("Cannot have more than one @Inject constructor in class: " + clazz); - } else if (injectConstructors.size() == 1) { - final Constructor injectConstructor = (Constructor) injectConstructors.getFirst(); - this.putCachedInjectConstructor(new CachedInjectConstructor<>(clazz, injectConstructor)); - return injectConstructor; - } else { - return null; - } - } - - protected final void putCachedInjectConstructor(CachedInjectConstructor cached) { - this.cachedInjectConstructors.add(cached); - } - - @SuppressWarnings("unchecked") - private @Nullable Constructor findCachedNonInjectConstructor(Class clazz, Class[] paramTypes) { - for (final CachedNonInjectConstructor cachedConstructor : this.cachedNonInjectConstructors) { - if (clazz.equals(cachedConstructor.clazz()) && Arrays.equals(cachedConstructor.paramTypes(), paramTypes)) { - return (Constructor) cachedConstructor.constructor(); - } - } - return null; - } - - private static boolean areArgsAssignable(Class[] paramTypes, Object[] givenArgs) { - if (paramTypes.length != givenArgs.length) { - return false; - } - for (int i = 0; i < paramTypes.length; i++) { - if (!paramTypes[i].isInstance(givenArgs[i])) { - return false; - } - } - return true; - } - - /** - * @implNote If overridden, please cache any found non-inject constructors using - * {@link #putCachedNonInjectConstructor}. - * - * @param clazz the {@link Class} in which to search for a constructor which does - * not have an {@literal @}Inject annotation. - * @param constructorArgs the given constructor args - * @return the found non-inject constructor appropriate for the given constructor args, - * or {@code null} if no such constructor exists - * @param the type - */ - @SuppressWarnings("unchecked") - protected @Nullable Constructor findNonInjectConstructor(Class clazz, Object[] constructorArgs) { - final Class[] types = toTypes(constructorArgs); - final Constructor cachedConstructor = this.findCachedNonInjectConstructor(clazz, types); - if (cachedConstructor != null) { - return cachedConstructor; - } - - final Constructor[] constructors = this.cachedAllConstructors.computeIfAbsent(clazz, Class::getConstructors); - for (Constructor constructor : constructors) { - if (areArgsAssignable(constructor.getParameterTypes(), constructorArgs)) { - final Constructor found = (Constructor) constructor; - this.putCachedNonInjectConstructor(new CachedNonInjectConstructor<>(clazz, found, types)); - return found; - } - } - return null; - } - - protected final void putCachedNonInjectConstructor(CachedNonInjectConstructor cached) { - this.cachedNonInjectConstructors.add(cached); - } - - /** - * @implNote Please call {@code super.findConstructor()} first, and then implement custom - * constructor finding logic. If the custom logic finds a constructor, please cache it - * using either {@link #putCachedNonInjectConstructor} or {@link #putCachedInjectConstructor}. - */ - protected Constructor findConstructor(Class clazz, Object[] args) { - final Constructor injectConstructor = this.findInjectConstructor(clazz); - if (injectConstructor != null) { - return injectConstructor; - } - final Constructor nonInjectConstructor = this.findNonInjectConstructor(clazz, args); - if (nonInjectConstructor != null) { - return nonInjectConstructor; - } - throw new RuntimeException("Could not find an appropriate constructor for " + clazz.getName() - + " with args " + Arrays.toString(toTypes(args)) - ); - } - - protected Collection getAllInjectSetters(Class clazz) { - final Method[] allMethods = clazz.getMethods(); - final Collection injectSetters = new ArrayList<>(); - for (final var method : allMethods) { - if ( - method.isAnnotationPresent(Inject.class) - && method.getName().startsWith("set") - && !Modifier.isStatic(method.getModifiers()) - && method.getParameterCount() == 1 - ) { - injectSetters.add(method); - } - } - return injectSetters; - } - - protected Collection getCachedSettersFor(Object target) { - return this.cachedSetters.computeIfAbsent(target.getClass(), this::getAllInjectSetters); - } - - protected Parameter getCachedInjectParameter(Method setter) { - return this.cachedSetterParameters.computeIfAbsent(setter, s -> { - if (s.getParameterCount() != 1) { - throw new IllegalArgumentException( - "Setter " + s.getName() + " has a parameter count other than one (1)!" - ); - } - return s.getParameters()[0]; - }); - } - - private @Nullable Object findInContext(CreateContext context, Class type) { - for (final Resolved resolved : context.getAllResolved()) { - if (type.isAssignableFrom(resolved.type)) { - return resolved.object; - } - } - return null; - } - - protected void injectSetter(CreateContext context, Object target, Method setter) { - final Parameter injectParam = this.getCachedInjectParameter(setter); - final Class typeToInject = injectParam.getType(); - final @Nullable Object fromContext = this.findInContext(context, typeToInject); - - final Consumer setterAction = arg -> { - try { - setter.invoke(target, arg); - } catch (InvocationTargetException | IllegalAccessException e) { - throw new RuntimeException(e); - } - }; - - if (context.containsConstruction(typeToInject)) { - context.addDeferredSetterAction(typeToInject, setterAction); - } else { - final Object arg; - if (fromContext != null) { - arg = fromContext; - } else { - arg = this.getSetterInjectArg(context, target.getClass(), setter, injectParam); - context.getAllResolved().add(new Resolved(typeToInject, arg)); - } - setterAction.accept(arg); - } - } - - protected void injectSetters(CreateContext context, Object target) { - this.getCachedSettersFor(target).forEach(setter -> this.injectSetter(context, target, setter)); - } - - /** - * {@inheritDoc} - */ - @Override - public T createInstance(Class type, Object... constructorArgs) { - final Constructor constructor = this.findConstructor(type, constructorArgs); - final CreateContext context = new CreateContext(type); - final Object[] allArgs = this.createArgs(context, constructor, constructorArgs); - try { - final T instance = constructor.newInstance(allArgs); - context.getAllResolved().add(new Resolved(type, instance)); - this.injectSetters(context, instance); - final List> deferredSetterActions = context.getDeferredSetterActions(); - context.popConstruction(); - deferredSetterActions.forEach(setterAction -> setterAction.accept(instance)); - return instance; - } catch (InvocationTargetException | IllegalAccessException | InstantiationException e) { - throw new RuntimeException(e); // In the future, we might have an option to ignore exceptions - } - } - - protected T createInstance(CreateContext context, Class type, Object... givenArgs) { - final Constructor constructor = this.findConstructor(type, givenArgs); - context.checkForCircularDependency(type); - context.pushConstruction(type); - final Object[] allArgs = this.createArgs(context, constructor, givenArgs); - try { - final T instance = constructor.newInstance(allArgs); - context.getAllResolved().add(new Resolved(type, instance)); - this.injectSetters(context, instance); - final List> deferredSetterActions = context.getDeferredSetterActions(); - context.popConstruction(); - deferredSetterActions.forEach(setterAction -> setterAction.accept(instance)); - return instance; - } catch (InvocationTargetException | IllegalAccessException | InstantiationException e) { - throw new RuntimeException(e); - } - } - - protected abstract Object[] createArgs( - CreateContext context, - Constructor constructor, - Object[] constructorArgs - ); - - protected abstract Object getSetterInjectArg( - CreateContext context, - Class targetType, - Method setter, - Parameter toInject - ); - -} diff --git a/util/di/src/main/java/groowt/util/di/AbstractRegistryObjectFactory.java b/util/di/src/main/java/groowt/util/di/AbstractRegistryObjectFactory.java deleted file mode 100644 index cd947fb..0000000 --- a/util/di/src/main/java/groowt/util/di/AbstractRegistryObjectFactory.java +++ /dev/null @@ -1,114 +0,0 @@ -package groowt.util.di; - -import groowt.util.di.filters.FilterHandler; -import groowt.util.di.filters.IterableFilterHandler; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -import static groowt.util.di.RegistryObjectFactoryUtil.orElseSupply; - -public abstract class AbstractRegistryObjectFactory extends AbstractInjectingObjectFactory - implements RegistryObjectFactory { - - public static abstract class AbstractBuilder implements Builder { - - private final Collection> filterHandlers = new ArrayList<>(); - private final Collection> iterableFilterHandlers = new ArrayList<>(); - private final Registry registry; - private @Nullable RegistryObjectFactory parent; - - public AbstractBuilder(Registry registry) { - this.registry = registry; - } - - public AbstractBuilder() { - this.registry = new DefaultRegistry(); - } - - protected Registry getRegistry() { - return this.registry; - } - - protected Collection> getFilterHandlers() { - return this.filterHandlers; - } - - protected Collection> getIterableFilterHandlers() { - return this.iterableFilterHandlers; - } - - protected @Nullable RegistryObjectFactory getParent() { - return this.parent; - } - - @Override - public void configureRegistry(Consumer configure) { - configure.accept(this.registry); - } - - public void addFilterHandler(FilterHandler handler) { - this.filterHandlers.add(handler); - } - - public void addIterableFilterHandler(IterableFilterHandler handler) { - this.iterableFilterHandlers.add(handler); - } - - public void setParent(@Nullable RegistryObjectFactory parent) { - this.parent = parent; - } - - } - - protected final Registry registry; - @Nullable private final RegistryObjectFactory parent; - - public AbstractRegistryObjectFactory(Registry registry, @Nullable RegistryObjectFactory parent) { - this.registry = registry; - this.parent = parent; - } - - @Override - public Registry getRegistry() { - return this.registry; - } - - @Override - public @Nullable ScopeHandler findScopeHandler(Class scopeType) { - return this.registry.getScopeHandler(scopeType); - } - - @Override - public @Nullable QualifierHandler findQualifierHandler(Class qualifierType) { - return this.registry.getQualifierHandler(qualifierType); - } - - protected final Optional findInParent(Function finder) { - return this.parent != null ? Optional.ofNullable(finder.apply(this.parent)) : Optional.empty(); - } - - protected final Optional findInSelfOrParent(Function finder) { - return orElseSupply( - finder.apply(this), - () -> this.parent != null ? finder.apply(this.parent) : null - ); - } - - protected final T getInSelfOrParent( - Function finder, - Supplier exceptionSupplier - ) { - return orElseSupply( - finder.apply(this), - () -> this.parent != null ? finder.apply(this.parent) : null - ).orElseThrow(exceptionSupplier); - } - -} diff --git a/util/di/src/main/java/groowt/util/di/Binding.java b/util/di/src/main/java/groowt/util/di/Binding.java deleted file mode 100644 index d9b6ccb..0000000 --- a/util/di/src/main/java/groowt/util/di/Binding.java +++ /dev/null @@ -1,3 +0,0 @@ -package groowt.util.di; - -sealed public interface Binding permits ClassBinding, ProviderBinding, SingletonBinding, LazySingletonBinding {} diff --git a/util/di/src/main/java/groowt/util/di/BindingConfigurator.java b/util/di/src/main/java/groowt/util/di/BindingConfigurator.java deleted file mode 100644 index 4352bc0..0000000 --- a/util/di/src/main/java/groowt/util/di/BindingConfigurator.java +++ /dev/null @@ -1,12 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Provider; - -import java.util.function.Supplier; - -public interface BindingConfigurator { - void to(Class target); - void toProvider(Provider provider); - void toSingleton(T target); - void toLazySingleton(Supplier singletonSupplier); -} diff --git a/util/di/src/main/java/groowt/util/di/BindingUtil.java b/util/di/src/main/java/groowt/util/di/BindingUtil.java deleted file mode 100644 index b6a2dd1..0000000 --- a/util/di/src/main/java/groowt/util/di/BindingUtil.java +++ /dev/null @@ -1,36 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Provider; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -public final class BindingUtil { - - public static Consumer> toClass(Class clazz) { - return bc -> bc.to(clazz); - } - - public static Consumer> toProvider(Provider provider) { - return bc -> bc.toProvider(provider); - } - - public static Consumer> toSingleton(T singleton) { - return bc -> bc.toSingleton(singleton); - } - - public static Consumer> toLazySingleton(Supplier singletonSupplier) { - return bc -> bc.toLazySingleton(singletonSupplier); - } - - public static Consumer> toSelf() { - return bc -> {}; - } - - public static KeyHolder named(String name, Class type) { - return new SimpleKeyHolder<>(NamedRegistryExtension.class, type, name); - } - - private BindingUtil() {} - -} diff --git a/util/di/src/main/java/groowt/util/di/ClassBinding.java b/util/di/src/main/java/groowt/util/di/ClassBinding.java deleted file mode 100644 index b01f909..0000000 --- a/util/di/src/main/java/groowt/util/di/ClassBinding.java +++ /dev/null @@ -1,3 +0,0 @@ -package groowt.util.di; - -public record ClassBinding(Class from, Class to) implements Binding {} diff --git a/util/di/src/main/java/groowt/util/di/DefaultNamedRegistryExtension.java b/util/di/src/main/java/groowt/util/di/DefaultNamedRegistryExtension.java deleted file mode 100644 index 22413de..0000000 --- a/util/di/src/main/java/groowt/util/di/DefaultNamedRegistryExtension.java +++ /dev/null @@ -1,80 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Named; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public class DefaultNamedRegistryExtension implements NamedRegistryExtension { - - protected static class NamedQualifierHandler implements QualifierHandler { - - private final DefaultNamedRegistryExtension extension; - - public NamedQualifierHandler(DefaultNamedRegistryExtension extension) { - this.extension = extension; - } - - @Override - public @Nullable Binding handle(Named named, Class dependencyClass) { - return this.extension.getBinding( - new SimpleKeyHolder<>(NamedRegistryExtension.class, dependencyClass, named.value()) - ); - } - - } - - protected final Map> bindings = new HashMap<>(); - protected final QualifierHandler qualifierHandler = this.getNamedQualifierHandler(); - - protected QualifierHandler getNamedQualifierHandler() { - return new NamedQualifierHandler(this); - } - - @SuppressWarnings("unchecked") - @Override - public @Nullable QualifierHandler getQualifierHandler(Class qualifierType) { - return Named.class.equals(qualifierType) ? (QualifierHandler) this.qualifierHandler : null; - } - - @Override - public Class getKeyClass() { - return String.class; - } - - @Override - public , T> void bind(KeyHolder keyHolder, Consumer> configure) { - final var configurator = new SimpleBindingConfigurator<>(keyHolder.type()); - configure.accept(configurator); - this.bindings.put(keyHolder.key(), configurator.getBinding()); - } - - @SuppressWarnings("unchecked") - @Override - public @Nullable , T> Binding getBinding(KeyHolder keyHolder) { - return (Binding) this.bindings.getOrDefault(keyHolder.key(), null); - } - - @Override - public , T> void removeBinding(KeyHolder keyHolder) { - this.bindings.remove(keyHolder.key()); - } - - @Override - public , T> void removeBindingIf(KeyHolder keyHolder, Predicate> filter) { - final String key = keyHolder.key(); - if (this.bindings.containsKey(key) && filter.test(this.getBinding(keyHolder))) { - this.bindings.remove(key); - } - } - - @Override - public void clearAllBindings() { - this.bindings.clear(); - } - -} diff --git a/util/di/src/main/java/groowt/util/di/DefaultRegistry.java b/util/di/src/main/java/groowt/util/di/DefaultRegistry.java deleted file mode 100644 index f3af321..0000000 --- a/util/di/src/main/java/groowt/util/di/DefaultRegistry.java +++ /dev/null @@ -1,221 +0,0 @@ -package groowt.util.di; - -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; - -public class DefaultRegistry implements Registry { - - protected static class BindingContainer { - - private final Map, Binding> bindings = new HashMap<>(); - - @SuppressWarnings("unchecked") - public @Nullable Binding get(Class key) { - for (final var entry : bindings.entrySet()) { - if (entry.getKey().isAssignableFrom(key)) { - return (Binding) entry.getValue(); - } - } - return null; - } - - public void put(Class key, Binding binding) { - this.bindings.put(key, binding); - } - - public void remove(Class key) { - this.bindings.remove(key); - } - - public void removeIf(Class key, Predicate> filter) { - if (filter.test(this.get(key))) { - this.bindings.remove(key); - } - } - - public void clear() { - this.bindings.clear(); - } - - } - - protected final BindingContainer bindingContainer = new BindingContainer(); - protected final Collection extensions = new ArrayList<>(); - - @Override - public void removeBinding(Class key) { - this.bindingContainer.remove(key); - } - - @Override - public void removeBindingIf(Class key, Predicate> filter) { - this.bindingContainer.removeIf(key, filter); - } - - private List getAllRegistryExtensions(Class extensionType) { - return this.extensions.stream() - .filter(extension -> extensionType.isAssignableFrom(extension.getClass())) - .map(extensionType::cast) - .toList(); - } - - private E getOneRegistryExtension(Class extensionType) { - final List extensions = this.getAllRegistryExtensions(extensionType); - if (extensions.size() == 1) { - return extensions.getFirst(); - } else if (extensions.isEmpty()) { - throw new IllegalArgumentException("There is no " + extensionType + " registered for this " + this); - } else { - throw new IllegalArgumentException("There is more than one " + extensionType + " registered for this " + this); - } - } - - @Override - public void addExtension(RegistryExtension extension) { - final List existing = this.getAllRegistryExtensions(extension.getClass()); - if (existing.isEmpty()) { - this.extensions.add(extension); - } else { - throw new IllegalArgumentException("There is already at least one " + extension.getClass() + " registered in " + this); - } - } - - @Override - public E getExtension(Class extensionType) { - return this.getOneRegistryExtension(extensionType); - } - - @Override - public Collection getExtensions(Class extensionType) { - return this.getAllRegistryExtensions(extensionType); - } - - @Override - public void removeExtension(RegistryExtension extension) { - this.extensions.remove(extension); - } - - @Override - public @Nullable QualifierHandler getQualifierHandler(Class qualifierType) { - final List> handlers = new ArrayList<>(); - for (final var extension : this.extensions) { - if (extension instanceof QualifierHandlerContainer handlerContainer) { - final var handler = handlerContainer.getQualifierHandler(qualifierType); - if (handler != null) { - handlers.add(handler); - } - } - } - if (handlers.isEmpty()) { - return null; - } else if (handlers.size() > 1) { - throw new RuntimeException("There is more than one QualifierHandler for " + qualifierType.getName()); - } else { - return handlers.getFirst(); - } - } - - @Override - public @Nullable ScopeHandler getScopeHandler(Class scopeType) { - final List> handlers = new ArrayList<>(); - for (final var extension : this.extensions) { - if (extension instanceof ScopeHandlerContainer handlerContainer) { - final var handler = handlerContainer.getScopeHandler(scopeType); - if (handler != null) { - handlers.add(handler); - } - } - } - if (handlers.isEmpty()) { - return null; - } else if (handlers.size() > 1) { - throw new RuntimeException("There is more than one ScopeHandler for " + scopeType.getName()); - } else { - return handlers.getFirst(); - } - } - - @Override - public void bind(Class key, Consumer> configure) { - final var configurator = new SimpleBindingConfigurator<>(key); - configure.accept(configurator); - this.bindingContainer.put(key, configurator.getBinding()); - } - - @Override - public @Nullable Binding getBinding(Class key) { - return this.bindingContainer.get(key); - } - - private KeyBinder findKeyBinder(Class keyClass) { - final List> binders = new ArrayList<>(); - for (final var extension : this.extensions) { - if (extension instanceof KeyBinder keyBinder && keyBinder.getKeyClass().isAssignableFrom(keyClass)) { - binders.add(keyBinder); - } - } - if (binders.isEmpty()) { - throw new IllegalArgumentException("There are no configured RegistryExtensions that can handle keys with type " + keyClass.getName()); - } else if (binders.size() > 1) { - throw new IllegalArgumentException("There is more than one configured RegistryExtension that can handle keys with type " + keyClass.getName()); - } else { - return binders.getFirst(); - } - } - - @SuppressWarnings("rawtypes") - protected final void withKeyBinder(KeyHolder keyHolder, Consumer action) { - action.accept(this.findKeyBinder(keyHolder.key().getClass())); - } - - @SuppressWarnings("rawtypes") - protected final @Nullable R tapKeyBinder( - KeyHolder keyHolder, - Function function - ) { - return function.apply(this.findKeyBinder(keyHolder.key().getClass())); - } - - @SuppressWarnings("unchecked") - @Override - public void bind(KeyHolder keyHolder, Consumer> configure) { - this.withKeyBinder(keyHolder, b -> b.bind(keyHolder, configure)); - } - - @SuppressWarnings("unchecked") - @Override - public @Nullable Binding getBinding(KeyHolder keyHolder) { - return this.tapKeyBinder(keyHolder, b -> b.getBinding(keyHolder)); - } - - @SuppressWarnings("unchecked") - @Override - public void removeBinding(KeyHolder keyHolder) { - this.withKeyBinder(keyHolder, b -> b.removeBinding(keyHolder)); - } - - @SuppressWarnings("unchecked") - @Override - public void removeBindingIf( - KeyHolder keyHolder, - Predicate> filter - ) { - this.withKeyBinder(keyHolder, b -> b.removeBindingIf(keyHolder, filter)); - } - - @Override - public void clearAllBindings() { - this.bindingContainer.clear(); - for (final var extension : this.extensions) { - if (extension instanceof KeyBinder keyBinder) { - keyBinder.clearAllBindings(); - } - } - } - -} diff --git a/util/di/src/main/java/groowt/util/di/DefaultRegistryObjectFactory.java b/util/di/src/main/java/groowt/util/di/DefaultRegistryObjectFactory.java deleted file mode 100644 index f8e8784..0000000 --- a/util/di/src/main/java/groowt/util/di/DefaultRegistryObjectFactory.java +++ /dev/null @@ -1,348 +0,0 @@ -package groowt.util.di; - -import groowt.util.di.filters.FilterHandler; -import groowt.util.di.filters.IterableFilterHandler; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.function.Supplier; - -import static groowt.util.di.RegistryObjectFactoryUtil.*; - -public class DefaultRegistryObjectFactory extends AbstractRegistryObjectFactory { - - public static final class Builder - extends AbstractRegistryObjectFactory.AbstractBuilder { - - /** - * Creates a {@code Builder} initialized with a {@link DefaultRegistry}, which is in-turn configured with a - * {@link NamedRegistryExtension} and a {@link SingletonScopeHandler}. - * - * @return the builder - */ - public static Builder withDefaults() { - final var b = new Builder(); - - b.configureRegistry(r -> { - r.addExtension(new DefaultNamedRegistryExtension()); - r.addExtension(new SingletonRegistryExtension(r)); - }); - - return b; - } - - /** - * @return a blank builder with a {@link Registry} from the given {@link Supplier}. - */ - public static Builder withRegistry(Supplier registrySupplier) { - return new Builder(registrySupplier.get()); - } - - /** - * @return a blank builder which will use {@link DefaultRegistry}. - */ - public static Builder blank() { - return new Builder(); - } - - private Builder(Registry registry) { - super(registry); - } - - private Builder() { - super(); - } - - @Override - public DefaultRegistryObjectFactory build() { - return new DefaultRegistryObjectFactory( - this.getRegistry(), - this.getParent(), - this.getFilterHandlers(), - this.getIterableFilterHandlers() - ); - } - - } - - private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; - - private final Collection> filterHandlers; - private final Collection> iterableFilterHandlers; - - protected DefaultRegistryObjectFactory( - Registry registry, - @Nullable RegistryObjectFactory parent, - Collection> filterHandlers, - Collection> iterableFilterHandlers - ) { - super(registry, parent); - this.filterHandlers = new ArrayList<>(filterHandlers); - this.filterHandlers.forEach(handler -> checkIsValidFilter(handler.getAnnotationClass())); - - this.iterableFilterHandlers = new ArrayList<>(iterableFilterHandlers); - this.iterableFilterHandlers.forEach(handler -> checkIsValidIterableFilter(handler.getAnnotationClass())); - } - - /** - * Checks if the given parameter has any qualifier annotations; if it does, - * it delegates finding the desired object to the registered {@link QualifierHandler}. - * - * @param parameter the parameter - * @return the object returned from the {@code QualifierHandler}, or {@code null} if no qualifier - * is present or the {@code QualifierHandler} itself returns {@code null}. - * - * @throws RuntimeException if no {@code QualifierHandler} is registered for a qualifier annotation present on the - * given parameter, or if the handler itself throws an exception. - */ - @SuppressWarnings("unchecked") - protected final @Nullable Object tryQualifiers(Parameter parameter) { - final Class paramType = parameter.getType(); - final List qualifiers = RegistryObjectFactoryUtil.getQualifierAnnotations( - parameter.getAnnotations() - ); - if (qualifiers.size() > 1) { - throw new RuntimeException("Parameter " + parameter + " cannot have more than one Qualifier annotation."); - } else if (qualifiers.size() == 1) { - final Annotation qualifier = qualifiers.getFirst(); - @SuppressWarnings("rawtypes") - final QualifierHandler handler = this.getInSelfOrParent( - f -> f.findQualifierHandler(qualifier.annotationType()), - () -> new RuntimeException("There is no configured QualifierHandler for " - + qualifier.annotationType().getName() - ) - ); - final Binding binding = handler.handle(qualifier, paramType); - if (binding != null) { - return this.handleBinding(binding, EMPTY_OBJECT_ARRAY); - } - } - // no Qualifier or the QualifierHandler didn't return a Binding - return null; - } - - /** - * Checks the {@code resolvedArg} against all filters present on the given parameter. - * - * @param parameter the parameter - * @param resolvedArg the resolved argument - * - * @throws RuntimeException if the {@link FilterHandler} itself throws an exception. - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - protected final void checkFilters(Parameter parameter, Object resolvedArg) { - final Annotation[] allAnnotations = parameter.getAnnotations(); - final Collection filterAnnotations = getFilterAnnotations(allAnnotations); - if (!filterAnnotations.isEmpty()) { - final Collection> filtersForParamType = this.filterHandlers.stream() - .filter(filterHandler -> - filterHandler.getArgumentClass().isAssignableFrom(parameter.getType()) - ) - .toList(); - for (final Annotation filterAnnotation : filterAnnotations) { - for (final FilterHandler filterHandler : filtersForParamType) { - if (filterAnnotation.annotationType().equals(filterHandler.getAnnotationClass())) { - // hopefully we've checked everything - ((FilterHandler) filterHandler).check(filterAnnotation, resolvedArg); - } - } - } - } - final Collection iterableFilterAnnotations = getIterableFilterAnnotations(allAnnotations); - if (!iterableFilterAnnotations.isEmpty() && resolvedArg instanceof Iterable iterable) { - for (final var annotation : iterableFilterAnnotations) { - this.iterableFilterHandlers.stream() - .filter(handler -> handler.getAnnotationClass().equals(annotation.annotationType())) - .forEach(handler -> { - ((IterableFilterHandler) handler).check(annotation, iterable); - }); - } - } - } - - protected final Object resolveInjectedArg(CreateContext context, Parameter parameter) { - final Object qualifierProvidedArg = this.tryQualifiers(parameter); - if (qualifierProvidedArg != null) { - this.checkFilters(parameter, qualifierProvidedArg); - context.getAllResolved().add(new Resolved(parameter.getType(), qualifierProvidedArg)); - return qualifierProvidedArg; - } else { - final Object created = this.get(context, parameter.getType()); - this.checkFilters(parameter, created); - context.getAllResolved().add(new Resolved(parameter.getType(), created)); - return created; - } - } - - protected final void resolveInjectedArgs(CreateContext context, Object[] dest, Parameter[] params) { - for (int i = 0; i < params.length; i++) { - dest[i] = this.resolveInjectedArg(context, params[i]); - } - } - - protected final void resolveGivenArgs(Object[] dest, Parameter[] params, Object[] givenArgs, int startIndex) { - for (int i = startIndex; i < dest.length; i++) { - final int resolveIndex = i - startIndex; - final Object arg = givenArgs[resolveIndex]; - this.checkFilters(params[resolveIndex], arg); - dest[i] = arg; - } - } - - // TODO: when there is a null arg, we lose the type. Therefore this algorithm breaks. Fix this. - @Override - protected Object[] createArgs(CreateContext context, Constructor constructor, Object[] givenArgs) { - final Class[] paramTypes = constructor.getParameterTypes(); - - // check no arg - if (paramTypes.length == 0 && givenArgs.length == 0) { - // no args given, none needed, so return empty array - return EMPTY_OBJECT_ARRAY; - } else if (paramTypes.length == 0) { // implicit that givenArgs.length != 0 - // zero expected, but got given args - throw new RuntimeException( - "Expected zero args for constructor " + constructor + " but received " + Arrays.toString(givenArgs) - ); - } else if (givenArgs.length > paramTypes.length) { - // expected is more than zero, but received too many given - throw new RuntimeException( - "Too many args given for constructor " + constructor + "; received " + Arrays.toString(givenArgs) - ); - } - - final Parameter[] allParams = constructor.getParameters(); - final Object[] resolvedArgs = new Object[allParams.length]; - - if (givenArgs.length == 0) { - // if no given args, then they are all injected - this.resolveInjectedArgs(context, resolvedArgs, allParams); - } else if (givenArgs.length == paramTypes.length) { - // all are given - this.resolveGivenArgs(resolvedArgs, allParams, givenArgs, 0); - } else { - // some are injected, some are given - // everything before (non-inclusive) is injected - // everything after (inclusive) is given - // ex: 1 inject, 1 given -> 2 (allParams) - 1 = 1 - // ex: 0 inject, 1 given -> 1 - 1 = 0 - final int firstGivenIndex = allParams.length - givenArgs.length; - - final Parameter[] injectedParams = new Parameter[firstGivenIndex]; - final Parameter[] givenParams = new Parameter[allParams.length - firstGivenIndex]; - - System.arraycopy(allParams, 0, injectedParams, 0, injectedParams.length); - System.arraycopy( - allParams, firstGivenIndex, givenParams, 0, allParams.length - firstGivenIndex - ); - - this.resolveInjectedArgs(context, resolvedArgs, injectedParams); - this.resolveGivenArgs(resolvedArgs, givenParams, givenArgs, firstGivenIndex); - } - - return resolvedArgs; - } - - private T handleBinding(Binding binding, Object[] constructorArgs) { - return this.handleBinding(binding, null, constructorArgs); - } - - @SuppressWarnings("unchecked") - private T handleBinding(Binding binding, @Nullable CreateContext context, Object[] constructorArgs) { - return switch (binding) { - case ClassBinding(Class ignored, Class to) -> { - final Annotation scopeAnnotation = getScopeAnnotation(to); - if (scopeAnnotation != null) { - final Class scopeClass = scopeAnnotation.annotationType(); - @SuppressWarnings("rawtypes") - final ScopeHandler scopeHandler = this.getInSelfOrParent( - f -> f.findScopeHandler(scopeClass), - () -> new RuntimeException( - "There is no configured ScopeHandler for " + scopeClass.getName() - ) - ); - final Binding scopedBinding = scopeHandler.onScopedDependencyRequest( - scopeAnnotation, to, this - ); - yield this.handleBinding(scopedBinding, constructorArgs); - } else { - if (context != null) { - yield this.createInstance(context, to, constructorArgs); - } else { - yield this.createInstance(to, constructorArgs); - } - } - } - case ProviderBinding providerBinding -> providerBinding.provider().get(); - case SingletonBinding singletonBinding -> singletonBinding.to(); - case LazySingletonBinding lazySingletonBinding -> lazySingletonBinding.singletonSupplier().get(); - }; - } - - protected final @Nullable Binding searchRegistry(Class from) { - return this.registry.getBinding(from); - } - - protected @Nullable T tryParent(Class clazz, Object[] constructorArgs) { - return this.findInParent(f -> f.getOrNull(clazz, constructorArgs)).orElse(null); - } - - @Override - protected Object getSetterInjectArg(CreateContext context, Class targetType, Method setter, Parameter toInject) { - return this.resolveInjectedArg(context, toInject); - } - - /** - * {@inheritDoc} - */ - @Override - public T get(Class clazz, Object... constructorArgs) { - final Binding binding = this.searchRegistry(clazz); - if (binding != null) { - return this.handleBinding(binding, constructorArgs); - } - final T parentResult = this.tryParent(clazz, constructorArgs); - if (parentResult != null) { - return parentResult; - } else { - throw new RuntimeException( - "No bindings for " + clazz + " with args " + Arrays.toString(constructorArgs) + "." - ); - } - } - - protected T get(CreateContext context, Class type) { - final Binding binding = this.searchRegistry(type); - if (binding != null) { - return this.handleBinding(binding, context, EMPTY_OBJECT_ARRAY); - } - final T parentResult = this.tryParent(type, EMPTY_OBJECT_ARRAY); - if (parentResult != null) { - return parentResult; - } else { - throw new RuntimeException( - "No bindings for " + type + " with args " + Arrays.toString(EMPTY_OBJECT_ARRAY) + "." - ); - } - } - - /** - * {@inheritDoc} - */ - @Override - public T getOrDefault(Class clazz, T defaultValue, Object... constructorArgs) { - final Binding binding = this.searchRegistry(clazz); - if (binding != null) { - return this.handleBinding(binding, constructorArgs); - } - final T parentResult = this.tryParent(clazz, constructorArgs); - return parentResult != null ? parentResult : defaultValue; - } - -} diff --git a/util/di/src/main/java/groowt/util/di/ExtensionContainer.java b/util/di/src/main/java/groowt/util/di/ExtensionContainer.java deleted file mode 100644 index 75bd6eb..0000000 --- a/util/di/src/main/java/groowt/util/di/ExtensionContainer.java +++ /dev/null @@ -1,10 +0,0 @@ -package groowt.util.di; - -import java.util.Collection; - -public interface ExtensionContainer { - void addExtension(RegistryExtension extension); - E getExtension(Class extensionType); - Collection getExtensions(Class extensionType); - void removeExtension(RegistryExtension extension); -} diff --git a/util/di/src/main/java/groowt/util/di/KeyBinder.java b/util/di/src/main/java/groowt/util/di/KeyBinder.java deleted file mode 100644 index ab12600..0000000 --- a/util/di/src/main/java/groowt/util/di/KeyBinder.java +++ /dev/null @@ -1,16 +0,0 @@ -package groowt.util.di; - -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiPredicate; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public interface KeyBinder { - Class getKeyClass(); - , T> void bind(KeyHolder keyHolder, Consumer> configure); - , T> @Nullable Binding getBinding(KeyHolder keyHolder); - , T> void removeBinding(KeyHolder keyHolder); - , T> void removeBindingIf(KeyHolder keyHolder, Predicate> filter); - void clearAllBindings(); -} diff --git a/util/di/src/main/java/groowt/util/di/KeyHolder.java b/util/di/src/main/java/groowt/util/di/KeyHolder.java deleted file mode 100644 index 953b645..0000000 --- a/util/di/src/main/java/groowt/util/di/KeyHolder.java +++ /dev/null @@ -1,7 +0,0 @@ -package groowt.util.di; - -public interface KeyHolder, K, T> { - Class binderType(); - Class type(); - K key(); -} diff --git a/util/di/src/main/java/groowt/util/di/LazySingletonBinding.java b/util/di/src/main/java/groowt/util/di/LazySingletonBinding.java deleted file mode 100644 index d392a48..0000000 --- a/util/di/src/main/java/groowt/util/di/LazySingletonBinding.java +++ /dev/null @@ -1,5 +0,0 @@ -package groowt.util.di; - -import java.util.function.Supplier; - -public record LazySingletonBinding(Supplier singletonSupplier) implements Binding {} diff --git a/util/di/src/main/java/groowt/util/di/NamedRegistryExtension.java b/util/di/src/main/java/groowt/util/di/NamedRegistryExtension.java deleted file mode 100644 index e4cc93d..0000000 --- a/util/di/src/main/java/groowt/util/di/NamedRegistryExtension.java +++ /dev/null @@ -1,3 +0,0 @@ -package groowt.util.di; - -public interface NamedRegistryExtension extends RegistryExtension, KeyBinder, QualifierHandlerContainer {} diff --git a/util/di/src/main/java/groowt/util/di/ObjectFactory.java b/util/di/src/main/java/groowt/util/di/ObjectFactory.java deleted file mode 100644 index db0ee81..0000000 --- a/util/di/src/main/java/groowt/util/di/ObjectFactory.java +++ /dev/null @@ -1,61 +0,0 @@ -package groowt.util.di; - -import org.jetbrains.annotations.Contract; - -import java.util.function.Function; - -/** - * An {@link ObjectFactory} is an object that can construct objects of given types. - */ -@FunctionalInterface -public interface ObjectFactory { - - /** - * Create a new instance of the given {@code instanceType} with the given constructor args. - * - * @apiNote An implementation may provide a subclass of the given instance type, - * or it may directly instantiate the given type, if it is a class - * and it can determine the correct constructor from the given arguments. - * See individual implementation documentation for exact behavior. - * - * @implSpec It is up to individual implementations of {@link ObjectFactory} to determine how to - * select the appropriate constructor for the given type. The returned - * instance must be new and in a valid state. - * - * @param instanceType the {@link Class} of the desired type - * @param constructorArgs any arguments to pass to the constructor(s) of the class. - * @return the new instance - * @param the desired type - */ - @Contract("_, _-> new") - T createInstance(Class instanceType, Object... constructorArgs); - - /** - * Very similar to {@link #createInstance(Class, Object...)}, but catches any {@link RuntimeException} - * thrown by {@link #createInstance} and subsequently passes it to the given {@link Function}, returning - * instead the return value of the {@link Function}. - * - * @param instanceType the desired type of the created instance - * @param onException a {@link Function} to handle when an exception occurs and return a value nonetheless - * @param constructorArgs arguments to pass to the constructor - * @return the created instance - * @param the desired type - * - * @throws RuntimeException if the given {@link Function} itself throws a RuntimeException - * - * @see #createInstance(Class, Object...) - */ - @Contract("_, _, _ -> new") - default T createInstanceCatching( - Class instanceType, - Function onException, - Object... constructorArgs - ) { - try { - return this.createInstance(instanceType, constructorArgs); - } catch (RuntimeException runtimeException) { - return onException.apply(runtimeException); - } - } - -} diff --git a/util/di/src/main/java/groowt/util/di/ObjectFactoryUtil.java b/util/di/src/main/java/groowt/util/di/ObjectFactoryUtil.java deleted file mode 100644 index 9e0a10f..0000000 --- a/util/di/src/main/java/groowt/util/di/ObjectFactoryUtil.java +++ /dev/null @@ -1,23 +0,0 @@ -package groowt.util.di; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public final class ObjectFactoryUtil { - - public static Class[] toTypes(Object... objects) { - final Class[] types = new Class[objects.length]; - for (int i = 0; i < objects.length; i++) { - final Object o = objects[i]; - if (o != null) { - types[i] = o.getClass(); - } else { - types[i] = Object.class; - } - } - return types; - } - - private ObjectFactoryUtil() {} - -} diff --git a/util/di/src/main/java/groowt/util/di/ProviderBinding.java b/util/di/src/main/java/groowt/util/di/ProviderBinding.java deleted file mode 100644 index 8ab5979..0000000 --- a/util/di/src/main/java/groowt/util/di/ProviderBinding.java +++ /dev/null @@ -1,5 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Provider; - -public record ProviderBinding(Class to, Provider provider) implements Binding {} diff --git a/util/di/src/main/java/groowt/util/di/QualifierHandler.java b/util/di/src/main/java/groowt/util/di/QualifierHandler.java deleted file mode 100644 index 3b04737..0000000 --- a/util/di/src/main/java/groowt/util/di/QualifierHandler.java +++ /dev/null @@ -1,10 +0,0 @@ -package groowt.util.di; - -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; - -@FunctionalInterface -public interface QualifierHandler { - @Nullable Binding handle(A annotation, Class dependencyClass); -} diff --git a/util/di/src/main/java/groowt/util/di/QualifierHandlerContainer.java b/util/di/src/main/java/groowt/util/di/QualifierHandlerContainer.java deleted file mode 100644 index 2fd98bf..0000000 --- a/util/di/src/main/java/groowt/util/di/QualifierHandlerContainer.java +++ /dev/null @@ -1,20 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Qualifier; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; - -public interface QualifierHandlerContainer { - - static void checkIsValidQualifier(Class annotationClass) { - if (!annotationClass.isAnnotationPresent(Qualifier.class)) { - throw new IllegalArgumentException( - "The given qualifier annotation + " + annotationClass + " is itself not annotated with @Qualifier" - ); - } - } - - @Nullable QualifierHandler getQualifierHandler(Class qualifierType); - -} diff --git a/util/di/src/main/java/groowt/util/di/Registry.java b/util/di/src/main/java/groowt/util/di/Registry.java deleted file mode 100644 index cdb778e..0000000 --- a/util/di/src/main/java/groowt/util/di/Registry.java +++ /dev/null @@ -1,21 +0,0 @@ -package groowt.util.di; - -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; -import java.util.function.Predicate; - -public interface Registry extends ExtensionContainer, QualifierHandlerContainer, ScopeHandlerContainer { - - void bind(Class key, Consumer> configure); - @Nullable Binding getBinding(Class key); - void removeBinding(Class key); - void removeBindingIf(Class key, Predicate> filter); - - void bind(KeyHolder keyHolder, Consumer> configure); - @Nullable Binding getBinding(KeyHolder keyHolder); - void removeBinding(KeyHolder keyHolder); - void removeBindingIf(KeyHolder keyHolder, Predicate> filter); - void clearAllBindings(); - -} diff --git a/util/di/src/main/java/groowt/util/di/RegistryExtension.java b/util/di/src/main/java/groowt/util/di/RegistryExtension.java deleted file mode 100644 index 5010d43..0000000 --- a/util/di/src/main/java/groowt/util/di/RegistryExtension.java +++ /dev/null @@ -1,3 +0,0 @@ -package groowt.util.di; - -public interface RegistryExtension {} diff --git a/util/di/src/main/java/groowt/util/di/RegistryObjectFactory.java b/util/di/src/main/java/groowt/util/di/RegistryObjectFactory.java deleted file mode 100644 index 2ff25e8..0000000 --- a/util/di/src/main/java/groowt/util/di/RegistryObjectFactory.java +++ /dev/null @@ -1,126 +0,0 @@ -package groowt.util.di; - -import groovy.lang.Closure; -import groovy.lang.DelegatesTo; -import groowt.util.di.filters.FilterHandler; -import groowt.util.di.filters.IterableFilterHandler; -import jakarta.inject.Provider; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; -import java.util.function.Consumer; - -/** - * A {@link RegistryObjectFactory} is an {@link ObjectFactory} that offers the ability - * to provide desired objects based on an instance of - * {@link Registry} to determine how to provide those objects. - */ -public interface RegistryObjectFactory extends ObjectFactory { - - interface Builder { - - void configureRegistry(Consumer configure); - - default void configureRegistry(@DelegatesTo(Registry.class) Closure configureClosure) { - this.configureRegistry(registry -> { - configureClosure.setDelegate(registry); - configureClosure.call(); - }); - } - - void addFilterHandler(FilterHandler handler); - - void addIterableFilterHandler(IterableFilterHandler handler); - - T build(); - - } - - Registry getRegistry(); - - default void configureRegistry(Consumer use) { - use.accept(this.getRegistry()); - } - - default void configureRegistry( - @DelegatesTo(value = Registry.class) - Closure configureClosure - ) { - final Registry registry = this.getRegistry(); - configureClosure.setDelegate(registry); - configureClosure.call(); - } - - @Nullable ScopeHandler findScopeHandler(Class scopeType); - - @Nullable QualifierHandler findQualifierHandler(Class qualifierType); - - /** - * Get an object with the desired type. How it is retrieved/created - * depends upon the {@link Binding} present in this {@link RegistryObjectFactory}'s held - * instances of {@link Registry}. The type of the {@link Binding} determines - * how the object is fetched: - * - *
    - *
  • {@link ClassBinding}: A new instance of the object is created using the given {@code constructorArgs}.
  • - *
  • {@link ProviderBinding}: An instance of the object is fetched from the bound {@link Provider}. - * Whether the instance is new or not depends on the {@link Provider}.
  • - *
  • {@link SingletonBinding}: The bound singleton object is returned.
  • - *
- * - * @implNote If {@code constructorArgs} are provided - * and the {@link Binding} for the desired type is not a - * {@link ClassBinding}, the implementation should - * either throw an exception or log a warning at the least. - * - * @param clazz the {@link Class} of the desired type - * @param constructorArgs As in {@link #createInstance(Class, Object...)}, - * the arguments which will be used to create the desired object - * if the {@link Binding} is a {@link ClassBinding}. - * @return an object of the desired type - * @param the desired type - * - * @throws RuntimeException if there is no registered {@link Binding} or there is a problem - * fetching or constructing the object. - */ - T get(Class clazz, Object... constructorArgs); - - /** - * Similarly to {@link #get(Class, Object...)}, fetches an object - * of the desired type, but does not throw if there is no registered {@link Binding} - * in any of the held instances of {@link Registry}, - * and instead returns the given {@code defaultValue}. - * - * @param clazz the {@link Class} of the desired type - * @param defaultValue the defaultValue to return - * @param constructorArgs see {@link #get(Class, Object...)} - * @return an object of the desired type - * @param the desired type - * - * @throws RuntimeException if there is a registered {@link Binding} and there is a problem - * fetching or constructing the object. - * - * @see #get(Class, Object...) - */ - T getOrDefault(Class clazz, T defaultValue, Object... constructorArgs); - - /** - * Similar to {@link #getOrDefault(Class, Object, Object...)}, except that - * it returns null by default if there is no registered {@link Binding}. - * - * @param clazz the {@link Class} of the desired type - * @param constructorArgs see {@link RegistryObjectFactory#get(Class, Object...)} - * @return an object of the desired type - * @param the desired type - * - * @see RegistryObjectFactory#get(Class, Object...) - * @see RegistryObjectFactory#getOrDefault(Class, Object, Object...) - * - * @throws RuntimeException if there is a registered {@code Binding} and there - * is a problem fetching or constructing the object. - */ - default @Nullable T getOrNull(Class clazz, Object... constructorArgs) { - return this.getOrDefault(clazz, null, constructorArgs); - } - -} diff --git a/util/di/src/main/java/groowt/util/di/RegistryObjectFactoryUtil.java b/util/di/src/main/java/groowt/util/di/RegistryObjectFactoryUtil.java deleted file mode 100644 index d32b351..0000000 --- a/util/di/src/main/java/groowt/util/di/RegistryObjectFactoryUtil.java +++ /dev/null @@ -1,69 +0,0 @@ -package groowt.util.di; - -import groowt.util.di.filters.Filter; -import groowt.util.di.filters.IterableFilter; -import jakarta.inject.Qualifier; -import jakarta.inject.Scope; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.function.Supplier; - -@ApiStatus.Internal -public final class RegistryObjectFactoryUtil { - - private RegistryObjectFactoryUtil() {} - - public static List getQualifierAnnotations(Annotation[] annotations) { - return Arrays.stream(annotations) - .filter(a -> a.annotationType().isAnnotationPresent(Qualifier.class)) - .toList(); - } - - public static List getFilterAnnotations(Annotation[] annotations) { - return Arrays.stream(annotations) - .filter(a -> a.annotationType().isAnnotationPresent(Filter.class)) - .toList(); - } - - public static List getIterableFilterAnnotations(Annotation[] annotations) { - return Arrays.stream(annotations) - .filter(a -> a.annotationType().isAnnotationPresent(IterableFilter.class)) - .toList(); - } - - public static Optional orElseSupply(T first, Supplier onNullFirst) { - return first != null ? Optional.of(first) : Optional.ofNullable(onNullFirst.get()); - } - - public static void checkIsValidFilter(Class annotationClass) { - if (!annotationClass.isAnnotationPresent(Filter.class)) { - throw new IllegalArgumentException( - "The given filter annotation " + annotationClass.getName() + " is itself not annotated with @Filter" - ); - } - } - - public static void checkIsValidIterableFilter(Class annotationClass) { - if (!annotationClass.isAnnotationPresent(IterableFilter.class)) { - throw new IllegalArgumentException( - "The given iterable filter annotation " + annotationClass.getName() + " is itself not annotated with @IterableFilter" - ); - } - } - - public static @Nullable Annotation getScopeAnnotation(Class clazz) { - final List scopeAnnotations = Arrays.stream(clazz.getAnnotations()) - .filter(annotation -> annotation.annotationType().isAnnotationPresent(Scope.class)) - .toList(); - if (scopeAnnotations.size() > 1) { - throw new RuntimeException(clazz.getName() + " has too many annotations that are themselves annotated with @Scope"); - } - return scopeAnnotations.size() == 1 ? scopeAnnotations.getFirst() : null; - } - -} diff --git a/util/di/src/main/java/groowt/util/di/ScopeHandler.java b/util/di/src/main/java/groowt/util/di/ScopeHandler.java deleted file mode 100644 index 31f3bc8..0000000 --- a/util/di/src/main/java/groowt/util/di/ScopeHandler.java +++ /dev/null @@ -1,8 +0,0 @@ -package groowt.util.di; - -import java.lang.annotation.Annotation; - -public interface ScopeHandler
{ - Binding onScopedDependencyRequest(A annotation, Class dependencyClass, RegistryObjectFactory objectFactory); - void reset(); -} diff --git a/util/di/src/main/java/groowt/util/di/ScopeHandlerContainer.java b/util/di/src/main/java/groowt/util/di/ScopeHandlerContainer.java deleted file mode 100644 index b08d3aa..0000000 --- a/util/di/src/main/java/groowt/util/di/ScopeHandlerContainer.java +++ /dev/null @@ -1,20 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Scope; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; - -public interface ScopeHandlerContainer { - - static void checkIsValidScope(Class scope) { - if (!scope.isAnnotationPresent(Scope.class)) { - throw new IllegalArgumentException( - "The given scope annotation " + scope + " is itself not annotated with @Scope" - ); - } - } - - @Nullable ScopeHandler getScopeHandler(Class scopeType); - -} diff --git a/util/di/src/main/java/groowt/util/di/SimpleBindingConfigurator.java b/util/di/src/main/java/groowt/util/di/SimpleBindingConfigurator.java deleted file mode 100644 index 4a682b1..0000000 --- a/util/di/src/main/java/groowt/util/di/SimpleBindingConfigurator.java +++ /dev/null @@ -1,43 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Provider; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Supplier; - -public class SimpleBindingConfigurator implements BindingConfigurator { - - private final Class from; - private @Nullable Binding binding; - - public SimpleBindingConfigurator(Class from) { - this.from = from; - } - - public final Binding getBinding() { - return this.binding != null - ? this.binding - : new ClassBinding<>(this.from, this.from); // return SelfBinding in case we never called anything - } - - @Override - public void to(Class target) { - this.binding = new ClassBinding<>(this.from, target); - } - - @Override - public void toProvider(Provider provider) { - this.binding = new ProviderBinding<>(this.from, provider); - } - - @Override - public void toSingleton(T target) { - this.binding = new SingletonBinding<>(target); - } - - @Override - public void toLazySingleton(Supplier singletonSupplier) { - this.binding = new LazySingletonBinding<>(singletonSupplier); - } - -} diff --git a/util/di/src/main/java/groowt/util/di/SimpleKeyHolder.java b/util/di/src/main/java/groowt/util/di/SimpleKeyHolder.java deleted file mode 100644 index 47a1745..0000000 --- a/util/di/src/main/java/groowt/util/di/SimpleKeyHolder.java +++ /dev/null @@ -1,4 +0,0 @@ -package groowt.util.di; - -public record SimpleKeyHolder, K, T>(Class binderType, Class type, K key) - implements KeyHolder {} diff --git a/util/di/src/main/java/groowt/util/di/SingletonBinding.java b/util/di/src/main/java/groowt/util/di/SingletonBinding.java deleted file mode 100644 index 67e04c6..0000000 --- a/util/di/src/main/java/groowt/util/di/SingletonBinding.java +++ /dev/null @@ -1,3 +0,0 @@ -package groowt.util.di; - -public record SingletonBinding(T to) implements Binding {} diff --git a/util/di/src/main/java/groowt/util/di/SingletonRegistryExtension.java b/util/di/src/main/java/groowt/util/di/SingletonRegistryExtension.java deleted file mode 100644 index 0e6e70e..0000000 --- a/util/di/src/main/java/groowt/util/di/SingletonRegistryExtension.java +++ /dev/null @@ -1,22 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Singleton; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; - -public class SingletonRegistryExtension implements RegistryExtension, ScopeHandlerContainer { - - private final SingletonScopeHandler handler; - - public SingletonRegistryExtension(Registry owner) { - this.handler = new SingletonScopeHandler(owner); - } - - @SuppressWarnings("unchecked") - @Override - public @Nullable ScopeHandler getScopeHandler(Class scopeType) { - return Singleton.class.isAssignableFrom(scopeType) ? (ScopeHandler) this.handler : null; - } - -} diff --git a/util/di/src/main/java/groowt/util/di/SingletonScopeHandler.java b/util/di/src/main/java/groowt/util/di/SingletonScopeHandler.java deleted file mode 100644 index 56f884e..0000000 --- a/util/di/src/main/java/groowt/util/di/SingletonScopeHandler.java +++ /dev/null @@ -1,46 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -import static groowt.util.di.BindingUtil.toLazySingleton; - -public final class SingletonScopeHandler implements ScopeHandler { - - private final Registry owner; - - public SingletonScopeHandler(Registry owner) { - this.owner = owner; - } - - @Override - public Binding onScopedDependencyRequest( - Singleton annotation, - Class dependencyClass, - RegistryObjectFactory objectFactory - ) { - final Binding potentialBinding = this.owner.getBinding(dependencyClass); - return switch (potentialBinding) { - case ClassBinding(Class from, Class to) -> { - this.owner.bind(from, toLazySingleton(() -> objectFactory.createInstance(to))); - yield this.owner.getBinding(from); - } - case ProviderBinding(Class from, Provider provider) -> { - this.owner.bind(from, toLazySingleton(provider::get)); - yield this.owner.getBinding(from); - } - case SingletonBinding singletonBinding -> singletonBinding; - case LazySingletonBinding lazySingletonBinding -> lazySingletonBinding; - case null -> { - this.owner.bind(dependencyClass, toLazySingleton(() -> objectFactory.createInstance(dependencyClass))); - yield this.owner.getBinding(dependencyClass); - } - }; - } - - @Override - public void reset() { - throw new UnsupportedOperationException("Cannot reset the Singleton scope!"); - } - -} diff --git a/util/di/src/main/java/groowt/util/di/annotation/Given.java b/util/di/src/main/java/groowt/util/di/annotation/Given.java deleted file mode 100644 index ce94d25..0000000 --- a/util/di/src/main/java/groowt/util/di/annotation/Given.java +++ /dev/null @@ -1,10 +0,0 @@ -package groowt.util.di.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.SOURCE) -@Target(ElementType.PARAMETER) -public @interface Given {} diff --git a/util/di/src/main/java/groowt/util/di/filters/Filter.java b/util/di/src/main/java/groowt/util/di/filters/Filter.java deleted file mode 100644 index 3f36642..0000000 --- a/util/di/src/main/java/groowt/util/di/filters/Filter.java +++ /dev/null @@ -1,10 +0,0 @@ -package groowt.util.di.filters; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.ANNOTATION_TYPE }) -public @interface Filter {} diff --git a/util/di/src/main/java/groowt/util/di/filters/FilterHandler.java b/util/di/src/main/java/groowt/util/di/filters/FilterHandler.java deleted file mode 100644 index 8581259..0000000 --- a/util/di/src/main/java/groowt/util/di/filters/FilterHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -package groowt.util.di.filters; - -import java.lang.annotation.Annotation; -import java.util.Objects; -import java.util.function.BiPredicate; - -public interface FilterHandler { - - boolean check(A annotation, T arg); - Class getAnnotationClass(); - Class getArgumentClass(); - - default FilterHandler and(BiPredicate and) { - Objects.requireNonNull(and); - return new SimpleFilterHandler<>( - (a, t) -> this.check(a, t) && and.test(a, t), - this.getAnnotationClass(), - this.getArgumentClass() - ); - } - - default FilterHandler or(BiPredicate or) { - Objects.requireNonNull(or); - return new SimpleFilterHandler<>( - (a, t) -> this.check(a, t) || or.test(a, t), - this.getAnnotationClass(), - this.getArgumentClass() - ); - } - - default FilterHandler negate() { - return new SimpleFilterHandler<>( - (a, t) -> !this.check(a, t), - this.getAnnotationClass(), - this.getArgumentClass() - ); - } - -} diff --git a/util/di/src/main/java/groowt/util/di/filters/FilterHandlers.java b/util/di/src/main/java/groowt/util/di/filters/FilterHandlers.java deleted file mode 100644 index 08e908e..0000000 --- a/util/di/src/main/java/groowt/util/di/filters/FilterHandlers.java +++ /dev/null @@ -1,35 +0,0 @@ -package groowt.util.di.filters; - -import java.lang.annotation.*; -import java.util.function.BiPredicate; - -import static groowt.util.di.filters.FilterUtil.isAssignableToAnyOf; - -public final class FilterHandlers { - - private FilterHandlers() {} - - public static FilterHandler of( - Class annotationClass, - Class argClass, - BiPredicate predicate - ) { - return new SimpleFilterHandler<>(predicate, annotationClass, argClass); - } - - @Filter - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.PARAMETER) - public @interface AllowTypes { - Class[] value(); - } - - public static FilterHandler getAllowsTypesFilterHandler(Class targetType) { - return of( - AllowTypes.class, - targetType, - (annotation, target) -> isAssignableToAnyOf(target.getClass(), annotation.value()) - ); - } - -} diff --git a/util/di/src/main/java/groowt/util/di/filters/FilterUtil.java b/util/di/src/main/java/groowt/util/di/filters/FilterUtil.java deleted file mode 100644 index 7471625..0000000 --- a/util/di/src/main/java/groowt/util/di/filters/FilterUtil.java +++ /dev/null @@ -1,16 +0,0 @@ -package groowt.util.di.filters; - -public final class FilterUtil { - - private FilterUtil() {} - - public static boolean isAssignableToAnyOf(Class subject, Class[] tests) { - for (final var test : tests) { - if (test.isAssignableFrom(subject)) { - return true; - } - } - return false; - } - -} diff --git a/util/di/src/main/java/groowt/util/di/filters/IterableFilter.java b/util/di/src/main/java/groowt/util/di/filters/IterableFilter.java deleted file mode 100644 index 63a80d1..0000000 --- a/util/di/src/main/java/groowt/util/di/filters/IterableFilter.java +++ /dev/null @@ -1,10 +0,0 @@ -package groowt.util.di.filters; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.ANNOTATION_TYPE) -public @interface IterableFilter {} diff --git a/util/di/src/main/java/groowt/util/di/filters/IterableFilterHandler.java b/util/di/src/main/java/groowt/util/di/filters/IterableFilterHandler.java deleted file mode 100644 index 26005e1..0000000 --- a/util/di/src/main/java/groowt/util/di/filters/IterableFilterHandler.java +++ /dev/null @@ -1,8 +0,0 @@ -package groowt.util.di.filters; - -import java.lang.annotation.Annotation; - -public interface IterableFilterHandler { - boolean check(A annotation, Iterable iterable); - Class getAnnotationClass(); -} diff --git a/util/di/src/main/java/groowt/util/di/filters/IterableFilterHandlers.java b/util/di/src/main/java/groowt/util/di/filters/IterableFilterHandlers.java deleted file mode 100644 index 78cde67..0000000 --- a/util/di/src/main/java/groowt/util/di/filters/IterableFilterHandlers.java +++ /dev/null @@ -1,33 +0,0 @@ -package groowt.util.di.filters; - -import java.lang.annotation.*; -import java.util.function.BiPredicate; - -import static groowt.util.di.filters.FilterUtil.isAssignableToAnyOf; - -public final class IterableFilterHandlers { - - private IterableFilterHandlers() {} - - public static IterableFilterHandler of( - Class filterType, - BiPredicate elementPredicate - ) { - return new SimpleIterableFilterHandler<>(filterType, elementPredicate); - } - - @IterableFilter - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.PARAMETER) - public @interface IterableElementTypes { - Class[] value(); - } - - public static IterableFilterHandler getIterableElementTypesFilterHandler() { - return of( - IterableElementTypes.class, - (annotation, element) -> isAssignableToAnyOf(element.getClass(), annotation.value()) - ); - } - -} diff --git a/util/di/src/main/java/groowt/util/di/filters/SimpleFilterHandler.java b/util/di/src/main/java/groowt/util/di/filters/SimpleFilterHandler.java deleted file mode 100644 index 338c504..0000000 --- a/util/di/src/main/java/groowt/util/di/filters/SimpleFilterHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package groowt.util.di.filters; - -import java.lang.annotation.Annotation; -import java.util.function.BiPredicate; - -final class SimpleFilterHandler implements FilterHandler { - - private final BiPredicate predicate; - private final Class annotationClass; - private final Class argClass; - - public SimpleFilterHandler(BiPredicate predicate, Class annotationClass, Class argClass) { - this.predicate = predicate; - this.annotationClass = annotationClass; - this.argClass = argClass; - } - - @Override - public boolean check(A annotation, T arg) { - return this.predicate.test(annotation, arg); - } - - @Override - public Class getAnnotationClass() { - return this.annotationClass; - } - - @Override - public Class getArgumentClass() { - return this.argClass; - } - -} diff --git a/util/di/src/main/java/groowt/util/di/filters/SimpleIterableFilterHandler.java b/util/di/src/main/java/groowt/util/di/filters/SimpleIterableFilterHandler.java deleted file mode 100644 index 3236cce..0000000 --- a/util/di/src/main/java/groowt/util/di/filters/SimpleIterableFilterHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -package groowt.util.di.filters; - -import java.lang.annotation.Annotation; -import java.util.Objects; -import java.util.function.BiPredicate; - -final class SimpleIterableFilterHandler implements IterableFilterHandler { - - private final Class annotationClass; - private final BiPredicate elementPredicate; - - public SimpleIterableFilterHandler(Class annotationClass, BiPredicate elementPredicate) { - this.annotationClass = annotationClass; - this.elementPredicate = elementPredicate; - } - - @Override - public boolean check(A annotation, Iterable iterable) { - for (final var e : Objects.requireNonNull(iterable)) { - if (!this.elementPredicate.test(annotation, e)) { - return false; - } - } - return true; - } - - @Override - public Class getAnnotationClass() { - return this.annotationClass; - } - -} diff --git a/util/di/src/test/java/groowt/util/di/DefaultRegistryObjectFactoryTests.java b/util/di/src/test/java/groowt/util/di/DefaultRegistryObjectFactoryTests.java deleted file mode 100644 index 5381de8..0000000 --- a/util/di/src/test/java/groowt/util/di/DefaultRegistryObjectFactoryTests.java +++ /dev/null @@ -1,275 +0,0 @@ -package groowt.util.di; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Singleton; -import org.junit.jupiter.api.Test; - -import static groowt.util.di.BindingUtil.*; -import static org.junit.jupiter.api.Assertions.*; - -public class DefaultRegistryObjectFactoryTests { - - public interface Greeter { - String greet(); - } - - public static final class DefaultGreeter implements Greeter { - - @Override - public String greet() { - return "Hello, World!"; - } - - } - - public static final class GivenArgGreeter implements Greeter { - - private final String greeting; - - @Inject - public GivenArgGreeter(String greeting) { - this.greeting = greeting; - } - - @Override - public String greet() { - return this.greeting; - } - - } - - public static final class InjectedArgGreeter implements Greeter { - - private final String greeting; - - @Inject - public InjectedArgGreeter(String greeting) { - this.greeting = greeting; - } - - @Override - public String greet() { - return this.greeting; - } - - } - - public static final class InjectedNamedArgGreeter implements Greeter { - - private final String greeting; - - @Inject - public InjectedNamedArgGreeter(@Named("greeting") String greeting) { - this.greeting = greeting; - } - - @Override - public String greet() { - return this.greeting; - } - - } - - public static final class InjectedNamedSetterGreeter implements Greeter { - - private String greeting; - - @Inject - public void setGreeting(@Named("greeting") String greeting) { - this.greeting = greeting; - } - - @Override - public String greet() { - return this.greeting; - } - - } - - @Test - public void classSmokeScreen() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(registry -> { - registry.bind(Greeter.class, bc -> bc.to(DefaultGreeter.class)); - }); - final RegistryObjectFactory container = b.build(); - final Greeter greeter = container.get(Greeter.class); - assertEquals("Hello, World!", greeter.greet()); - } - - @Test - public void singletonSmokeScreen() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(registry -> { - registry.bind(Greeter.class, toSingleton(new DefaultGreeter())); - }); - final RegistryObjectFactory container = b.build(); - final Greeter greeter = container.get(Greeter.class); - assertEquals("Hello, World!", greeter.greet()); - } - - @Test - public void providerSmokeScreen() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(registry -> { - registry.bind(Greeter.class, toProvider(DefaultGreeter::new)); - }); - final RegistryObjectFactory container = b.build(); - final Greeter greeter = container.get(Greeter.class); - assertEquals("Hello, World!", greeter.greet()); - } - - @Test - public void givenArgSmokeScreen() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(registry -> { - registry.bind(Greeter.class, bc -> bc.to(GivenArgGreeter.class)); - }); - final RegistryObjectFactory container = b.build(); - final Greeter greeter = container.get(Greeter.class, "Hello, World!"); - assertEquals("Hello, World!", greeter.greet()); - } - - @Test - public void injectedArg() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(registry -> { - registry.bind(Greeter.class, bc -> bc.to(InjectedArgGreeter.class)); - registry.bind(String.class, toSingleton("Hello, World!")); - }); - final RegistryObjectFactory container = b.build(); - final Greeter greeter = container.get(Greeter.class); - assertEquals("Hello, World!", greeter.greet()); - } - - @Test - public void injectedNamedArg() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(registry -> { - registry.bind(Greeter.class, bc -> bc.to(InjectedNamedArgGreeter.class)); - registry.bind(named("greeting", String.class), toSingleton("Hello, World!")); - }); - final RegistryObjectFactory container = b.build(); - final Greeter greeter = container.get(Greeter.class); - assertEquals("Hello, World!", greeter.greet()); - } - - @Test - public void injectedSetter() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(r -> { - r.bind(Greeter.class, toClass(InjectedNamedSetterGreeter.class)); - r.bind(named("greeting", String.class), toSingleton("Hello, World!")); - }); - final RegistryObjectFactory f = b.build(); - final Greeter greeter = f.get(Greeter.class); - assertEquals("Hello, World!", greeter.greet()); - } - - public static final class GreeterDependency { - - private GreeterDependencyUser greeter; - - @Inject - public void setGreeter(GreeterDependencyUser greeter) { - this.greeter = greeter; - } - - public String filterGreeting() { - return this.greeter.getGreeting().toUpperCase(); - } - - } - - public static final class GreeterDependencyUser implements Greeter { - - private final GreeterDependency greeterDependency; - - @Inject - public GreeterDependencyUser(GreeterDependency greeterDependency) { - this.greeterDependency = greeterDependency; - } - - @Override - public String greet() { - return this.greeterDependency.filterGreeting(); - } - - public String getGreeting() { - return "hello, world!"; - } - - } - - @Test - public void injectedDeferred() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(r -> { - r.bind(GreeterDependencyUser.class, toSelf()); - r.bind(GreeterDependency.class, toSelf()); - }); - final var f = b.build(); - final var g = f.get(GreeterDependencyUser.class); - assertEquals("HELLO, WORLD!", g.greet()); - } - - public static final class NoInjectGreeter implements Greeter { - - private final String greeting; - - public NoInjectGreeter(String greeting) { - this.greeting = greeting; - } - - @Override - public String greet() { - return this.greeting; - } - - } - - @Test - public void noInjectFoundViaGet() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(r -> { - r.bind(NoInjectGreeter.class, toSelf()); - }); - final var f = b.build(); - final var g = f.get(NoInjectGreeter.class, "Given Greeting"); - assertEquals("Given Greeting", g.greet()); - } - - @Test - public void noInjectFindViaCreate() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(r -> { - r.bind(NoInjectGreeter.class, toSelf()); - }); - final var f = b.build(); - final var g = f.createInstance(NoInjectGreeter.class, "Given Greeting"); - assertEquals("Given Greeting", g.greet()); - } - - @Singleton - public static final class SingletonGreeter implements Greeter { - - @Override - public String greet() { - return "Hello, World!"; - } - - } - - @Test - public void singletonDoesNotOverflow() { - final var b = DefaultRegistryObjectFactory.Builder.withDefaults(); - b.configureRegistry(r -> { - r.bind(SingletonGreeter.class, toSelf()); - }); - final var f = b.build(); - final var g = f.get(SingletonGreeter.class); - assertEquals("Hello, World!", g.greet()); - } - -} diff --git a/util/di/src/test/resources/log4j2.xml b/util/di/src/test/resources/log4j2.xml deleted file mode 100644 index beab8e9..0000000 --- a/util/di/src/test/resources/log4j2.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file