Conversation
Type resolution skipped every IsStatic || IsFinal field, so DTOs whose members are declared final exported with an empty field map and no warning. The intent was to skip compile-time constants, but final is also how immutable DTOs are written and what Lombok @value generates; what distinguishes a constant from data is staticness, not finality. Fields are now skipped only when static (which already covers static final constants regardless of initializer); final instance fields resolve and export like any other field. The same rule is applied to dependency-resolved classes, which went through an identical filter. Per-module changes: - api-collector-java/resolver: the field loop in Resolve drops the IsFinal condition and only skips IsStatic, with a comment recording the constant-vs-data distinction so it is not reintroduced. - api-collector-java/maven: MavenDependencyResolver.ResolveType applies the same static-only filter when flattening dependency classes into ResolvedType fields. - api-collector-java/parser: record components are marked IsFinal (they are implicitly private final fields per JLS 8.10.3 and were left unset only because the resolver used to drop final fields), and Field gains HasInitializer, read off the tree-sitter declarator's labeled `value` field, so a static final field with an initializer is recognizable as a compile-time constant. Acceptance criteria verified: - A class whose instance fields are final exports all of them (TestResolve_ImmutableFinalFields, TestParser_ParseImmutableProduct). - static final constants remain excluded (same tests assert 'TYPE' stays out of the exported field map). - Classes with neither modifier are unchanged (existing resolver, springmvc, and apilot-cli golden tests pass untouched). Tests: TestResolve_ImmutableFinalFields and record-field IsFinal assertions in resolver_test.go; TestParser_ParseImmutableProduct plus record-component finality in parser_test.go with the ImmutableProduct testdata fixture; TestMavenDependencyResolver_ResolveTypeFieldFiltering in maven. go vet and go test pass for api-collector-java and apilot-cli (golden files unaffected).
|
📦 Build artifact for this PR is available in the GitHub Actions workflow run under Artifacts. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #155 +/- ##
=============================================
+ Coverage 71.594% 71.816% +0.223%
=============================================
Files 66 66
Lines 12381 12383 +2
=============================================
+ Hits 8864 8893 +29
+ Misses 2932 2905 -27
Partials 585 585
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #141.
Type resolution skipped every field marked
IsStatic || IsFinal, so DTOs whose members are declared final exported with an empty field map and no warning. The intent was presumably to skip compile-time constants, butfinalis also how immutable DTOs are written, and it is what Lombok generates:Both resolve to an object model with no fields at all. The distinction that matters is not
finalbut "is this a compile-time constant": astatic finalfield with an initializer is a constant, an instancefinalfield is data. Since statics are skipped regardless, the correct rule is to skip onlyIsStatic— final instance fields then resolve and export like any other field.The same filter existed in the maven dependency resolver, so a Lombok
@ValueDTO coming from a dependency JAR hit the identical bug; it gets the same rule.This PR also follows up on the coupling left when #139 landed: record components are implicitly
private final(JLS 8.10.3) and were deliberately left unmarked only because the resolver used to drop final fields — they are now marked accurately.Changes
api-collector-java/resolver/resolver.goResolvedrops theIsFinalcondition and skips onlyIsStatic, which already coversstatic finalconstants with or without an initializer. A comment records the constant-vs-data distinction so the old rule is not reintroducedapi-collector-java/maven/dep_resolver.goMavenDependencyResolver.ResolveTypeapplies the same static-only filter when flattening dependency classes intoResolvedTypefieldsapi-collector-java/parser/types.goFieldgainsHasInitializer— whether the declaration carries an= valuepart — so astatic finalfield with an initializer is recognizable as a compile-time constantapi-collector-java/parser/extractor.goextractFieldreads initializer presence off the tree-sitter declarator's labeledvaluefield (ChildByFieldName("value"); the grammar has noinitializernode kind — the value is anarray_initializeror an expression).extractRecordComponentssetsIsFinal: trueon record components and its comment no longer describes working around the old resolver ruleapi-collector-java/testdata/ImmutableProduct.java@Value-style immutable DTO fixture (sku/priceas final instance fields) that also carries a realpublic static final String TYPE = "product"constantapi-collector-java/resolver/resolver_test.goTestResolve_ImmutableFinalFields: the all-final DTO exportssku(string) andprice(BigDecimal → double) whileTYPEstays excluded. The inline record tests now setIsFinal: trueon their fields, matching what the parser emits since #139's follow-up in this PRapi-collector-java/parser/parser_test.goTestParser_ParseImmutableProductover the fixture:TYPEis static + final + with initializer,sku/priceare final instance fields without one.TestParser_ParseRecordadditionally asserts record components are marked finalapi-collector-java/maven/dep_resolver_test.goTestMavenDependencyResolver_ResolveTypeFieldFiltering: dependency classes go through the same rule — statics dropped, final instance fields and plain fields keptVerification
go vet ./...clean andgo test ./...passes forapi-collector-java;go test ./...passes forapilot-cli(the only dependent module), golden files unaffected — this change is Java-collector-only and the CLI golden project is Go.finalexports all of them (TestResolve_ImmutableFinalFields,TestParser_ParseImmutableProduct).static finalconstants remain excluded (the same tests assertTYPEstays out of the exported field map).