Skip to content

Preserve property descriptions during Gradle incremental compilation#50489

Draft
galenzo17 wants to merge 1 commit into
spring-projects:mainfrom
galenzo17:fix/28075-preserve-descriptions-incremental-build
Draft

Preserve property descriptions during Gradle incremental compilation#50489
galenzo17 wants to merge 1 commit into
spring-projects:mainfrom
galenzo17:fix/28075-preserve-descriptions-incremental-build

Conversation

@galenzo17
Copy link
Copy Markdown

Status

Draft. Seeking approach validation before adding performance benchmarks
and a repro on a spring-boot-internal module. Specifically requesting
sanity-check on the FieldValuesParser extension (the @FunctionalInterface
removal to add a default method).

Summary

When Gradle performs incremental compilation, unchanged @ConfigurationProperties
classes are passed to the annotation processor as .class files via the classes
parameter of JavaCompiler.getTask(). Since bytecode does not carry javadoc,
Elements.getDocComment() returns null for these elements and their property
descriptions are lost from spring-configuration-metadata.json.

This implements option 1 from the issue thread
(confirmed by @wilkinsona):
cache descriptions in a location outside CLASS_OUTPUT that Gradle does not clean
during incremental builds.

Approach

  • New processor option org.springframework.boot.configurationprocessor.descriptionCacheLocation
    configures where the cache file lives (opt-in, zero behavior change when unset)
  • .class-backed elements are detected via com.sun.source.util.Trees.getTree(),
    reusing the existing reflection wrapper in JavaCompilerFieldValuesParser
  • On write, descriptions for .class-backed types are filled from cache before the
    JSON is emitted; then the cache is replaced with the current metadata
  • Replace (not merge) strategy on cache update ensures deleted/de-annotated types are
    automatically pruned — no unbounded growth

Files changed

File Change
FieldValuesParser Added default hasSourceTree() (removed @FunctionalInterface — internal API)
JavaCompilerFieldValuesParser hasSourceTree() using existing Trees instance
MetadataGenerationEnvironment hasSourceTree() delegating to field values parser
ConfigurationMetadataAnnotationProcessor New option, tracks .class-backed types, fills missing descriptions from cache on write, then refreshes cache
DescriptionCache (new) File-based metadata cache with read/write/lookup
DescriptionCacheTests (new) 5 tests covering bug confirmation, JavaBean fix, record fix, staleness pruning, corrupt cache

Tests

  • 5 new tests in DescriptionCacheTests — all pass
  • All existing spring-boot-configuration-processor tests continue to pass
  • Checkstyle clean

Scope and limitations

Alternatives considered

  • Option 2 (non-incremental processor): would increase compile times for all users
  • Option 3 (annotation-based descriptions instead of javadoc): would require
    ecosystem-wide migration of existing property descriptions from javadoc to a new
    annotation
  • Merge-based cache update: would accumulate stale entries for deleted types;
    replace strategy is simpler and leverages the invariant that Gradle passes all
    annotated types every round

See gh-28075

Cache descriptions in a location outside CLASS_OUTPUT so that Gradle's
incremental compilation does not lose javadoc-based descriptions for
types passed as .class files.

See spring-projectsgh-28075

Signed-off-by: Agustin Bereciartua <bereciartua.agustin@gmail.com>
@galenzo17 galenzo17 force-pushed the fix/28075-preserve-descriptions-incremental-build branch from 9a177ef to 3baf552 Compare May 23, 2026 19:15
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants