random12524345
random12524345

Reputation: 99

NullPointerException when making call to Spring Data JPA Repository

When I call my API to validate a token for the frontend I am running into an issue when calling my UserDetailsService's loadUserByUsername method. I am able to pass the username to the method but my userRepository fails to execute the findByUsername method, and I am not sure what is going on. I am printing the name out before the call and it is returning the correct username, also a user of that name exists in the DB.

This is what I am getting in the console:

2020-07-09 22:46:55.121  INFO 18048 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet        : Completed initialization in 10 ms
2020-07-09 22:46:55.153  INFO 18048 --- [nio-8080-exec-4] c.g.Apollo.security.jwt.JwtFilter        : token not presented...
2020-07-09 22:46:55.759  INFO 18048 --- [nio-8080-exec-4] c.g.Apollo.service.UserService           : success...
2020-07-09 22:47:10.885  INFO 18048 --- [nio-8080-exec-5] c.g.Apollo.security.jwt.JwtFilter        : token not presented...
2020-07-09 22:47:10.898  INFO 18048 --- [nio-8080-exec-5] c.g.A.s.jwt.JwtUserDetailsService        : load user... max123
2020-07-09 22:47:10.909  WARN 18048 --- [nio-8080-exec-5] g.e.SimpleDataFetcherExceptionHandler    : Exception while fetching data (/verifyToken) : null

java.lang.NullPointerException: null
    at com.**.Apollo.security.jwt.JwtUserDetailsService.loadUserByUsername(JwtUserDetailsService.java:23) ~[classes/:na]
    at com.**.Apollo.service.UserService.verifyToken(UserService.java:173) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
    at io.leangen.graphql.metadata.execution.SingletonMethodInvoker.execute(SingletonMethodInvoker.java:21) ~[spqr-0.9.9.jar:na]

The UserRepository method works just fine when I login a user but fails here.

JwtUserDetailsService, this is called from the verifyToken method:

@Slf4j
@Service
public class JwtUserDetailsService implements UserDetailsService {

private UserRepository userRepository;

@Override
public UserDetails loadUserByUsername(String username) {
    log.info("load user... {}", username);
    Optional<User> user = userRepository.findByUsername(username);
    log.info("after");
    if (user.isPresent()) {
        log.info("user:: {}", user.get().getUsername());
        return getJwtUser(user.get());
    } else {
        log.info("user not found");
        return null;
    }
}

public JwtUser getJwtUser(User user) {
    return new JwtUser(
            user.getId(),
            user.getUsername(),
            user.getFirstName(),
            user.getLastName(),
            user.getEmail(),
            user.getPassword(),
            List.of(new SimpleGrantedAuthority(user.getRole().getRoleName().name())),
            user.getEnabled(),
            null
    );
}

UserRepository:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    Optional<User> findByUsername(String username);

    boolean existsByUsername(String username);

    Optional<User> findByToken(String token);
}

UserSerice, this is what is exposed to the frontend:

@GraphQLQuery
public User verifyToken(String token) {
    Optional<User> optionalUser = userRepository.findByToken(token);
    if(optionalUser.isPresent()) {
        UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(optionalUser.get().getUsername());
        if(jwtTokenUtil.isTokenValid(token, userDetails)) {
            return optionalUser.get();
        }
    }
    return null;
}

Upvotes: 0

Views: 4056

Answers (3)

Swapnil Khante
Swapnil Khante

Reputation: 659

It seems that your UserRepository dependency is not getting injected in JwtUserDetailsService as you did not autowire it.

You can do the following:

Autowire the dependency using the constructor injection which is the recommended way:

private final UserRepository userRepository;

public JwtUserDetailsService(UserRepository userRepository)  {
    this.userRepository = userRepository;
} 

It is not recommended to autowire your private members, checkout this post

As you are already using project Lombok, more elegant way to do it instead of writing a constructor would be just annotate your class with @RequiredArgsConstructor.

   @Slf4j
   @RequiredArgsConstructor
   @Service
   public class JwtUserDetailsService implements UserDetailsService {

     private final UserRepository userRepository; 
     ..

   }

Here Project lombok will generate a constructor for you which will take care of the dependency injection.

Upvotes: 0

Rahul Kumar
Rahul Kumar

Reputation: 372

You need to add @Autowired in class JwtUserDetailsService

@Autowired
private UserRepository userRepository;

Upvotes: 1

Edgar Domingues
Edgar Domingues

Reputation: 990

It is throwing a NullPointerException because the userRepository in JwtUserDetailsService was not injected and is null.

Create a constructor like the following:

public JwtUserDetailsService(UserRepository userRepository) {
    this.userRepository = userRepository;
}

Upvotes: 1

Related Questions