Developers Notes
  • Welcome
  • Developer
    • Java
      • JUnit
        • Parameterized Test
        • Introduction to WireMock
      • Maven
        • Resource Reader and Writer
        • JUnit with Maven
        • Maven Run
        • A Quick Guide to Maven Wrapper
      • Spring
        • Autowired vs Resource
        • Spring OpenFeign 사용시 https 신뢰하는 방법
        • Aspect with Annotation
        • Spring JPA에서 Tibero를 사용하기 위한 설정
        • Spring module dependency
        • Mockito
          • Autowired @Value field in Spring with Mockito
        • SpringBoot Hybernate application.yml
        • ReflectionTestUtils
        • Spring Properties File Outside jar
        • Spring @RequestParam Annotation
        • Properties with Spring and Spring Boot
        • Passing JVM Options from Gradle bootRun
        • Securing Spring Boot API With API Key and Secret
        • Why Is Field Injection Not Recommended?
        • An Overview of Identifiers in Hibernate/JPA
      • Etcs
        • BigDecimal 사용시 주의 사항
        • static factory methods common naming conventions
        • List of Lists into a List (Stream)
        • Return null in stream
        • Logging with Lombok
        • JPA
        • Big-O Java Collections
    • MySQL
      • Active Connections on MySQL
      • MariaDB-Galera
      • FOUND_ROWS
      • MySQL Group Replication Requirements
      • Data Types Explicit Default Handling
    • C/C++
      • Autotool 사용법
      • Intruduction to GNU Autotools
      • mysql
        • C Api Flow
        • MySQL Connector/C++ 8.3 Developer Guide
      • Common vulnerabilities guide for C programmers
      • HTTP in C++
      • JSON in C++
      • How to get memory usage at runtime using C++?
      • How to get time in milliseconds using C++ on Linux?
      • Sleep Functions in C++
      • Calculate Cpu Usage on Linux as Top
    • CryptoGraphy
      • 인증 기관(CA;Certificate Authority) 구성하고 인증서 발급하기
      • KeyTool Import PrivateKey, Certificate
      • Java Keytool 사용법
      • PKCS, Public Key Cryptography Standard
      • CER/DER/CRT/CSR 형식 파일이란?
      • FIPS 140-2
      • SSL 인증서 발급
      • 사용법, tip 정리
      • OpenSSL
        • OpenSSL guide
        • Openssl RSA Private Key Encrypt
      • How to Read PEM File to Get Public and Private Keys
    • PKCS#11 API
      • PKCS#11 API-강좌1
      • PKCS#11 API-강좌2
      • PKCS#11 API-강좌3
      • PKCS#11 API-강좌4
      • PKCS#11 API-강좌5(C 언어로 된 Sample Code)
      • PKCS#11 API-강좌6(EC Key 생성 및 Signing)
    • Warehouse of PKI
    • GoLang
      • go-cshared-examples
      • Fun building shared libraries in Go
      • Golang time
      • Encoding Json
  • OpenSSL
    • OpenSSL Document
      • openssl-req
      • x509v3_config
      • Openssl Example
    • Creating a Self-Signed Certificate With OpenSSL
    • Openssl 3.x Provider
      • Writing OpenSSL Provider Skeleton
    • OpenSSL Certificate Command
  • DevOps
    • Docker
      • Environment Variables for MariaDB or MySQL Docker
      • Container Technology, Docker
      • Docker Trouble Shooting
      • Docker BuildKit
      • How to clear Docker cache and free up space on your system
    • Cloud
      • Serverless Architecture
      • AWS
        • AWS 주요 자습서 Link
        • Diagram-as-code for AWS architecture.
        • AWS Architecture icon
      • Install MariaDB Galera by Helm
      • Jenkinsfile VIM syntax highlighting
      • Cloud Development Kit for Kubernetes
    • VM
      • vagrant를 사용한 vm 설치 방법
    • Etcs
      • Logstash
        • Installing Logstash
        • Configuration Logstash Output
      • Rancher Install
      • Install ELK
      • Simpler Tool for Deploying Rancher
    • Ubuntu
      • Install SFTP Client
  • Etcs
    • Etcs
      • Useful Tools
      • Links
      • Entertainment
Powered by GitBook
On this page
  • 1. Overview
  • 2. Dependency Injection
  • 3. Null-Safety
  • 4. Immutability
  • 5. Design Problems
  • 6. Testing
  • 7. Conclusion
Edit on GitHub
  1. Developer
  2. Java
  3. Spring

Why Is Field Injection Not Recommended?

PreviousSecuring Spring Boot API With API Key and SecretNextAn Overview of Identifiers in Hibernate/JPA

Last updated 1 year ago

1. Overview

When we run the code analysis tool in the IDE, it may issue the “Field injection is not recommended” warning for fields with the @Autowired annotation.

In this tutorial, we’ll explore why field injection isn’t recommended and what alternative approaches we can use.

2. Dependency Injection

The process where objects use their dependent objects without a need to define or create them is called dependency injection. It’s one of the core functionalities of the Spring framework.

We can inject dependent objects in three ways, using:

  • Constructor injection

  • Setter injection

  • Field injection

