You’ve annotated your field with @Autowired, but when you try to use it, you get a NullPointerException. Spring Boot’s supposed to inject the dependency automatically, but instead you’re dealing with null references and runtime crashes.

Quick Answer: Your @Autowired field is null because Spring isn't managing the object instance where you're trying to inject. The most common cause is creating objects with the new keyword instead of letting Spring manage the lifecycle through component scanning or configuration.

Why @Autowired Returns Null

Spring’s dependency injection only works on beans that Spring itself creates and manages. When you instantiate a class using new, you’re bypassing Spring’s container entirely. That instance won’t have any of its @Autowired fields populated because Spring never gets a chance to inject them.

Think of it this way: Spring maintains a registry of all managed beans. When it creates a bean, it looks at all the @Autowired annotations and injects the appropriate dependencies from its registry. But if you create an object yourself, Spring doesn’t even know it exists.

The Five Most Common Causes

Cause #1: Creating Objects with new

This is by far the most common mistake. You’re manually instantiating a class that has @Autowired dependencies.

Before (problematic):

@Service
public class OrderService {
    @Autowired
    private PaymentProcessor paymentProcessor;

    // This will be null!
}

// In some other class:
public class OrderController {
    public void processOrder() {
        OrderService service = new OrderService();
        service.process(); // paymentProcessor is null → NPE!
    }
}

After (fixed):

@RestController
public class OrderController {
    @Autowired
    private OrderService orderService; // Let Spring inject it

    @PostMapping("/orders")
    public void processOrder() {
        orderService.process(); // Works perfectly
    }
}

Alternatively, use constructor injection (recommended):

@RestController
public class OrderController {
    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping("/orders")
    public void processOrder() {
        orderService.process(); // Clean and testable
    }
}

Cause #2: Missing Component Scanning Annotations

Your class needs to be discoverable by Spring’s component scanning. Without annotations like @Component, @Service, @Repository, or @Controller, Spring won’t create a bean for it.

Before (problematic):

public class EmailService { // Missing annotation!
    @Autowired
    private JavaMailSender mailSender; // Will be null

    public void sendEmail(String to, String message) {
        mailSender.send(...); // NPE here
    }
}

After (fixed):

@Service // Now Spring knows to manage this
public class EmailService {
    @Autowired
    private JavaMailSender mailSender; // Gets injected properly

    public void sendEmail(String to, String message) {
        mailSender.send(...); // Works!
    }
}

Cause #3: Component Outside Base Package

Spring Boot automatically scans the package where your main @SpringBootApplication class is located and all sub-packages. If your component is in a different package tree, Spring won’t find it.

// Main class in: com.example.app
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// This service in: com.mycompany.services (different root!)
@Service
public class AnalyticsService { // Won't be scanned
    @Autowired
    private DataRepository repo; // Will be null
}

Solution 1: Move to correct package

com.example.app
├── Application.java
└── services
    └── AnalyticsService.java  ← Move here

Solution 2: Add explicit component scan

@SpringBootApplication
@ComponentScan(basePackages = {"com.example.app", "com.mycompany.services"})
public class Application {
    // Now it finds both package trees
}

Cause #4: Using @Autowired in Non-Spring Managed Objects

Configuration classes, utility classes instantiated manually, or objects created by third-party libraries won’t have dependency injection working.

This won’t work:

public class StringUtils { // Plain utility class
    @Autowired
    private SomeService service; // Will be null

    public static String process(String input) {
        StringUtils utils = new StringUtils();
        return utils.service.transform(input); // NPE
    }
}

If you really need Spring dependencies in a utility context, make it a bean:

Better approach:

@Component
public class StringProcessor {
    private final TransformService service;

    public StringProcessor(TransformService service) {
        this.service = service;
    }

    public String process(String input) {
        return service.transform(input);
    }
}

// Inject it wherever needed
@Service
public class DocumentService {
    @Autowired
    private StringProcessor processor;
}

Cause #5: Timing Issues in @PostConstruct

If you’re accessing @Autowired dependencies in a @PostConstruct method, make sure all dependencies are properly configured. Sometimes circular dependencies or complex initialization chains cause issues.

@Service
public class CacheService {
    @Autowired
    private DataRepository repository;

    @PostConstruct
    public void initialize() {
        // If repository isn't fully initialized yet, this might fail
        repository.findAll().forEach(this::cache);
    }
}

Fix with lazy initialization:

@Service
public class CacheService {
    @Autowired
    @Lazy
    private DataRepository repository;

    @PostConstruct
    public void initialize() {
        repository.findAll().forEach(this::cache);
    }
}

Constructor Injection: The Modern Best Practice

Field injection with @Autowired works, but constructor injection is strongly recommended for several reasons:

  1. Immutability: Dependencies can be final
  2. Testability: Easy to mock in unit tests
  3. Null safety: Dependencies must be provided at construction time
  4. No reflection needed: More efficient

Modern Spring style:

@Service
public class OrderService {
    private final PaymentProcessor paymentProcessor;
    private final InventoryService inventoryService;
    private final NotificationService notificationService;

