Class BaseCommandProcessor

java.lang.Object
javax.annotation.processing.AbstractProcessor
io.github.projectunified.craftcommand.processor.BaseCommandProcessor
All Implemented Interfaces:
Processor
Direct Known Subclasses:
BukkitCommandProcessor, PaperCommandProcessor, StandaloneCommandProcessor

public abstract class BaseCommandProcessor extends AbstractProcessor
Re-structured, highly readable base class for command annotation processors. Supports custom validation annotations, parameter resolvers, deep subcommand nesting, and compiler extensions via SPI.
  • Field Details

  • Constructor Details

    • BaseCommandProcessor

      public BaseCommandProcessor()
  • Method Details

    • getSimpleName

      public static String getSimpleName(com.palantir.javapoet.TypeName typeName)
      Utility method to get the simple name of a type.
      Parameters:
      typeName - the full type name
      Returns:
      the simple type name
    • getSubcommandNames

      protected static String getSubcommandNames(CommandModel model)
      Utility method to format a list of all subcommand names defined in a command model.
      Parameters:
      model - the command model
      Returns:
      a formatted string of subcommand names
    • getUsage

      protected static String getUsage(MethodModel method, CommandModel classModel)
      Utility method to build the command usage syntax string for a command method, with support for flattening @Resolve resolver params.
      Parameters:
      method - the method model
      classModel - the command model (for resolver lookup), or null to skip flattening
      Returns:
      the usage string
    • findAnnotationUp

      protected static <A extends Annotation> A findAnnotationUp(Element element, Class<A> annotationType)
      Walks up the enclosing element hierarchy to find the first annotation of the given type on the element or any of its enclosing elements.
      Parameters:
      element - the starting element
      annotationType - the annotation class to search for
      Returns:
      the annotation instance, or null if not found
    • isI18nKey

      protected static boolean isI18nKey(String message)
      Returns true if the message uses the i18n: prefix for runtime lookup.
    • i18nKey

      protected static String i18nKey(String message)
      Extracts the i18n key from a message. Assumes isI18nKey(String) is true.
    • getDefaultPrimitiveValue

      public String getDefaultPrimitiveValue(TypeMirror type)
      Gets the default literal value expression for a primitive (or wrapper) type. Delegates to TypeSupport; returns "null" for non-primitives.
      Parameters:
      type - the type mirror
      Returns:
      the default value literal string
    • init

      public void init(ProcessingEnvironment processingEnv)
      Specified by:
      init in interface Processor
      Overrides:
      init in class AbstractProcessor
    • registerTypes

      protected void registerTypes(TypeSupport types)
      Override this method to register platform-specific types into TypeSupport. Called during init(javax.annotation.processing.ProcessingEnvironment) after SPI extensions are loaded.

      Example (Bukkit):

      
       @Override
       protected void registerTypes(TypeSupport types) {
           types.register(TypeSupport.Entry.builder(playerClass, 1)
               .primitiveDefault("null")
               .literal(d -> CodeBlock.of("null"))
               .platformResolution((spec, p) -> spec.addStatement("$L = getPlayer($L)", p[0], p[1]))
               .platformSuggestions((spec, p) -> spec.addStatement("return suggestPlayers($L)", p[2]))
               .build());
       }
       
      Parameters:
      types - the type support registry to populate
    • getWrapperClassSuffix

      protected abstract String getWrapperClassSuffix()
      Returns the wrapper class suffix specific to the platform.
      Returns:
      the class name suffix (e.g. "$BukkitCommand" or "$StandaloneCommand")
    • getSenderTypeName

      protected abstract com.palantir.javapoet.ClassName getSenderTypeName()
      Returns the platform-specific command sender type name.
    • getManagerType

      protected abstract com.palantir.javapoet.TypeName getManagerType()
      Returns the platform-specific command manager type.
    • anchorConfigureType

      protected void anchorConfigureType(com.palantir.javapoet.TypeSpec.Builder typeSpec)
      Phase 1: Configure the class declaration (superclass, interfaces).
    • anchorAdditionalFields

      protected void anchorAdditionalFields(com.palantir.javapoet.TypeSpec.Builder typeSpec, CommandModel model)
      Phase 2: Add additional fields after instance and manager.
    • anchorConstructorTop

      protected void anchorConstructorTop(com.palantir.javapoet.MethodSpec.Builder constructorBuilder, CommandModel model)
      Phase 3 (top): Add platform-specific constructor statements at the beginning. Called before this.instance/this.manager assignments.
    • anchorConstructorBottom

      protected void anchorConstructorBottom(com.palantir.javapoet.MethodSpec.Builder constructorBuilder, CommandModel model)
      Phase 3 (bottom): Add platform-specific constructor statements at the end. Called after nested subcommand instantiation.
    • anchorBuildEntryMethods

      protected void anchorBuildEntryMethods(com.palantir.javapoet.TypeSpec.Builder typeSpec, CommandModel model, TypeElement typeElement)
      Phase 4: Generate platform-specific entry methods (execute, tabComplete, getCommandNode, etc.).
    • anchorAdditionalHelpers

      protected void anchorAdditionalHelpers(com.palantir.javapoet.TypeSpec.Builder typeSpec, CommandModel model)
      Phase 5: Add additional helper methods. Default generates suggestBoolean and sender-cast helpers.
    • anchorExtraMethods

      protected void anchorExtraMethods(com.palantir.javapoet.TypeSpec.Builder typeSpec, CommandModel model)
      Phase 7: Add extra methods after CommandInfoExposer (Brigadier tree, etc.).
    • createExecutionSource

      protected ExecutionSource createExecutionSource(String argsVar, boolean hasDynamic, String argIdxVar)
    • onBeforeExecute

      protected void onBeforeExecute(com.palantir.javapoet.MethodSpec.Builder methodSpec, Element element, String returnStatement)
    • generateUnknownSubcommandMessage

      protected void generateUnknownSubcommandMessage(com.palantir.javapoet.MethodSpec.Builder methodSpec, CommandModel model)
    • isSenderType

      public boolean isSenderType(com.palantir.javapoet.TypeName typeName)
      Checks if the sender type is supported
    • isSenderBaseType

      public boolean isSenderBaseType(com.palantir.javapoet.TypeName typeName)
    • isSenderParam

      public boolean isSenderParam(com.palantir.javapoet.TypeName typeName, MethodModel method)
      Checks if a type is any sender tier: command's sender type, base sender type, or platform sender type. When method is null, skips the command's sender type check.
    • senderTypeRegistry

      protected SenderTypeRegistry senderTypeRegistry()
      Returns:
      the sender type registry for platform processors to register sender types
    • process

      public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
      /** Main entry point for the compiler annotation processing round. Searches for types annotated with @Command, parses their structure, and generates the wrappers.
      Specified by:
      process in interface Processor
      Specified by:
      process in class AbstractProcessor
    • buildWrapperClass

      protected void buildWrapperClass(CommandModel model, TypeElement typeElement) throws IOException
      Generates the wrapper class using the template flow with anchor injection points.
      Throws:
      IOException
    • generateFieldsAndConstructorStatements

      protected void generateFieldsAndConstructorStatements(CommandModel model, com.palantir.javapoet.TypeSpec.Builder typeSpec, com.palantir.javapoet.MethodSpec.Builder constructor, String parentFieldName)
    • buildAliasesExpression

      protected com.palantir.javapoet.CodeBlock buildAliasesExpression(CommandModel model)
    • generateExecuteMethodBody

      protected void generateExecuteMethodBody(com.palantir.javapoet.MethodSpec.Builder executeSpec, CommandModel model, String returnStatement)
    • getSubcommandFieldName

      protected String getSubcommandFieldName(CommandModel child)
    • getInstanceVarExpression

      public String getInstanceVarExpression(CommandModel classModel, CommandModel rootModel)
    • getResolverInstanceExpr

      public String getResolverInstanceExpr(ExecutableElement resolver, CommandModel classModel, CommandModel rootModel)
      Returns the instance expression for calling a resolver method. When the resolver is on an outer class (not in the command tree), returns null to indicate the resolver cannot be called from this wrapper.
    • getParameterSuggestionMethodName

      protected String getParameterSuggestionMethodName(CommandModel classModel, MethodModel method, int index)
    • generateSubcommandClassExecutors

      protected void generateSubcommandClassExecutors(com.palantir.javapoet.TypeSpec.Builder typeSpec, CommandModel model, CommandModel rootModel)
    • buildExecutionRouting

      protected void buildExecutionRouting(com.palantir.javapoet.MethodSpec.Builder methodSpec, CommandModel model, String argsVar, String instanceVar, CommandModel rootModel, String returnStatement)
    • getLocalResolverMinWidth

      protected int getLocalResolverMinWidth(ExecutableElement resolverMethod, MethodModel commandMethod)
    • getLocalResolverMaxWidth

      protected int getLocalResolverMaxWidth(ExecutableElement resolverMethod, MethodModel commandMethod)
    • firstParamIsSender

      public boolean firstParamIsSender(ExecutableElement method)
    • firstParamIsSender

      public boolean firstParamIsSender(ExecutableElement resolverMethod, MethodModel commandMethod)
      Checks if the first parameter of a method is a sender parameter, considering the command method's sender type.
    • generateResolveSingleArgument

      protected void generateResolveSingleArgument(com.palantir.javapoet.MethodSpec.Builder methodSpec, TypeMirror type, String varName, String argStrVar, String senderVar, String argsVar)
    • generateAssignDefaultValue

      protected void generateAssignDefaultValue(com.palantir.javapoet.MethodSpec.Builder methodSpec, TypeMirror type, String varName, String defaultValue, String senderVarName)
    • getAssignmentValueForType

      public com.palantir.javapoet.CodeBlock getAssignmentValueForType(com.palantir.javapoet.TypeName typeName, String defaultValue)
    • buildMethodExecution

      protected void buildMethodExecution(com.palantir.javapoet.MethodSpec.Builder methodSpec, CommandModel classModel, MethodModel method, String argsVar, String instanceVar, CommandModel rootModel)
    • buildMethodExecution

      protected void buildMethodExecution(com.palantir.javapoet.MethodSpec.Builder methodSpec, CommandModel classModel, MethodModel method, String instanceVar, CommandModel rootModel, ExecutionSource source)
    • buildSenderResolution

      public void buildSenderResolution(com.palantir.javapoet.MethodSpec.Builder methodSpec, CommandModel classModel, MethodModel method, CommandModel rootModel, String senderVarName, ParameterModel senderParam, com.palantir.javapoet.TypeName senderParamTypeName)
    • buildLocalResolverParameter

      protected void buildLocalResolverParameter(com.palantir.javapoet.MethodSpec.Builder methodSpec, CommandModel classModel, MethodModel method, ParameterModel p, com.palantir.javapoet.TypeName pTypeName, String varName, ExecutableElement localResolver, CommandModel rootModel, String senderVarName, String argsVar, String argIdxVar, boolean hasDynamic, int i)
    • buildBuiltInParameter

      protected void buildBuiltInParameter(com.palantir.javapoet.MethodSpec.Builder methodSpec, ParameterModel p, com.palantir.javapoet.TypeName pTypeName, String varName, String argsVar, String argIdxVar, String senderVarName, boolean hasDynamic, int i)
    • buildSuggestionRouting

      protected void buildSuggestionRouting(com.palantir.javapoet.MethodSpec.Builder methodSpec, CommandModel model, String argsVar, String instanceVar, CommandModel rootModel)
    • buildSubcommandSuggestionRouting

      protected void buildSubcommandSuggestionRouting(com.palantir.javapoet.MethodSpec.Builder methodSpec, CommandModel classModel, MethodModel method, String argsVar)
    • buildParameterSuggestions

      protected void buildParameterSuggestions(com.palantir.javapoet.TypeSpec.Builder typeSpec, CommandModel model, CommandModel rootModel)
    • getResolverParamSuggestionMethodName

      protected String getResolverParamSuggestionMethodName(CommandModel classModel, MethodModel method, String resolverName, int index)
    • buildResolverParamSuggestionHelper

      protected com.palantir.javapoet.MethodSpec buildResolverParamSuggestionHelper(CommandModel classModel, MethodModel method, ParameterModel rp, String helperName, CommandModel rootModel)
    • buildParameterSuggestionHelper

      protected com.palantir.javapoet.MethodSpec buildParameterSuggestionHelper(CommandModel classModel, MethodModel method, ParameterModel p, int index, CommandModel rootModel)
    • findLocalResolver

      public ExecutableElement findLocalResolver(CommandModel classModel, ParameterModel p, CommandModel rootModel)
    • generateResolverInvocation

      public void generateResolverInvocation(com.palantir.javapoet.MethodSpec.Builder methodSpec, ExecutableElement localResolver, CommandModel classModel, CommandModel rootModel, com.palantir.javapoet.TypeName pTypeName, String varName, String senderVarName, List<String> resolverArgVarNames, boolean includeSender)
      Generates the common local resolver invocation code: null-check resolver instance, build method call with pre-resolved parameter variables, and assign the result.
      Parameters:
      methodSpec - the target method builder
      localResolver - the resolver method element
      classModel - the command class model
      rootModel - the root command model
      pTypeName - the target parameter type
      varName - the variable name to assign the result to
      senderVarName - the sender variable name
      resolverArgVarNames - pre-resolved resolver parameter variable names
    • generateResolverResolution

      public void generateResolverResolution(ExecutionSource executionSource, com.palantir.javapoet.MethodSpec.Builder methodSpec, CommandModel classModel, MethodModel method, CommandModel rootModel, MethodModel resolverModel, String varName, String senderVarName, ParameterModel parentParam, String rawSourceExpr)
      Unified resolver param resolution: resolves each non-sender param using the same code path, then invokes the resolver method. Supports @Default, @Greedy, @Name, @Suggest, @Resolve (nested), and validation annotations like @Min, @Max, @ValidateWith.
      Parameters:
      rawSourceExpr - the raw sender expression for the platform (e.g. "sender" or "ctx.getSource()")
    • runParameterAnnotationHandlers

      public void runParameterAnnotationHandlers(VariableElement param, String varName, String instanceExpr, String senderVar, com.palantir.javapoet.MethodSpec.Builder methodSpec)
      Runs all SPI parameter annotation handlers on a VariableElement. Used for both command method parameters and resolver method parameters.
    • findSuggestMethod

      protected ExecutableElement findSuggestMethod(TypeElement typeElement, String name)
    • isField

      protected boolean isField(TypeElement typeElement, String name)
    • findModelForClass

      public CommandModel findModelForClass(CommandModel current, TypeElement targetClass)
    • isBuiltInType

      public boolean isBuiltInType(com.palantir.javapoet.TypeName typeName)
    • findSuggestionProvider

      protected SuggestionProvider findSuggestionProvider(com.palantir.javapoet.TypeName typeName)
      Finds a global suggestion provider for the given type via SPI.
    • getBuiltInWidth

      protected int getBuiltInWidth(com.palantir.javapoet.TypeName typeName)
    • isPlatformBuiltInType

      protected boolean isPlatformBuiltInType(com.palantir.javapoet.TypeName typeName)
    • resolveParameterForType

      public void resolveParameterForType(com.palantir.javapoet.MethodSpec.Builder methodSpec, com.palantir.javapoet.TypeName typeName, String varName, String argStrVar)
    • getSenderExpression

      protected com.palantir.javapoet.CodeBlock getSenderExpression(String senderVar)
      Returns the sender expression for instanceof checks and general usage. Paper: sender.getSender() (extracts CommandSender from CommandSourceStack). Base: sender (already the correct type).
    • isStringArray

      protected boolean isStringArray(TypeMirror type)
      Checks if a TypeMirror is String[].
    • getResolverSenderExpression

      public String getResolverSenderExpression(ExecutableElement localResolver, String rawSourceExpr, String castSenderVar, com.palantir.javapoet.TypeName commandSenderType)
      Returns the sender expression to pass to a resolver method. Command's sender type → castSenderVar, base type → rawSourceExpr, platform sender → cast helper, else → castSenderVar.
    • buildAdditionalHelpers

      protected void buildAdditionalHelpers(com.palantir.javapoet.TypeSpec.Builder typeSpec, CommandModel model)
      Generates additional platform-independent helper methods (like suggestBoolean and sender casting helpers).