Skip to content

Commit

Permalink
development. (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
portlek authored Sep 30, 2024
1 parent 40275cf commit d513633
Show file tree
Hide file tree
Showing 405 changed files with 17,683 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
key: "${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}"
restore-keys: |
${{ runner.os }}-gradle-
- run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
key: "${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}"
restore-keys: |
${{ runner.os }}-gradle-
- run: |
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ repositories {
}
dependencies {
// Base module
// Base modules
implementation "net.infumia:frame:VERSION"
implementation "net.infumia:frame-core:VERSION"
}
```
### Code
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package net.infumia.frame.annotation;

import io.leangen.geantyref.TypeToken;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import net.infumia.frame.annotation.exception.AnnotatedMethodHandlerInitiationException;
import net.infumia.frame.api.injection.InjectionRequester;
import net.infumia.frame.api.util.Preconditions;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Abstract class that handles annotated methods for dependency injection.
*
* @param <C> the type of context used for method invocation.
*/
public abstract class AnnotatedMethodHandler<C> {

/**
* Parameters of the method being handled.
*/
@NotNull
protected final List<Parameter> parameters;

/**
* MethodHandle for invoking the method.
*/
@NotNull
protected final MethodHandle methodHandle;

/**
* Accessor for retrieving annotations from the method.
*/
@NotNull
protected final AnnotationAccessor annotationAccessor;

/**
* Injector for managing dependencies.
*/
@NotNull
protected final InjectionRequester<C> injector;

/**
* Ctor.
*
* @param method the method to be handled.
* @param instance the instance on which the method will be invoked.
* @param injector the injector used to provide dependencies.
* @throws AnnotatedMethodHandlerInitiationException if the method cannot be accessed or unreflect.
*/
protected AnnotatedMethodHandler(
@NotNull final Method method,
@NotNull final Object instance,
@NotNull final InjectionRequester<C> injector
) {
try {
this.parameters = Arrays.asList(method.getParameters());
if (!method.isAccessible()) {
method.setAccessible(true);
}
this.methodHandle = MethodHandles.lookup().unreflect(method).bindTo(instance);
this.annotationAccessor = AnnotationAccessor.of(method);
this.injector = injector;
} catch (final Exception exception) {
throw new AnnotatedMethodHandlerInitiationException(exception);
}
}

/**
* Retrieves the value for a specific parameter in the given context.
* <p>
* Returning {@code null} skip the contextual parameters values, instead {@link #injector} will be used.
*
* @param context the context in which the method is being invoked.
* @param parameter the parameter whose value is to be retrieved.
* @return the value of the parameter.
*/
@Nullable
@ApiStatus.OverrideOnly
protected ParameterValue getParameterValue(
@NotNull final C context,
@NotNull final Parameter parameter
) {
return null;
}

/**
* Creates a list of parameter values based on the current context.
*
* @param context the context in which the method is being invoked.
* @return an unmodifiable list of parameter values.
*/
@NotNull
@SuppressWarnings("unchecked")
protected CompletableFuture<Collection<ParameterValue>> createParameterValues(
@NotNull final C context
) {
final CompletableFuture<@Nullable ParameterValue>[] futures =
this.parameters.stream()
.map(parameter -> this.createParameterValue(context, parameter))
.toArray(CompletableFuture[]::new);

return CompletableFuture.allOf(futures).thenApply(__ ->
Arrays.stream(futures)
.map(CompletableFuture::join)
.collect(
Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)
)
);
}

@NotNull
private CompletableFuture<@Nullable ParameterValue> createParameterValue(
@NotNull final C context,
@NotNull final Parameter parameter
) {
final ParameterValue contextualValue = this.getParameterValue(context, parameter);
if (contextualValue != null) {
return CompletableFuture.completedFuture(contextualValue);
}
return this.requestParameterValue(parameter, context);
}

@NotNull
private CompletableFuture<ParameterValue> requestParameterValue(
@NotNull final Parameter parameter,
@NotNull final C context
) {
return this.requestInjection(parameter, context).thenApply(value -> {
Preconditions.argumentNotNull(
value,
"Could not create value for parameter '%s' of type '%s' in method '%s'",
parameter.getName(),
parameter.getType().getTypeName(),
this.methodHandle
);
if (parameter.getType() == String.class) {
return ParameterValue.of(parameter, parameter.getName());
}
return ParameterValue.of(parameter, value);
});
}

@NotNull
@SuppressWarnings("unchecked")
private CompletableFuture<@Nullable Object> requestInjection(
@NotNull final Parameter parameter,
@NotNull final C context
) {
return this.injector.request(
(TypeToken<Object>) TypeToken.get(parameter.getParameterizedType()),
context,
AnnotationAccessor.of(AnnotationAccessor.of(parameter), this.annotationAccessor)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.infumia.frame.annotation;

import org.jetbrains.annotations.NotNull;

/**
* Represents a descriptor for a parameter.
*/
public interface ParameterDescriptor {
/**
* Retrieves the name of the parameter.
*
* @return the name of the parameter.
*/
@NotNull
String name();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package net.infumia.frame.annotation;

import java.lang.reflect.Parameter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Represents a value associated with a parameter.
*/
public interface ParameterValue {
/**
* Creates a new instance of {@link ParameterValue} with the specified parameter and value.
*
* @param parameter the parameter associated with this value.
* @param value the value associated with the parameter.
* @return a new {@link ParameterValue} instance.
*/
@NotNull
static ParameterValue of(@NotNull final Parameter parameter, @Nullable final Object value) {
return new ParameterValueImpl(parameter, value);
}

/**
* Creates a new instance of {@link ParameterValue} with the specified parameter, value, and descriptor.
*
* @param parameter the parameter associated with this value.
* @param value the value associated with the parameter.
* @param descriptor an optional descriptor for the parameter.
* @return a new {@link ParameterValue} instance.
*/
@NotNull
static ParameterValue of(
@NotNull final Parameter parameter,
@Nullable final Object value,
@Nullable final ParameterDescriptor descriptor
) {
return new ParameterValueImpl(parameter, value, descriptor);
}

/**
* Returns the parameter associated with this value.
*
* @return the parameter.
*/
@NotNull
Parameter parameter();

/**
* Returns the value associated with the parameter.
*
* @return the value.
*/
@Nullable
Object value();

/**
* Returns the descriptor for the parameter.
*
* @return the descriptor.
*/
@Nullable
ParameterDescriptor descriptor();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package net.infumia.frame.annotation;

import java.lang.reflect.Parameter;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@Getter
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
final class ParameterValueImpl implements ParameterValue {

@NotNull
private final Parameter parameter;

@Nullable
private final Object value;

@Nullable
private final ParameterDescriptor descriptor;

public ParameterValueImpl(@NotNull final Parameter parameter, @Nullable final Object value) {
this(parameter, value, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.infumia.frame.annotation.config;

import net.infumia.frame.api.context.ContextBase;
import org.jetbrains.annotations.NotNull;

public interface ConfigKeyProvider {
@NotNull
String provideConfigKey(@NotNull ContextBase ctx);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package net.infumia.frame.annotation.config;

import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public interface ConfigValueProvider {
@Nullable
Object getRaw(@NotNull String key);

@Nullable
Integer getInt(@NotNull String key);

@Nullable
String getString(@NotNull String key);

@Nullable
ItemStack getItem(@NotNull String key);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package net.infumia.frame.annotation.config;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ConfigValueProviderEmpty implements ConfigValueProvider {

public static final ConfigValueProvider INSTANCE = new ConfigValueProviderEmpty();

@Nullable
@Override
public Object getRaw(@NotNull final String key) {
return null;
}

@Nullable
@Override
public Integer getInt(@NotNull final String key) {
return null;
}

@Nullable
@Override
public String getString(@NotNull final String key) {
return null;
}

@Nullable
@Override
public ItemStack getItem(@NotNull final String key) {
return null;
}
}
Loading

0 comments on commit d513633

Please sign in to comment.