    // Single constructor - @Autowired is implicit (Spring 4.3+)
    public OrderService(
            PaymentProcessor paymentProcessor,
            InventoryService inventoryService,
            NotificationService notificationService) {
        this.paymentProcessor = paymentProcessor;
        this.inventoryService = inventoryService;
        this.notificationService = notificationService;
    }

    public void processOrder(Order order) {
        // All dependencies guaranteed non-null
        inventoryService.reserve(order);
        paymentProcessor.charge(order);
        notificationService.sendConfirmation(order);
    }
}

Even cleaner with Lombok:

@Service
@RequiredArgsConstructor // Generates constructor for final fields
public class OrderService {
    private final PaymentProcessor paymentProcessor;
    private final InventoryService inventoryService;
    private final NotificationService notificationService;

    public void processOrder(Order order) {
        inventoryService.reserve(order);
        paymentProcessor.charge(order);
        notificationService.sendConfirmation(order);
    }
}

Debugging Checklist

When you encounter null @Autowired fields, work through this checklist:

  1. Is the class a Spring-managed bean?

    • Check for @Component, @Service, @Repository, or @Controller
    • Verify it’s in a package that’s component-scanned
  2. How is the object being created?

    • If you see new ClassName(), that’s the problem
    • Use dependency injection instead
  3. Is the dependency itself a bean?

    • The thing you’re trying to inject must also be Spring-managed
    • Check for missing annotations on the dependency
  4. Check your package structure

    • Run your app with --debug flag to see component scan output
    • Look for “Identified candidate component class” messages
  5. Enable Spring Boot debug logging

# application.properties
logging.level.org.springframework=DEBUG

This shows you exactly which beans Spring is creating and managing.

Real-World Example: REST Controller

Here’s a complete example showing the right way to structure a Spring Boot REST controller with multiple dependencies:

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;
    private final EmailService emailService;
    private final AuditLogger auditLogger;

    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        return userService.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody @Valid UserDto dto) {
        User user = userService.create(dto);
        emailService.sendWelcomeEmail(user);
        auditLogger.log("User created: " + user.getId());
        return ResponseEntity.status(HttpStatus.CREATED).body(user);
    }
}

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository repository;

    public Optional<User> findById(Long id) {
        return repository.findById(id);
    }

    public User create(UserDto dto) {
        User user = new User();
        user.setName(dto.getName());
        user.setEmail(dto.getEmail());
        return repository.save(user);
    }
}

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // Spring Data JPA automatically implements this
}

Notice how everything is connected through constructor injection. No field-level @Autowired, no manual instantiation with new, and all dependencies are guaranteed to be present.

Testing Your Dependencies

When writing unit tests, constructor injection makes mocking trivial:

@Test
void shouldCreateUserAndSendEmail() {
    // Arrange
    UserService userService = mock(UserService.class);
    EmailService emailService = mock(EmailService.class);
    AuditLogger auditLogger = mock(AuditLogger.class);

    UserController controller = new UserController(
        userService,
        emailService,
        auditLogger
    );

    UserDto dto = new UserDto("John", "john@example.com");
    User user = new User(1L, "John", "john@example.com");
    when(userService.create(dto)).thenReturn(user);

    // Act
    ResponseEntity<User> response = controller.createUser(dto);

    // Assert
    assertEquals(HttpStatus.CREATED, response.getStatusCode());
    verify(emailService).sendWelcomeEmail(user);
    verify(auditLogger).log("User created: 1");
}

No Spring context needed for unit tests. Fast, focused, and reliable.

Prevention Tips

  1. Avoid field injection - Use constructor injection instead
  2. Never use new for Spring-managed classes
  3. Use final fields - Forces constructor injection and prevents null
  4. Enable strict null checks - Use IDE warnings or tools like SpotBugs
  5. Leverage Lombok - @RequiredArgsConstructor reduces boilerplate
  6. Test early - Write integration tests that actually start the Spring context

Common Questions

Q: Can I use @Autowired on private fields? A: Yes, it works, but constructor injection is preferred for testability and immutability.

Q: What’s the difference between @Autowired and @Inject? A: @Inject is from JSR-330 (standard Java DI), @Autowired is Spring-specific. They’re mostly interchangeable, but @Autowired has additional features like required=false.

Q: Why does IntelliJ warn about field injection? A: Because constructor injection is considered best practice. IntelliJ’s inspection is nudging you toward better code.

Q: Can I mix field and constructor injection? A: Technically yes, but don’t. Pick one style (preferably constructor) and stick with it for consistency.

Key Takeaways

  • @Autowired only works on Spring-managed beans
  • Never instantiate Spring components with new
  • Prefer constructor injection over field injection
  • Ensure your classes are annotated and component-scanned
  • Use final fields to catch null dependencies at compile time
  • When debugging, check if Spring is actually creating your beans

Still hitting NullPointerException with your Spring dependencies? Use Debugly’s trace formatter to quickly parse and analyze Java stack traces. It highlights the exact line where your null reference occurs and makes it easy to trace back through your dependency chain to find the root cause.

Got more complex Spring dependency issues? Check out our guide on Spring Boot BeanCreationException for related troubleshooting steps, or learn about NoSuchBeanDefinitionException if Spring can’t find your beans at all.