Search code examples
javaspring-bootdependency-injectionnullpointerexception

NullPointerException: Cannot invoke "org.modelmapper.ModelMapper.map(Object, java.lang.Class)" because "this.modelMapper" is null


I have a mapper

@Component
public class DTOmapper {

    private final ModelMapper modelMapper;

    public DTOmapper(ModelMapper modelMapper) {
        this.modelMapper = modelMapper;
    }

    UserDTO convertUserToDTO(account.User user) {
        // here we make use of the 3rd party library to transform a User into a UserDTO
        return modelMapper.map(user, UserDTO.class);
    }

}

And I am trying to use it:

@RestController
public class AccountController {

    @PostMapping("/api/auth/signup")
    public ResponseEntity<UserDTO> postAuthSignUp(@RequestBody account.User user, @Autowired DTOmapper dTOmapper) {
        if(user.email().endsWith("@acme.com")
        ) {
            return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body( dTOmapper.convertUserToDTO(user) );
        }else{
            return ResponseEntity.badRequest().build();
        }
    }
}

And I get

java.lang.NullPointerException: Cannot invoke "org.modelmapper.ModelMapper.map(Object, java.lang.Class)" because "this.modelMapper" is null
    at account.DTOmapper.convertUserToDTO(DTOmapper.java:12) ~[classes/:an]

Why and how to solve it?

User is a record

public record User(String name, String lastname, String email, String password) {
}

ModelMapper bean declaration:

@SpringBootApplication
public class AccountServiceApplication {
  public static void main(String[] args) {
    SpringApplication.run(AccountServiceApplication.class, args);
  }

  @Bean
  public ModelMapper modelMapper() {
    return new ModelMapper();
  }
}

Solution

  • Also make sure that the ModelMapper is configured as a Bean in your project, should look something like this:

    @Configuration
    public class ProjectConfigFile {
    
     @Bean
      public ModelMapper modelMapper() {
        return new ModelMapper();
      }
    }
    

    And I would use constructor injection for the mapper in your AccountController and call it directly, such as

    @RestController
    public class AccountController {
    
    private final DTOmapper dTOmapper;
    
    public AccountController(DTOmapper dTOmapper) {
        this.dTOmapper = dTOmapper;
    }
    
    @PostMapping("/api/auth/signup")
    public ResponseEntity<UserDTO> postAuthSignUp(@RequestBody account.User user) {
        // Use the injected dTOmapper directly
        if (user.email().endsWith("@acme.com")) {
            return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(dTOmapper.convertUserToDTO(user));
        } else {
            return ResponseEntity.badRequest().build();
        }
      }
    }