Skip to content

Commit

Permalink
allowed multiple context factories
Browse files Browse the repository at this point in the history
  • Loading branch information
Mqzn committed Oct 4, 2024
1 parent e1ef412 commit 7e97c95
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 62 deletions.
20 changes: 17 additions & 3 deletions core/src/main/java/dev/velix/imperat/ResolverRegistrar.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.velix.imperat;

import dev.velix.imperat.annotations.base.element.ParameterElement;
import dev.velix.imperat.command.ContextResolverFactory;
import dev.velix.imperat.command.parameters.CommandParameter;
import dev.velix.imperat.context.Source;
Expand Down Expand Up @@ -27,7 +28,7 @@ public sealed interface ResolverRegistrar<S extends Source> permits Imperat {
*
* @param factory the factory to register
*/
void registerContextResolverFactory(ContextResolverFactory<S> factory);
void registerContextResolverFactory(Type type, ContextResolverFactory<S> factory);

/**
* Checks whether the type has
Expand All @@ -40,10 +41,12 @@ public sealed interface ResolverRegistrar<S extends Source> permits Imperat {
boolean hasContextResolver(Type type);

/**
* @param resolvingContextType the type the factory is registered to
* @return returns the factory for creation of
* {@link ContextResolver}
*/
ContextResolverFactory<S> getContextResolverFactory();
@Nullable
ContextResolverFactory<S> getContextResolverFactory(Type resolvingContextType);

/**
* Fetches {@link ContextResolver} for a certain type
Expand All @@ -52,8 +55,19 @@ public sealed interface ResolverRegistrar<S extends Source> permits Imperat {
* @param <T> the type of class
* @return the context resolver
*/
@Nullable
<T> ContextResolver<S, T> getContextResolver(Type resolvingContextType);


/**
* Fetches the context resolver for {@link ParameterElement} of a method
*
* @param element the element
* @param <T> the type of value this parameter should be resolved into
* @return the {@link ContextResolver} for this element
*/
@Nullable
<T> ContextResolver<S, T> getMethodParamContextResolver(@NotNull ParameterElement element);

/**
* Fetches the {@link ContextResolver} suitable for the {@link CommandParameter}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,10 @@ public static <S extends Source> Object[] loadParameterInstances(

for (int i = 1, p = 0; i < method.size(); i++, p++) {
ParameterElement actualParameter = method.getParameterAt(i);

var factory = dispatcher.getContextResolverFactory();
var contextResolver = factory.create(actualParameter);

if (contextResolver != null) {
paramsInstances[i] = contextResolver.resolve(context, actualParameter);
p--;
continue;
}


assert actualParameter != null;
contextResolver = dispatcher.getContextResolver(actualParameter.getType());
var contextResolver = dispatcher.getMethodParamContextResolver(actualParameter);

if (contextResolver != null) {
paramsInstances[i] = contextResolver.resolve(context, actualParameter);
p--;
Expand Down
29 changes: 21 additions & 8 deletions core/src/main/java/dev/velix/imperat/command/BaseImperat.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import dev.velix.imperat.annotations.base.AnnotationParser;
import dev.velix.imperat.annotations.base.AnnotationReader;
import dev.velix.imperat.annotations.base.AnnotationReplacer;
import dev.velix.imperat.annotations.base.element.ParameterElement;
import dev.velix.imperat.command.parameters.CommandParameter;
import dev.velix.imperat.command.processors.CommandPostProcessor;
import dev.velix.imperat.command.processors.CommandPreProcessor;
Expand Down Expand Up @@ -49,8 +50,8 @@ public abstract class BaseImperat<S extends Source> implements Imperat<S> {

private final Map<String, Command<S>> commands = new HashMap<>();
private final Map<Class<? extends Throwable>, ThrowableResolver<?, S>> handlers = new HashMap<>();

private final Queue<CommandPreProcessor<S>> globalPreProcessors ;
private final Queue<CommandPreProcessor<S>> globalPreProcessors;
private final Queue<CommandPostProcessor<S>> globalPostProcessors;

protected BaseImperat(@NotNull PermissionResolver<S> permissionResolver) {
Expand Down Expand Up @@ -340,17 +341,17 @@ public boolean hasContextResolver(Type type) {
* @param factory the factory to register
*/
@Override
public void registerContextResolverFactory(ContextResolverFactory<S> factory) {
contextResolverRegistry.setFactory(factory);
public void registerContextResolverFactory(Type type, ContextResolverFactory<S> factory) {
contextResolverRegistry.registerFactory(type, factory);
}

/**
* @return returns the factory for creation of
* {@link ContextResolver}
*/
@Override
public ContextResolverFactory<S> getContextResolverFactory() {
return contextResolverRegistry.getFactory();
public @Nullable ContextResolverFactory<S> getContextResolverFactory(Type type) {
return contextResolverRegistry.getFactoryFor(type).orElse(null);
}

/**
Expand All @@ -361,9 +362,21 @@ public ContextResolverFactory<S> getContextResolverFactory() {
*/
@Override
public <T> @Nullable ContextResolver<S, T> getContextResolver(Type resolvingContextType) {
return contextResolverRegistry.getResolver(resolvingContextType);
return contextResolverRegistry.getResolverWithoutParameterElement(resolvingContextType);
}


/**
* Fetches the context resolver for {@link ParameterElement} of a method
*
* @param element the element
* @return the {@link ContextResolver} for this element
*/
@Override
public <T> @Nullable ContextResolver<S, T> getMethodParamContextResolver(@NotNull ParameterElement element) {
Preconditions.notNull(element, "element");
return contextResolverRegistry.getContextResolver(element.getType(), element);
}

/**
* Registers {@link ContextResolver}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import dev.velix.imperat.annotations.base.element.ParameterElement;
import dev.velix.imperat.context.Source;
import dev.velix.imperat.resolvers.ContextResolver;
import dev.velix.imperat.util.TypeUtility;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Type;

/**
* Represents a context resolver factory
* that is responsible for creating {@link ContextResolver}
Expand All @@ -15,21 +15,13 @@
*/
public interface ContextResolverFactory<S extends Source> {


static <S extends Source, T> @NotNull ContextResolverFactory<S> of(
Class<T> clazz,
ContextResolver<S, T> resolver
) {
return (p) -> p != null && TypeUtility.areRelatedTypes(clazz, p.getType()) ? resolver : null;
}

/**
* Creates a context resolver based on the parameter
*
* @param parameter the parameter (null if used classic way)
* @return the {@link ContextResolver} specific for that parameter
*/
@Nullable
ContextResolver<S, ?> create(@Nullable ParameterElement parameter);
<T> ContextResolver<S, T> create(Type type, @Nullable ParameterElement parameter);

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.velix.imperat.command;

import dev.velix.imperat.Imperat;
import dev.velix.imperat.annotations.base.element.ParameterElement;
import dev.velix.imperat.context.Source;
import dev.velix.imperat.help.CommandHelp;
import dev.velix.imperat.resolvers.ContextResolver;
Expand All @@ -11,18 +12,15 @@
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Type;
import java.util.Optional;

@ApiStatus.AvailableSince("1.0.0")
final class ContextResolverRegistry<S extends Source> extends Registry<Type, ContextResolver<S, ?>> {

private ContextResolverFactory<S> factory;
final class ContextResolverRegistry<S extends Source> extends Registry<Type, ContextResolver<S, ?>> implements ContextResolverFactory<S> {
private final Registry<Type, ContextResolverFactory<S>> factories = new Registry<>();

private ContextResolverRegistry(final Imperat<S> imperat) {
super();
factory = (parameter -> {
assert parameter != null;
return getResolver(parameter.getType());
});
this.registerResolver(TypeWrap.of(CommandHelp.class).getType(), (ctx, param) -> new CommandHelp(imperat, ctx));
}

Expand All @@ -33,26 +31,46 @@ public static <S extends Source> ContextResolverRegistry<S> createDefault(final
public <T> void registerResolver(Type type, ContextResolver<S, T> resolver) {
setData(type, resolver);
}



public void registerFactory(Type type, ContextResolverFactory<S> factory) {
factories.setData(type, factory);
}

public Optional<ContextResolverFactory<S>> getFactoryFor(Type type) {
return factories.getData(type);
}

@SuppressWarnings("unchecked")
public <T> @Nullable ContextResolver<S, T> getResolver(Type type) {
return (ContextResolver<S, T>) getData(type).orElseGet(() -> {
<T> @Nullable ContextResolver<S, T> getContextResolver(Type type, @Nullable ParameterElement element) {
//we search for factories mainly
return (ContextResolver<S, T>) getFactoryFor(type)
.flatMap((factory) -> Optional.ofNullable(factory.create(type, element)))
.orElseGet(() -> this.create(type, element));
}

public <T> @Nullable ContextResolver<S, T> getResolverWithoutParameterElement(Type type) {
//
ContextResolver<S, T> resultFromFactory = getContextResolver(type, null);
if (resultFromFactory == null) {
for (var registeredType : getKeys()) {
if (TypeUtility.areRelatedTypes(type, registeredType)) {
return getData(registeredType).orElse(null);
return getResolverWithoutParameterElement(registeredType);
}
}
return null;
});
}
return resultFromFactory;
}

public ContextResolverFactory<S> getFactory() {
return factory;
}

public void setFactory(ContextResolverFactory<S> factory) {
this.factory = factory;

/**
* Creates a context resolver based on the parameter
*
* @param parameter the parameter (null if used classic way)
* @return the {@link ContextResolver} specific for that parameter
*/
@Override
@SuppressWarnings("unchecked")
public @Nullable <T> ContextResolver<S, T> create(Type type, @Nullable ParameterElement parameter) {
return (ContextResolver<S, T>) getData(type).orElse(null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,8 @@ public Collection<? extends ResolvedArgument<S>> getResolvedArguments() {
@Override
@SuppressWarnings("unchecked")
public <T> @Nullable T getContextResolvedArgument(Class<T> type) throws ImperatException {
var factory = dispatcher.getContextResolverFactory();
if (factory == null) {
var cr = dispatcher.getContextResolver(type);
if (cr == null) return null;
return (T) cr.resolve(this, null);
}
ContextResolver<S, T> factoryCr = (ContextResolver<S, T>) factory.create(null);
return factoryCr == null ? null : factoryCr.resolve(this, null);
var resolver = dispatcher.getContextResolver(type);
return resolver == null ? null : (T) resolver.resolve(this, null);
}

/**
Expand Down

0 comments on commit 7e97c95

Please sign in to comment.