The third approach here involves injecting dependencies directly into the class using the @Autowired annotation. Although it may be the simplest approach, we must understand that there are potential issues it might cause.

What’s more, even the doesn’t provide field injection as one of the DI options anymore.

3. Null-Safety

Field injection creates a risk of NullPointerException if dependencies aren’t correctly initialized.

Let’s define the EmailService class and add the EmailValidator dependency using the field injection:

@Service
public class EmailService {

    @Autowired
    private EmailValidator emailValidator;
}

Now, let’s add the process() method:

public void process(String email) {
    if(!emailValidator.isValid(email)){
        throw new IllegalArgumentException(INVALID_EMAIL);
    }
    // ...
}

The EmailService works properly only if we provide the EmailValidator dependency. However, using the field injection, we didn’t provide a direct way of instantiating the EmailService with required dependencies.

Moreover, we are able to create the EmailService instance using the default constructor:

EmailService emailService = new EmailService();
emailService.process("[email protected]");

Executing the code above would cause NullPointerException since we didn’t provide its mandatory dependency, EmailValidator.

Now, we can reduce the risk of NullPointerException using the constructor injection:

private final EmailValidator emailValidator;

public EmailService(final EmailValidator emailValidator) {
   this.emailValidator = emailValidator;
}

With this approach, we exposed the required dependencies publicly. Additionally, we now require clients to provide the mandatory dependencies. In other words, there’s no way to create a new instance of the EmailService without providing the EmailValidator instance.

4. Immutability

Using the field injection, we are unable to create immutable classes.

We need to instantiate the final fields when they’re declared or through the constructor. Furthermore, Spring performs autowiring once the constructors have been called. Therefore, it’s impossible to autowire the final fields using field injection.

Since the dependencies are mutable, there’s no way we can ensure they will remain unchanged once they’re initialized. Furthermore, reassigning non-final fields can cause unexpected side effects when running the application.

Alternatively, we can use constructor injection for mandatory dependencies and setter injection for optional ones. This way, we can ensure the required dependencies will remain unchanged.

5. Design Problems

Now, let’s discuss some possible design problems when it comes to field injection.

5.1. Single Responsibility Violation

Being part of the SOLID principles, the Single responsibility principle states each class should have only one responsibility. To put it differently, one class should be responsible for only one action and, thus, have only one reason to change.

When we use field injection, we may end up violating the single responsibility principle. We can easily add more dependencies than necessary and create a class that’s doing more than one job.

On the other hand, if we’re using constructor injection, we’d notice we might have a design problem if a constructor has more than a few dependencies. Furthermore, even the IDE would issue a warning if there are more than seven parameters in the constructor.

5.2. Circular Dependencies

Simply put, circular dependencies occur when two or more classes depend on each other. Because of these dependencies, it’s impossible to construct objects, and the execution can end up with runtime errors or infinite loops.

The use of field injection can result in circular dependencies going unnoticed:

@Component
public class DependencyA {

   @Autowired
   private DependencyB dependencyB;
}

@Component
public class DependencyB {

   @Autowired
   private DependencyA dependencyA;
}

Since the dependencies are injected when needed and not on the context load, Spring won’t throw BeanCurrentlyInCreationException.

With constructor injection, it’s possible to detect circular dependencies at compile time since they would create unresolvable errors.

Moreover, if we have circular dependencies in our code, it might be a sign something is wrong with our design. Therefore, we should consider redesigning our application if possible.

6. Testing

Unit testing reveals one of the major drawbacks of the field injection approach.

Suppose we’d like to write a unit test to check whether the process() method defined in the EmailService is working properly.

Firstly, we’d like to mock the EmailValidation object. However, since we inserted the EmailValidator using field injection, we can’t directly replace it with a mocked version:

EmailValidator validator = Mockito.mock(EmailValidator.class);
EmailService emailService = new EmailService();

Furthermore, providing the setter method in the EmailService class would introduce an additional vulnerability as other classes, not just the test class, could call the method.

However, we can instantiate our class through reflection. For instance, we can use Mockito:

@Mock
private EmailValidator emailValidator;

@InjectMocks
private EmailService emailService;

@BeforeEach
public void setup() {
   MockitoAnnotations.openMocks(this);
}

Here, Mockito will try to inject mocks using the @InjectMocks annotation. However, if the field injection strategy fails, Mockito won’t report the failure.

On the other hand, using constructor injection, we can provide the required dependencies without reflection:

private EmailValidator emailValidator;

private EmailService emailService;

@BeforeEach
public void setup() {
   this.emailValidator = Mockito.mock(EmailValidator.class);
   this.emailService = new EmailService(emailValidator);
}

7. Conclusion

In this article, we learned about the reasons why field injection isn’t recommended.

To sum up, instead of the field injection, we could use constructor injection for required and setter injection for optional dependencies.

However, since Spring Boot 2.6. version by default.

As always, the source code of this article is available .

official Spring documentation
circular dependencies are no longer allowed
over on GitHub
Why Is Field Injection Not Recommended? | BaeldungBaeldung
Logo