target();
57 |
58 | /**
59 | * Injects the members of a class in the given instance. If the instance of a class is created by an injector, this
60 | * process is executed automatically. Therefore, if all class instances are created automatically, there is no need to
61 | * call this method manually.
62 | *
63 | * If the given instance is null, only static members will be injected in the target class, unless they were already
64 | * injected once by a different injector.
65 | *
66 | * Member injection follows these ordering rules:
67 | *
68 | * - supertype members are injected before subtype members.
69 | *
- static members are injected before instance members.
70 | *
- fields are injected before methods.
71 | *
- fields with the same modifier are sorted by name.
72 | *
- methods with the same modifier are sorted by {@link Order} or name for methods with the same ordering.
73 | *
74 | *
75 | * @param instance the instance to inject members in.
76 | */
77 | void injectMembers(@Nullable T instance);
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/dev/derklaro/aerogel/internal/binding/InstalledBindingImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of aerogel, licensed under the MIT License (MIT).
3 | *
4 | * Copyright (c) 2021-2025 Pasqual K. and contributors
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package dev.derklaro.aerogel.internal.binding;
26 |
27 | import dev.derklaro.aerogel.Injector;
28 | import dev.derklaro.aerogel.ScopeApplier;
29 | import dev.derklaro.aerogel.binding.BindingOptions;
30 | import dev.derklaro.aerogel.binding.InstalledBinding;
31 | import dev.derklaro.aerogel.binding.ProviderWithContext;
32 | import dev.derklaro.aerogel.binding.UninstalledBinding;
33 | import dev.derklaro.aerogel.binding.key.BindingKey;
34 | import java.util.List;
35 | import java.util.Optional;
36 | import org.jetbrains.annotations.NotNull;
37 | import org.jetbrains.annotations.Unmodifiable;
38 |
39 | final class InstalledBindingImpl implements InstalledBinding {
40 |
41 | private final Injector injector;
42 | private final UninstalledBinding source;
43 |
44 | private final ProviderWithContext providerWithContext;
45 |
46 | public InstalledBindingImpl(
47 | @NotNull Injector injector,
48 | @NotNull UninstalledBinding source,
49 | @NotNull ProviderWithContext providerWithContext
50 | ) {
51 | this.source = source;
52 | this.injector = injector;
53 | this.providerWithContext = providerWithContext;
54 | }
55 |
56 | @Override
57 | public @NotNull BindingKey extends T> mainKey() {
58 | return this.source.mainKey();
59 | }
60 |
61 | @Override
62 | public @NotNull @Unmodifiable List> keys() {
63 | return this.source.keys();
64 | }
65 |
66 | @Override
67 | public boolean supportsKey(@NotNull BindingKey> key) {
68 | return this.source.supportsKey(key);
69 | }
70 |
71 | @Override
72 | public @NotNull Injector installedInjector() {
73 | return this.injector;
74 | }
75 |
76 | @Override
77 | public @NotNull BindingOptions options() {
78 | return this.source.options();
79 | }
80 |
81 | @Override
82 | public @NotNull Optional scope() {
83 | return this.source.scope();
84 | }
85 |
86 | @Override
87 | public @NotNull ProviderWithContext providerWithContext() {
88 | return this.providerWithContext;
89 | }
90 |
91 | @Override
92 | public @NotNull UninstalledBinding asUninstalled() {
93 | return this.source;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/dev/derklaro/aerogel/InjectorBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of aerogel, licensed under the MIT License (MIT).
3 | *
4 | * Copyright (c) 2021-2025 Pasqual K. and contributors
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package dev.derklaro.aerogel;
26 |
27 | import dev.derklaro.aerogel.binding.key.BindingKey;
28 | import java.lang.invoke.MethodHandles;
29 | import java.util.function.Predicate;
30 | import org.apiguardian.api.API;
31 | import org.jetbrains.annotations.Contract;
32 | import org.jetbrains.annotations.NotNull;
33 |
34 | /**
35 | * A builder for an injector which allows to fine-tune an injector instance. A new builder instance can be obtained by
36 | * using {@link Injector#builder()}. Using {@code Injector.builder().build()} would create an injector instance
37 | * identical to {@link Injector#newInjector()}.
38 | *
39 | * @author Pasqual Koschmieder
40 | * @since 3.0
41 | */
42 | @API(status = API.Status.STABLE, since = "3.0")
43 | public interface InjectorBuilder {
44 |
45 | /**
46 | * Sets the member lookup that will be used to resolve reflective members of classes when needed (such as constructors
47 | * when resolving injection points and field/methods for member injection). If not explicitly set a default lookup
48 | * will be used instead.
49 | *
50 | * @param lookup the lookup instance to use for member lookups.
51 | * @return this builder, for chaining.
52 | */
53 | @NotNull
54 | @Contract("_ -> this")
55 | InjectorBuilder memberLookup(@NotNull MethodHandles.Lookup lookup);
56 |
57 | /**
58 | * Sets the filter for jit bindings to use. By default, a jit binding can be created for all binding keys. The given
59 | * filter will be called for every key for which a jit binding would be necessary. If the filter indicates that no jit
60 | * binding should be created for a key an exception is thrown during the injection process.
61 | *
62 | * @param filter the filter to use for jit bindings.
63 | * @return this builder, for chaining.
64 | */
65 | @NotNull
66 | @Contract("_ -> this")
67 | InjectorBuilder jitBindingFilter(@NotNull Predicate> filter);
68 |
69 | /**
70 | * Constructs a new injector instance based on the options provided to this builder.
71 | *
72 | * @return a new injector instance based on the options provided to this builder.
73 | */
74 | @NotNull
75 | @Contract(value = " -> new", pure = true)
76 | Injector build();
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/dev/derklaro/aerogel/binding/DynamicBinding.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of aerogel, licensed under the MIT License (MIT).
3 | *
4 | * Copyright (c) 2021-2025 Pasqual K. and contributors
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package dev.derklaro.aerogel.binding;
26 |
27 | import dev.derklaro.aerogel.binding.key.BindingKey;
28 | import java.util.Optional;
29 | import org.apiguardian.api.API;
30 | import org.jetbrains.annotations.NotNull;
31 |
32 | /**
33 | * A binding that can provide bindings for elements dynamically, for example based on annotation values. When a matching
34 | * request is made to a dynamic binding, the binding can decide if it can provide a binding for the requested element or
35 | * not. Return values are required to be predictable, therefore calling the {@link #tryMatch(BindingKey)} method with
36 | * the same binding key twice, should always return the same binding instance. Once a binding was resolved from a
37 | * dynamic binding, no subsequent dynamic bindings will be called, and the result will be stored as a fixed binding.
38 | *
39 | * @author Pasqual Koschmieder
40 | * @since 3.0
41 | */
42 | @API(status = API.Status.STABLE, since = "3.0")
43 | public interface DynamicBinding {
44 |
45 | /**
46 | * Get if this dynamic binding would support creating a binding instance for the given binding key. If this method
47 | * returns {@code true} for the given binding key, a subsequent call to {@link #tryMatch(BindingKey)} with the same
48 | * key MUST return a binding.
49 | *
50 | * @param key the key to check for support.
51 | * @return true if this binding supports the given key, false otherwise.
52 | */
53 | boolean supports(@NotNull BindingKey> key);
54 |
55 | /**
56 | * Tries to match this binding against the given binding key. If this binding matches the given key and want to
57 | * provide a binding for it, the method should return an optional containing an uninstalled binding to use for the
58 | * element. In case this binding can't provide an instance for the key, the method should return an empty optional.
59 | *
60 | * @param key the binding key of the element that gets injected.
61 | * @param the type of value handled by the binding.
62 | * @return an uninstalled binding if this binding matches, an empty optional otherwise.
63 | */
64 | @NotNull
65 | Optional> tryMatch(@NotNull BindingKey key);
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/dev/derklaro/aerogel/internal/context/scope/threadlocal/ThreadLocalInjectionContextScope.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of aerogel, licensed under the MIT License (MIT).
3 | *
4 | * Copyright (c) 2021-2025 Pasqual K. and contributors
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package dev.derklaro.aerogel.internal.context.scope.threadlocal;
26 |
27 | import dev.derklaro.aerogel.internal.context.InjectionContext;
28 | import dev.derklaro.aerogel.internal.context.scope.InjectionContextScope;
29 | import java.util.function.Supplier;
30 | import org.apiguardian.api.API;
31 | import org.jetbrains.annotations.NotNull;
32 | import org.jetbrains.annotations.UnknownNullability;
33 |
34 | /**
35 | * An injection context scope that uses thread-locals to set the context of the current scope.
36 | *
37 | * @author Pasqual K.
38 | * @since 3.0
39 | */
40 | @API(status = API.Status.INTERNAL, since = "3.0")
41 | final class ThreadLocalInjectionContextScope implements InjectionContextScope {
42 |
43 | private final InjectionContext context;
44 | private final ThreadLocal scopeThreadLocal;
45 |
46 | /**
47 | * Constructs a new thread local injection context scope.
48 | *
49 | * @param context the context that is wrapped in this scope.
50 | * @param scopeThreadLocal the thread local that is used by the context provider.
51 | */
52 | public ThreadLocalInjectionContextScope(
53 | @NotNull InjectionContext context,
54 | @NotNull ThreadLocal scopeThreadLocal
55 | ) {
56 | this.context = context;
57 | this.scopeThreadLocal = scopeThreadLocal;
58 | }
59 |
60 | /**
61 | * {@inheritDoc}
62 | */
63 | @Override
64 | public @NotNull InjectionContext context() {
65 | return this.context;
66 | }
67 |
68 | /**
69 | * {@inheritDoc}
70 | */
71 | @Override
72 | public @UnknownNullability T executeScoped(@NotNull Supplier operation) {
73 | InjectionContextScope currentScope = this.scopeThreadLocal.get();
74 | try {
75 | // update the thread local to use this scope, then call the given operation
76 | this.scopeThreadLocal.set(this);
77 | return operation.get();
78 | } finally {
79 | // reset to the previous scope if present, else remove the mapping to the current scope
80 | if (currentScope != null) {
81 | this.scopeThreadLocal.set(currentScope);
82 | } else {
83 | this.scopeThreadLocal.remove();
84 | }
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/dev/derklaro/aerogel/internal/util/MapUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of aerogel, licensed under the MIT License (MIT).
3 | *
4 | * Copyright (c) 2021-2025 Pasqual K. and contributors
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package dev.derklaro.aerogel.internal.util;
26 |
27 | import java.util.Collections;
28 | import java.util.HashMap;
29 | import java.util.Map;
30 | import java.util.concurrent.ConcurrentHashMap;
31 | import java.util.concurrent.ConcurrentMap;
32 | import java.util.function.Consumer;
33 | import org.apiguardian.api.API;
34 | import org.jetbrains.annotations.NotNull;
35 | import org.jetbrains.annotations.Unmodifiable;
36 |
37 | /**
38 | * A small utility to provide pre-configured map instances.
39 | *
40 | * @author Pasqual K.
41 | * @since 2.0
42 | */
43 | @API(status = API.Status.INTERNAL, since = "1.0")
44 | public final class MapUtil {
45 |
46 | private MapUtil() {
47 | throw new UnsupportedOperationException();
48 | }
49 |
50 | /**
51 | * Creates a new concurrent map instance with an initial capacity of 16, a load factor of 0.9 (to ensure dense
52 | * packaging which improves memory usage) and 1 shard (1 shard can handle multiple concurrent calls, there is no need
53 | * to create more shards).
54 | *
55 | * @param the type of keys which are stored in the map.
56 | * @param the type of values which are stored in the map.
57 | * @return a new concurrent map as described above.
58 | */
59 | public static @NotNull ConcurrentMap newConcurrentMap() {
60 | return new ConcurrentHashMap<>(16, 0.9f, 1);
61 | }
62 |
63 | /**
64 | * Constructs a new map with the given expected size, which prevents resizing. The created map is passed to the given
65 | * decorator and then wrapped to be unmodifiable.
66 | *
67 | * @param elementCount the expected size of the map.
68 | * @param decorator the decorator to put the needed entries into the map before it's made unmodifiable.
69 | * @param the type of keys which are stored in the map.
70 | * @param the type of values which are stored in the map.
71 | * @return an unmodifiable map with the added entries from the given decorator.
72 | */
73 | @Unmodifiable
74 | public static @NotNull Map staticMap(int elementCount, @NotNull Consumer