1

I have a bean being created by a service with the following class:

@Configuration
public class AccessManager {

    @Bean(name="access", destroyMethod="destroy")
    @Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
    @Autowired
    public Access create(HttpServletRequest request) {
        System.out.println(request.getRemoteAddr());
        return new Access();
    }

}

Everything works as expected, except that when the application is starting, this method is being called, probably because I have some other singleton beans that use the Access bean. At the start up there is no request bound to the Thread, and it's expected to get a java.lang.IllegalStateException when trying to access any property of the request parameter.

No problem. The question is, is it possible to check if the underlying HttpServletRequest of the proxy request is null before calling a property that raises the exception?

Caio Cunha
  • 23,326
  • 6
  • 78
  • 74

2 Answers2

2

You probably want to take a look at RequestContextHolder#getRequestAttributes(). That will return null if you're not currently in a context where request scope could be used.

@Configuration
public class AccessManager {

    @Bean(name="access", destroyMethod="destroy")
    @Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
    @Autowired
    public Access create(HttpServletRequest request) {
        if (RequestContextHolder.getRequestAttributes() != null) {
            System.out.println(request.getRemoteAddr());
        }
        return new Access();
    }

}
MCDS
  • 260
  • 1
  • 5
1

I think the issue here is with separation of concerns. Usually your service layer should not have any dependency on the servlet classes. This is very much a controller/UI concern.

Your service class should be provided with the properties which it needs to do its job. In this case a String. This service method should be called from a controller method which is injected with the servlet request.

Something like the following:

@Controller
public class MyController {

  @Autowired
  private AccessManager accessManager;


  @RequestMapping
  public void handleRequest(HttpServletRequest request) {
    accessManager.create(request.getRemoteAddr());
  }
}

and your service would then look like this:

@Service
public class AccessManager {

  public Access create(String remoteAddress) {
    return new Access();
  }
}

To sum up, anything annotated as @Service shouldn't have access to the Request.

Alex Barnes
  • 7,174
  • 1
  • 30
  • 50
  • The interest bean here is the `Access` itself. I thought `AccessManager` only as the "bean factory" responsible for building `Access`'s session beans. And for this task, it needs the request object. O inject the `Access` bean instead of the `AccessManager` to the my `@Controller`'s. Is this wrong? The `AccessManager` is not interesting to any of my controllers. – Caio Cunha Aug 17 '12 at 19:53
  • Anyway, the above situation is only a example. I have others points on the code where a proxied bean is used and I'd like to check if the underlying object is in a valid state without using a `try-catch` to achieve it. – Caio Cunha Aug 17 '12 at 20:06
  • 2
    My point is that anything annotated as Service shouldn't have access to the Request. – Alex Barnes Aug 17 '12 at 20:32
  • Sorry, now I got it. I just changed from `@Service` to `@Configuration`. The Request is necessary for the bean instantiation to seek for values inside it (the domain, for example). As the `Access` bean is session-scoped, it will always have a request bound to the Thread. – Caio Cunha Aug 17 '12 at 20:46
  • You say there will always be a request bound, it it's an @Configuration class which is loaded on app startup there will be no request available. Hence you won't have anything to inject. – Alex Barnes Aug 17 '12 at 20:56
  • But will be no asks for an Access bean, too, as they're session-scoped. Except for the initialization of the `@Controller`s, and this will cause an `IllegalStateException`, which I'd like to avoid as there is nothing to do. – Caio Cunha Aug 17 '12 at 21:00
  • There is no error at the application at all. The problem is that during the start up, it's instantiating an `Access` bean, I don't know why, and it shouldn't as it is session-scoped. Anyway, as this instance is not supose to exists, it could be securely discarded. The problem is that this would cause an `IllegalStateException` if I try to access the instance. I'd like to prevent the exception by checking the bean state validity. Is it possible or I do need a `try-catch`? – Caio Cunha Aug 17 '12 at 22:04