Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upgrade to aerogel v3 #1524

Open
wants to merge 10 commits into
base: nightly
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ subprojects {
if (project.path != ":launcher:java8" && project.path != ":launcher:patcher") {
options.compilerArgs.add("--enable-preview")
options.compilerArgs.add("-Xlint:-deprecation,-unchecked,-preview")
options.compilerArgs.add("-proc:full")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package eu.cloudnetservice.driver.document.defaults;

import dev.derklaro.aerogel.auto.Provides;
import dev.derklaro.aerogel.auto.annotation.Provides;
import eu.cloudnetservice.driver.document.DocumentFactory;
import eu.cloudnetservice.driver.document.DocumentFactoryRegistry;
import eu.cloudnetservice.driver.document.empty.EmptyDocumentFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package eu.cloudnetservice.driver.event;

import dev.derklaro.aerogel.auto.Provides;
import dev.derklaro.aerogel.auto.annotation.Provides;
import eu.cloudnetservice.driver.inject.InjectionLayer;
import jakarta.inject.Singleton;
import java.lang.reflect.Modifier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package eu.cloudnetservice.driver.event;

import dev.derklaro.aerogel.Element;
import dev.derklaro.aerogel.binding.key.BindingKey;
import dev.derklaro.reflexion.MethodAccessor;
import dev.derklaro.reflexion.Reflexion;
import eu.cloudnetservice.driver.inject.InjectUtil;
Expand All @@ -40,7 +40,7 @@ final class DefaultRegisteredEventListener implements RegisteredEventListener {
private final EventListener eventListener;

private final String methodName;
private final Element[] methodArguments;
private final BindingKey<?>[] methodArguments;
private final MethodAccessor<?> methodAccessor;

private final InjectionLayer<?> injectionLayer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,33 @@

package eu.cloudnetservice.driver.inject;

import dev.derklaro.aerogel.Element;
import dev.derklaro.aerogel.InjectionContext;
import dev.derklaro.aerogel.Injector;
import dev.derklaro.aerogel.SpecifiedInjector;
import dev.derklaro.aerogel.auto.runtime.AutoAnnotationRegistry;
import dev.derklaro.aerogel.binding.BindingConstructor;
import dev.derklaro.aerogel.internal.context.util.ContextInstanceResolveHelper;
import dev.derklaro.aerogel.auto.AerogelAutoModule;
import dev.derklaro.aerogel.binding.DynamicBinding;
import dev.derklaro.aerogel.binding.UninstalledBinding;
import dev.derklaro.aerogel.binding.key.BindingKey;
import dev.derklaro.aerogel.internal.context.scope.InjectionContextProvider;
import jakarta.inject.Provider;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import lombok.NonNull;
import org.jetbrains.annotations.UnknownNullability;

/**
* The default implementation for of an injector layer.
*
* @param injector the injector to use for the layer.
* @param autoRegistry the auto registry to use for the layer.
* @param name the name of this injection layer.
* @param <I> the type of injector this layer uses.
* @param injector the injector to use for the layer.
* @param autoModule the auto registry to use for the layer.
* @param name the name of this injection layer.
* @param <I> the type of injector this layer uses.
* @since 4.0
*/
record DefaultInjectionLayer<I extends Injector>(
@NonNull I injector,
@NonNull AutoAnnotationRegistry autoRegistry,
@NonNull AerogelAutoModule autoModule,
@NonNull String name
) implements InjectionLayer<I> {

Expand All @@ -62,8 +66,8 @@ record DefaultInjectionLayer<I extends Injector>(
* {@inheritDoc}
*/
@Override
public <T> @UnknownNullability T instance(@NonNull Element element) {
return this.injector.instance(element);
public <T> @UnknownNullability T instance(@NonNull BindingKey<T> bindingKey) {
return this.injector.instance(bindingKey);
}

/**
Expand All @@ -73,26 +77,41 @@ record DefaultInjectionLayer<I extends Injector>(
@SuppressWarnings("unchecked")
public <T> @UnknownNullability T instance(
@NonNull Class<T> type,
@NonNull Consumer<InjectionContext.Builder> builder
@NonNull Consumer<Map<BindingKey<?>, Provider<?>>> overrides
) {
// get the binding associated with the given type & construct a context builder
var element = Element.forType(type);
var element = BindingKey.of(type);
var binding = this.injector.binding(element);
var contextBuilder = InjectionContext.builder(type, binding.provider(element));

// apply the builder decorator to the builder
builder.accept(contextBuilder);
// construct the map and decorate it using the consumer
Map<BindingKey<?>, Provider<?>> overridesMap = new HashMap<>();
overrides.accept(overridesMap);

var contextScope = InjectionContextProvider.provider().enterContextScope(this.injector, binding, overridesMap);

// resolve the instance
return (T) ContextInstanceResolveHelper.resolveInstanceAndRemoveContext(contextBuilder.build());
return contextScope.executeScoped(() -> {
try {
return (T) contextScope.context().resolveInstance();
} finally {
if (contextScope.context().root()) {
contextScope.context().finishConstruction();
}
}
});
}

/**
* {@inheritDoc}
*/
@Override
public void install(@NonNull BindingConstructor constructor) {
this.injector.install(constructor);
public void install(@NonNull UninstalledBinding<?> binding) {
this.injector.installBinding(binding);
}

@Override
public void install(@NonNull DynamicBinding binding) {
this.injector.installBinding(binding);
}

/**
Expand All @@ -101,7 +120,15 @@ public void install(@NonNull BindingConstructor constructor) {
@Override
public void installAutoConfigureBindings(@NonNull ClassLoader loader, @NonNull String component) {
var fileName = String.format(AUTO_CONFIGURE_FILE_NAME_FORMAT, component);
this.autoRegistry.installBindings(loader, fileName, this.injector);
try (var stream = loader.getResourceAsStream(fileName)) {
if (stream != null) {
this.autoModule.deserializeBindings(stream, loader).installBindings(this.injector);
}
} catch (IOException exception) {
throw new UncheckedIOException(
String.format("Unable to auto configure bindings for component %s with file %s", component, fileName),
exception);
}
}

/**
Expand All @@ -127,9 +154,7 @@ public void installAutoConfigureBindings(@NonNull ClassLoader loader, @NonNull S
@Override
public void close() {
// remove the bindings from the parent injector if needed
if (this.injector instanceof SpecifiedInjector specifiedInjector) {
specifiedInjector.removeConstructedBindings();
}
this.injector.close();

// remove this injector from the registry
InjectionLayerProvider.REGISTRY.unregisterLayer(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,9 @@
package eu.cloudnetservice.driver.inject;

import com.google.common.base.Preconditions;
import dev.derklaro.aerogel.AerogelException;
import dev.derklaro.aerogel.Element;
import dev.derklaro.aerogel.binding.BindingBuilder;
import dev.derklaro.aerogel.binding.BindingConstructor;
import dev.derklaro.aerogel.internal.util.ElementHelper;
import dev.derklaro.aerogel.binding.key.BindingKey;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Objects;
import lombok.NonNull;
import org.jetbrains.annotations.ApiStatus;

Expand All @@ -38,7 +32,7 @@
public final class InjectUtil {

private static final Object[] EMPTY_INSTANCE_ARRAY = new Object[0];
private static final Element[] EMPTY_ELEMENT_ARRAY = new Element[0];
private static final BindingKey<?>[] EMPTY_ELEMENT_ARRAY = new BindingKey[0];

private InjectUtil() {
throw new UnsupportedOperationException();
Expand All @@ -51,7 +45,7 @@ private InjectUtil() {
* @return an array of element each representing a given parameter, in order.
* @throws NullPointerException if the given parameter array is null.
*/
public static @NonNull Element[] buildElementsForParameters(@NonNull Parameter[] parameters) {
public static @NonNull BindingKey<?>[] buildElementsForParameters(@NonNull Parameter[] parameters) {
return buildElementsForParameters(parameters, 0);
}

Expand All @@ -63,90 +57,69 @@ private InjectUtil() {
* @return an array of element each representing a given parameter, in order.
* @throws NullPointerException if the given parameter array is null.
*/
public static @NonNull Element[] buildElementsForParameters(@NonNull Parameter[] parameters, int offset) {
public static @NonNull BindingKey<?>[] buildElementsForParameters(@NonNull Parameter[] parameters, int offset) {
// return an empty element array if the given parameters are empty
if (parameters.length <= offset) {
return EMPTY_ELEMENT_ARRAY;
}

// construct the element array
var params = Arrays.copyOfRange(parameters, offset, parameters.length);
var elements = new Element[params.length];
var elements = new BindingKey[params.length];
for (int i = 0; i < params.length; i++) {
var parameter = params[i];
elements[i] = ElementHelper.buildElement(parameter, parameter.getDeclaredAnnotations());
elements[i] = BindingKey.of(parameter.getParameterizedType()).selectQualifier(parameter.getAnnotations());
}
return elements;
}

/**
* Finds all instances that are requested by the given element array in the given injection layer.
*
* @param layer the layer to retrieve the needed instances from.
* @param elements the elements to get the instances of.
* @param layer the layer to retrieve the needed instances from.
* @param keys the keys to get the instances of.
* @return the instances represented by the given elements, in order.
* @throws NullPointerException if the given injection layer or elements array is null.
* @throws AerogelException if an exception occurs while constructing a requested instance.
*/
public static @NonNull Object[] findAllInstances(@NonNull InjectionLayer<?> layer, @NonNull Element[] elements) {
return findAllInstances(layer, elements, 0);
public static @NonNull Object[] findAllInstances(
@NonNull InjectionLayer<?> layer,
@NonNull BindingKey<?>[] keys
) {
return findAllInstances(layer, keys, 0);
}

/**
* Finds all instances that are requested by the given element array in the given injection layer.
*
* @param layer the layer to retrieve the needed instances from.
* @param elements the elements to get the instances of.
* @param offset the offset to start writing the elements from in the resulting array, must be bigger than zero.
* @param layer the layer to retrieve the needed instances from.
* @param keys the keys to get the instances of.
* @param offset the offset to start writing the elements from in the resulting array, must be bigger than zero.
* @return the instances represented by the given elements, in order.
* @throws NullPointerException if the given injection layer or elements array is null.
* @throws IllegalArgumentException if the given offset is smaller than zero.
* @throws AerogelException if an exception occurs while constructing a requested instance.
*/
public static @NonNull Object[] findAllInstances(
@NonNull InjectionLayer<?> layer,
@NonNull Element[] elements,
@NonNull BindingKey<?>[] keys,
int offset
) {
Preconditions.checkArgument(offset >= 0, "offset must be >= 0");

// return an empty array if the offset is 0 and no elements are present
if (elements.length == 0 && offset == 0) {
if (keys.length == 0 && offset == 0) {
return EMPTY_INSTANCE_ARRAY;
}

// return an array of the expected size if an offset is present but no elements are present
if (elements.length == 0) {
if (keys.length == 0) {
return new Object[offset];
}

// find the instances
var instances = new Object[elements.length + offset];
for (int i = 0; i < elements.length; i++) {
instances[i + offset] = layer.instance(elements[i]);
var instances = new Object[keys.length + offset];
for (int i = 0; i < keys.length; i++) {
instances[i + offset] = layer.instance(keys[i]);
}
return instances;
}

/**
* Creates a fixed binding constructor without setting any required name or annotation. It is only based on the type.
*
* @param value the value that is bound to the type.
* @param types the types to bind the given value to.
* @return the new binding constructor.
* @throws NullPointerException if the given type or value is null.
* @throws IndexOutOfBoundsException if the given type array is empty.
*/
public static @NonNull BindingConstructor createFixedBinding(@NonNull Object value, @NonNull Type... types) {
Objects.checkIndex(0, types.length);

// extract the root binding type
if (types.length == 1) {
// only one type given, no need for further checks
return BindingBuilder.create().bindFully(types[0]).toInstance(value);
} else {
// bind all given types fully
return BindingBuilder.create().bindAllFully(types).toInstance(value);
}
}
}
Loading
Loading