Skip to content

Fix generic type loss in AutowiredFieldIntoConstructorParameterVisitor (fixes #1005)#1006

Closed
dim-kod wants to merge 3 commits into
openrewrite:mainfrom
dim-kod:fix/autowired-generic-type-loss
Closed

Fix generic type loss in AutowiredFieldIntoConstructorParameterVisitor (fixes #1005)#1006
dim-kod wants to merge 3 commits into
openrewrite:mainfrom
dim-kod:fix/autowired-generic-type-loss

Conversation

@dim-kod

@dim-kod dim-kod commented Apr 23, 2026

Copy link
Copy Markdown

What's changed?

AutowiredFieldIntoConstructorParameterVisitor now preserves generic type parameters when converting @Autowired fields to constructor parameters.

Both AddConstructorVisitor and AddConstructorParameterAndAssignment were using TypeUtils.asFullyQualified(type).getClassName() to render the field type in the generated constructor, which strips generics — so List<String> ends up as raw List.

The fix switches to TypeTree.toString(), which goes through JavaPrinter and gives you the full source-level type string. I also added addImportsForType/collectFullyQualifiedNames helpers to register type parameter FQNs with the JavaTemplate builder.

A second commit broadens the type guard from TypeUtils.asFullyQualified() == null to null || Primitive — this fixes a separate issue where array-typed fields like String[] a were silently skipped during constructor generation.

What's your motivation?

Any @Autowired field with a parameterized type ends up with a raw-type constructor parameter after the recipe runs, which produces compiler warnings and loses type safety.

Anything in particular you'd like reviewers to focus on?

  • The TypeTree.toString() approach — it uses JavaPrinter.printTrimmed() under the hood and already handles all type forms (parameterized, wildcards, bounded wildcards, nested generics, arrays).
  • The broadened type guard (Primitive check instead of asFullyQualified == null) — this intentionally lets JavaType.Array through.

Have you considered any alternatives or workarounds?

  • A custom renderTypeSimple(JavaType) that recursively builds the simple-name type string from JavaType — works, but duplicates what TypeTree.toString() already does.
  • TypeUtils.toString(JavaType) — produces fully qualified names (e.g. java.util.List<java.lang.String>), not source-level simple names, so it doesn't work for template strings.

Any additional context

Test coverage went from 11 to 22 tests. New tests cover:

  • Generic types into new/existing/parameterized constructors (List<String>)
  • Nested generics (Map<String, List<Integer>>)
  • Wildcards: unbounded (List<?>), upper-bounded (List<? extends Number>), lower-bounded (List<? super Integer>)
  • User-defined generic types across packages (MyService<MyConfig>)
  • Array types (String[])
  • @Autowired(required = false)
  • Multiple annotations (@Autowired @Qualifier("myBean"))

Checklist

  • I've added unit tests to cover both positive and negative cases
  • I've read and applied the recipe conventions and best practices
  • I've used the IntelliJ IDEA auto-formatter on affected files

dim-kod added 2 commits April 23, 2026 09:32
…r parameters

Both AddConstructorVisitor and AddConstructorParameterAndAssignment used
TypeUtils.asFullyQualified(type).getClassName() to render the field type
in the generated constructor parameter, which dropped generic type
parameters (e.g. List<String> became raw List).

Use TypeTree.toString() instead, which leverages JavaPrinter to produce
the full source-level type string including generics, wildcards, and
nested type parameters. Also add addImportsForType/collectFullyQualifiedNames
helpers to register type parameter FQNs with the JavaTemplate builder.
The type guard used TypeUtils.asFullyQualified() which returns null for
JavaType.Array, preventing constructor generation for array-typed fields.
Replace with a null + primitive check so arrays (and other non-primitive
types) are accepted. Also add tests for @Autowired(required = false)
and fields with multiple annotations.
…-type-loss

# Conflicts:
#	src/main/java/org/openrewrite/java/spring/AutowiredFieldIntoConstructorParameterVisitor.java
@dim-kod

dim-kod commented May 5, 2026

Copy link
Copy Markdown
Author

Hello @timtebeek, any updates?

@timtebeek

Copy link
Copy Markdown
Member

Hi no just need some more time for a proper review and merge; but with Devoxx UK this week, and Code Remix Summit next week it can take a bit longer to run through. Thanks for the work and patience in seeing this through!

@dim-kod

dim-kod commented May 7, 2026

Copy link
Copy Markdown
Author

Understood, thanks.

@MBoegers

MBoegers commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Hey @dim-kod, thanks for your analysis on this one. I took your branch and evolved it by using more built-in utilities. Do you mind reviewing the result? #1037
If you are okay with the proposal you can close this PR.

@dim-kod dim-kod closed this Jun 15, 2026
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants