10

I want to make a check in database when i receive a request. So i did a Interceptor like below,

CustomInterceptor.java

@Component
public class CustomInterceptor extends HandlerInterceptorAdapter {

@Autowired
private DatabaseService databaseService;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    //Set Request Attribute(TODO)
    LogService.info(this.getClass().getName(), "New Request URI is:" + request.getRequestURI());
    return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    String authToken = request.getHeader("AuthToken");
        boolean isValidRequest = databaseService.checkIfTokenIsValid(authToken);
    }
}

Application.class:

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

//    protected Properties props = new Properties();
//
//    public Application() {
//        props.setProperty("error.path", "/error");
////        props.setProperty("error.whitelabel.enabled", "false");
////        props.setProperty("org.springframework.web", "DEBUG");
//    }
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
//        application.properties(props);
    return application.sources(Application.class);
}

@Override
public void onStartup(final ServletContext servletContext) throws ServletException {
    LogService.info(Application.class.getName(), "Loading Service...");
    super.onStartup(servletContext);
    LogService.info(Application.class.getName(), "Service Started");
}

public static void main(String[] args) {
    ApplicationContext context = SpringApplication.run(Application.class, args);
}

DatabasService.java

@Service
public class DatabaseService {


@Autowired
private ApplicationProperties properties;

private final JdbcTemplate defaultJdbcTemplate;

@Autowired
public DatabaseService(
        @Qualifier("dataSource") DataSource dataSource) {
    defaultJdbcTemplate = new JdbcTemplate(dataSource);
}

public boolean checkIfTokenIsValid() {
    //Perform Check
 }
}

CustomWebConfiguration.java

@Configuration
@EnableWebMvc
public class CustomWebConfiguration extends WebMvcConfigurerAdapter {

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
    "classpath:/META-INF/resources/", "classpath:/resources/",
    "classpath:/static/", "classpath:/public/"};

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!registry.hasMappingForPattern("/**")) {
        registry.addResourceHandler("/**").addResourceLocations(
                CLASSPATH_RESOURCE_LOCATIONS);
    }
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new CustomInterceptor())
            .addPathPatterns("/**");
}

}

But i get NullPointer At: boolean isValidRequest = databaseService.checkIfTokenIsValid(authToken);

What is wrong here, why cannot spring Autowire the Databaseservice in Interceptor?

Note: Autowire works fine everywhere else, but not in the interceptor.

Solution (Thanks to M. Deinum) Change the CustomWebConfiguration.java like below;

@Configuration
@EnableWebMvc
public class CustomWebConfiguration extends WebMvcConfigurerAdapter {

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
    "classpath:/META-INF/resources/", "classpath:/resources/",
    "classpath:/static/", "classpath:/public/"};

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!registry.hasMappingForPattern("/**")) {
        registry.addResourceHandler("/**").addResourceLocations(
                CLASSPATH_RESOURCE_LOCATIONS);
     }
    }

@Bean
public CustomInterceptor customInterceptor() {
    return new CustomInterceptor();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(customInterceptor())
            .addPathPatterns("/**");
 }
}
Rajkishan Swami
  • 3,569
  • 10
  • 48
  • 68
  • can you post the details where is DatabaseService class defined and how is it mapped? – Mohit Kanwar Jul 23 '15 at 05:42
  • @MohitKanwar : Edited Question. – Rajkishan Swami Jul 23 '15 at 05:48
  • 2
    Let me guess you are using a `addInterceptors` method from the `WebMvcConfigurer[Adapter]` and use `new CustomInterceptor()`. This makes your interceptor a non managed bean and will never be injected. Create a `@Bean` method for it (or inject it into your configuration class) and use that instance to add as an interceptor. – M. Deinum Jul 23 '15 at 07:29
  • @M.Deinum : Yes i do. I thought if i make it `@Component` then spring will take is as a candidate for auto-detection as the Documentation says. I have modified question. – Rajkishan Swami Jul 23 '15 at 07:40
  • No it won't only when spring is also controlling the lifecycle of the bean, it isn't as you are manually constructing it. Hence it isn't a spring bean making `@Component` and `@Autowired` useless. As stated make it a managed bean instead of creating your own instance. – M. Deinum Jul 23 '15 at 07:47
  • @M.Deinum : Your suggesstion worked perfectly. Thank you again(You have helped me before also :)). And i just noticed this can be a duplicate question. Can you please post this as answer so i can accept? – Rajkishan Swami Jul 23 '15 at 07:56

2 Answers2

14

Spring will only autowire beans it knows about, you are creating the instance yourself outside the control of Spring.

Either inject a CustomInterceptor into your configuration class or add a @Bean method to make it a Spring managed instance. Then use that instance to add it to the list of interceptors.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
0

It is OK to use @SpringBootApplication on your main class, however don't you miss @EnableAutoConfiguration and @ComponentScan on the same class to tell Spring Boot to look for other components and services automatically?

GHajba
  • 3,665
  • 5
  • 25
  • 35
  • `@SpringBootApplication` automatically contains `@EnableAutoConfiguration` and `@ComponentScan`. So as long as the default configuration for these annotations is enough for you, you don't have to specify them explicitly. – dunni Jul 23 '15 at 06:02