Skip to content

Fix aesh-processor for inner classes and custom CommandInvocation types#373

Merged
stalep merged 3 commits intoaeshell:masterfrom
tristantarrant:372/fix_inner_class_and_raw_type_generation
Mar 23, 2026
Merged

Fix aesh-processor for inner classes and custom CommandInvocation types#373
stalep merged 3 commits intoaeshell:masterfrom
tristantarrant:372/fix_inner_class_and_raw_type_generation

Conversation

@tristantarrant
Copy link
Copy Markdown
Contributor

@tristantarrant tristantarrant commented Mar 23, 2026

Summary

  • Fix inner class command metadata generation using incorrect package names
  • Fix generic type mismatch when commands use custom CommandInvocation subtypes
  • Add reflection-free field population support for GraalVM native image
  • Fix field setter/resetter being lost in ProcessedCommand.addOption() copy

Fixes #372

Details

Inner class fix: Uses elementUtils.getPackageOf() instead of string splitting on qualifiedName. Inner class metadata classes use flattened names (e.g., Config_Set_AeshMetadata).

Raw type fix: Casts ProcessedCommandBuilder.builder() to raw ProcessedCommandBuilder so .command(instance) works regardless of the CommandInvocation type parameter.

Reflection-free field population: Adds BiConsumer<Object, Object> fieldSetter and Consumer<Object> fieldResetter to ProcessedOption, allowing the annotation processor to generate direct field access lambdas instead of relying on reflection. This enables aesh commands to work in GraalVM native images without reflection metadata for field population. Private fields fall back to reflection.

addOption copy fix: ProcessedCommand.addOption() and setOptions() create copies of ProcessedOption but were not carrying over fieldSetter/fieldResetter, silently discarding the generated field accessors.

Test plan

  • 10 new tests in FieldSetterPopulatorTest and MetadataProviderFieldSetterTest
  • Full aesh test suite passes (357 tests)
  • Tested against Infinispan CLI native image: --version and interactive mode work correctly

…Invocation types

Two bugs in the annotation processor:

1. Inner class commands (e.g., Config.Set) used qualifiedName string
   splitting to derive the package, producing invalid package names
   like "org.example.Config". Now uses elementUtils.getPackageOf() and
   flattens inner class names with underscore (Config_Set_AeshMetadata).

2. Generated code used typed ProcessedCommandBuilder.builder() which
   fails when commands use custom CommandInvocation subtypes. Now casts
   to raw ProcessedCommandBuilder since @SuppressWarnings is already present.
…M native image

Add BiConsumer fieldSetter and Consumer fieldResetter to ProcessedOption,
allowing the annotation processor to generate direct field access lambdas
instead of relying on reflection. This enables aesh commands to work in
GraalVM native images without reflection metadata for field population.

- ProcessedOption: add fieldSetter/fieldResetter, injectValueWithSetter(),
  resetField() methods
- ProcessedOptionBuilder: add fieldSetter/fieldResetter builder methods
- AeshCommandPopulator: delegate resetField to ProcessedOption
- CodeGenerator: generate fieldSetter/fieldResetter lambdas for
  non-private fields, skip private fields (fall back to reflection)
…ption() copy

ProcessedCommand.addOption() and setOptions() create a copy of the
ProcessedOption but didn't carry over fieldSetter/fieldResetter, causing
the annotation processor's generated field accessors to be silently
discarded. Also adds comprehensive tests for field setter population.
@stalep stalep merged commit f0118f0 into aeshell:master Mar 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

aesh-processor: broken code generation for inner command classes and custom CommandInvocation types

2 participants