Convert Spring field injection to constructor injection (IntelliJ IDEA)?
Asked Answered
S

2

11

I am convinced to convert my Spring Java field injection [@Autowired] to constructor injection (among other reasons, to facilitate mock unit testing)...

Is there a utility I can use to automatically do that Spring field to constructor injection conversion?

For example, IntelliJ IDEA has generation shortcuts for a lot of things (i.e: generate setters & getters for fields); I'm hoping there's something similar to that... This is particularly useful when it is tedious to do the conversion manually, because a class to be converted already has numerous field-injected fields.

Subjoin answered 16/5, 2017 at 18:27 Comment(7)
Not that I know of.Palmira
Nothing out of the box. The way I do is, I do a search and replace for @Autowired private to @Autowired private final. Then there is a error displayed saying, final fields are not initialized. If you do a autocompletion(Alt+Enter) then it asks if It wants to create a contructor, and then you can select the fields and Enter. Thats it.Felid
@Felid that sounds like a good workaround. I will try it on the next chance I get where private is acceptable.Subjoin
And I guess I could always change private back to whatever it was, after the auto-constructor completes.Subjoin
of course, private is just an example I gave you. It could be any modifier. Main thing is to make the fields final, So that Idea cries with an error and we can kick in auto completion to generate required constructorFelid
@Felid ingeniously simple fix. Thank you :)Hatten
@Subjoin @ meese Let me add it as an aswer, since many people are stumbling upon this.Felid
H
9

Yes, it's now implemented in IntelliJ IDEA.

1) Place your cursor on one of the @Autowired annotation.

2) Hit Alt+Enter.

3) Select Create constructor

enter image description here

This is the quick fix related to the inspection "Field injection warning":

Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".

Field injection/NullPointerException example:

class MyComponent {

  @Inject MyCollaborator collaborator;

  public void myBusinessMethod() {
    collaborator.doSomething(); // -> NullPointerException   
  } 
}   

Constructor injection should be used:

class MyComponent {

  private final MyCollaborator collaborator;

  @Inject
  public MyComponent(MyCollaborator collaborator) {
    Assert.notNull(collaborator, "MyCollaborator must not be null!");
    this.collaborator = collaborator;
  }

  public void myBusinessMethod() {
    collaborator.doSomething(); // -> safe   
  }
}
Hellbender answered 25/1, 2019 at 13:41 Comment(4)
+1/Accepted for the new 'create constructor' context option! But question about Assert#notNull: Both two versions of MyComponent will throw an Exception of collaborator is null, so what is the advantage of Assert#notNull? Just a programmer-refine-able message param? Or maybe guaranteed Exception at Spring-context-load-time, instead of runtime possibility (via #myBusinessMethod)?Subjoin
Is there a 1-liner to assert all injected variables non-null?Subjoin
@Subjoin Assert#notNull throws an IllegalArgumentException at the construction of the object instead of a NullPointerException at some random point in the execution of the application. It's an application of the fail fast principle.Hellbender
@Subjoin I'm not sure there is 1-liner to assert all injected variables non-null but you can build one.Hellbender
F
7

Nothing out of the box.

The way I do is, I do a search and replace for
@Autowired private to @Autowired private final.

Then there is a error displayed saying, final fields are not initialized.
If you do a autocompletion(Alt+Enter), then it asks if you want to create a contructor, and then you can select the fields and click Enter.

private is just an example. It could be any modifier. Main thing is to make the fields final, So that Idea cries with an error and we can kick in auto completion to generate required constructor

Felid answered 22/3, 2018 at 21:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.