#Autowired property in bean constructed as MVC method parameter - java

I'm using the Spring MVC framework. In the code fragment below, is it possible for me to have Spring inject a bean into the MyRequestClass request parameter when it is constructed (ie. using #Autowired or ApplicationContextAware interface)? I need that request object to access one of my singleton Spring beans and would rather not have to create an ApplicationContextAware implementing singleton just for this purpose.
So far, I'm just getting NullPointerExceptions trying to access the beanaroo property with either approach.
#RequestMapping("/**")
#Controller
public class MyController {
#RequestMapping(value = "/mymethod", method = RequestMethod.POST)
public ModelAndView myMethod(#RequestBody MyRequestClass request,
ModelMap modelMap,
HttpServletResponse response) {
...
}
}
eg.
public class MyRequestClass {
#Autowired
private MyInjectedBean beanaroo;
}
I also tried defining a prototype bean of that class in my application context file but it didn't have any effect either.

You can, using #Configurable and aspectJ, but I wouldn't if I were you.
I'd just have the bean have a method that takes MyInjectedBean as param, and call that from the controller.

Related

Spring framework: what happens when you inject a Java bean into another Java bean but they have different scopes

I'm new to Java and Spring framework programming.
Please consider the following two Java files:
//AccountService.java
package org.mycompany.accountManagement
#Path("/bankaccount")
#Component
#Scope("session")
public class AccountService
{
private Depositer myDepositer;
#Autowired
pubilc AccountService( Depositer depositer )
{
myDepositer = depositer;
}
}
//Depositer.java
package org.mycompany.accountManagement
#Component
#Scope("request")
public class Depositer
{
public void deposit(){ System.out.println("Depositing..."); }
}
The class AccountService is instantiated only once for a given HTTP session. When it is instantiated, a Depositer object was also instantiated and was kept by AccountService as a private variable. Since the lifetime of this AccountService object persists throughout the HTTP session, I suppose the Depositor object that it keeps is used throughout the session. However, the scope of the Depositor class was supposed to be "request," i.e., instantiation for every request... I'm confused here, is a new Depositer object instantiated for every request? Or is the same Depositor object used throughout the session?
Spring uses Proxy pattern internally to solve this and create new instance for request scope bean inside session scoped bean, you know spring has access to every HttpServletRequest and you can even inject it in your class if you want. so it wraps the session scope bean with a proxy and when you reference request scope bean from the containing session scope bean if it is a new HttpServletRequest it will create new instance but if it is the same HttpServletRequest it returns the existing request scope bean.

Inject #Context values into regular beans

Is it possible to inject #Context values into regular spring beans (not Jax-Rs resources or providers)?
JERSEY-469 would suggest it can be done, but when I view it in debugger the fields are null (I'm checking this well after creation, this is not a problem with InitializingBean, I can't get the field injected at all).
#Component
#Scope("prototype")
public final class TaskDO {
#Context private ResourceContext resourceContext;
#FormParam("xml") private String xml;
}

How to send same headers for whole Spring Framework controller?

Specifically, I want whole controlerer to send "Access-Control-Allow-Origin=*".
I've tried below but that doesn't seem to work:
#Controller
#RequestMapping(value = "/controller/base", headers="Access-Control-Allow-Origin=*")
public class UserController {
#RequestMapping(method = RequestMethod.GET, value = "/blah", produces = application/json")
#ResponseBody
public Map blah(/*...,*/ HttpServletResponse response, HttpServletRequest request) throws Exception {
//...
}
}
It only work when I explicitly set (in all methods) like that:
response.addHeader("Access-Control-Allow-Origin", "*");
Any way to somehow set this for one or more controllers in a single place?
As far as I know there is no way to intercept all methods of a controller from the controller itself (except for ugly hacks such as using #InitBinder).
However, you can create a HandlerInterceptor and apply it to the base URL of your controller. For example, using #EnableMvc:
#Configuration
#EnableWebMvc
public class MyWebConfiguration extends WebMvcConfigurerAdapter {
...
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(...).addPathPatterns("/controller/base/**");
}
...
}
Consider using the #ControllerAdvice annotation introduced in Spring 3.2, combined with #InitBinder.
"Classes annotated with #ControllerAdvice can contain #ExceptionHandler, #InitBinder, and #ModelAttribute methods and those will apply to #RequestMapping methods across controller hierarchies as opposed to the controller hierarchy within which they are declared. #ControllerAdvice is a component annotation allowing implementation classes to be auto-detected through classpath scanning."
Set the response header in the method annotated with #InitBinder.
Annotate the class with #ControllerAdvice to have it process the #InitBinder globally.

SpringMVC #Scope session not creating threads

Say I have the following class...
#Controller
public class WebController {
#Autowired PersonService personService;
#RequestMapping(value = "/get", method = RequestMethod.GET)
#ResponseBody
#Scope("session")
public List<Player> getPerson(String personName) {
return playerService.getByName(personName);
}
}
Now this invokes the following service...
#Service("playerService")
public class PlayerServiceImpl implements PlayerService {
private List<Player> players;
#Override
#Transactional
public List<Player> getByName(final String name) {
if (players == null) {
players = getAll();
}
return getValidPlayers(name);
}
If I initially start my application, players is null, correctly, then when in the same session, I invoke this method again with a new value, players is no longer null, as you would expect. However, no new thread appears to be being created, if I open a new browser window (therefore creating a new session) and invoke this method, it still has the values from the previous session.
Why is #Scope("session") not creating a new thread in the thread pool?
I've specified <context:component-scan base-package="com." /> in my servlet-context as expected, everything works fine apart from the service methods are all acting as singletons rather than creating a new thread per session like say a Java EE container.
If players was marked as static I'd understand.
I've also tried marking my controller as #Scope("session") (as shown below) but this appears to have no impact either. What's the best way to make my Spring app create a new thread for a new session?
#Controller
#Scope("session")
public class PlayerController {
You are using #Scope annotation the wrong way.
Quoting the docs:
When used as a type-level annotation in conjunction with the Component annotation, indicates the name of a scope to use for instances of the annotated type.
When used as a method-level annotation in conjunction with the Bean annotation, indicates the name of a scope to use for the instance returned from the method.
So you can annotate either a spring component bean or a method that creates a bean if you're using java config. Java config is the only reason it even compiles (it wouldn't in pre 3.0 spring)
In your case that annotation is on a normal bean method where it doesn't mean anything.
Solving the right problem
It looks like you're trying to implement db cache by storing query results in a List<Player> players.
Don't do that. Use one of the prebuilt cache abstractions (spring has a very nice one) instead.
So where should #Scope go?
Annotating #Controller with #Scope("session") won't help as it will create session scoped controllers but the service they have injected is still a singleton.
Annotating only Service bean won't work either, cause #Controller is a singleton and it's dependencies are autowired on application startup.
Annotating both #Service and #Controller might work, but seems a bit heavy handed.
It's better to avoid state at all.
New threads are created for each request.
Your service has an instance variable (players) which is not threadsafe - it is shared by all threads. Any spring bean - including controllers and services are by default a singleton, you need to specify on the service annotation its scope.
#Service("playerService")
#Scope("session")
public class PlayerServiceImpl
But its best(simpler, easier to scale) to keep beans singletons and not rely on instance variables (unless they are also managed by spring/threadsafe/singletons).

#Autowired does not create members in constructor

I have a bean that is created from context, after which a autowired member is created:
#Service
public class FileDownloadService extends WFWFileDownloadService {
#Autowired
ConfigurationManager configurationManager;
When I use in code manual constructor call:
FileDownloadService fileDownloadService = new FileDownloadService();
I see configurationManager is null, so I have to make manual wiring:
public FileDownloadService() {
configurationManager = new ConfigurationManagerImpl();
}
What am I doing wrong to make autowiring working with manual creating?
When you call the constructor directly, you're just creating an object and not a bean. The support of the #Autowired annotation is a feature of bean.
Ask the Spring context for the bean.
If you attempt to get the bean by using new operator, you will get all autowired beans inside that class as null.
Your service class is annotated with #Service, so to use it you should autowire this service class also.
Sample code to access service bean in other classes is :
#Controller or #Component
public class OtherClass {
#Autowired FileDownloadService fileService;
public void download() {
fileService.downloadFile();
}
}
In order this class to be able to autowire other beans, this class itself should be annotated with #Controller or #Component.
The Answer is simple:
If you manually create the Object, there is no wiring involved. How should Spring know, that you are in need for wiring? Instead of using new, you could use the getBean() method of the application context (Bean Factory). http://static.springsource.org/spring/docs/current/javadoc-api/index.html?org/springframework/beans/factory/BeanFactory.html
http://static.springsource.org/spring/docs/current/javadoc-api/index.html?org/springframework/beans/factory/BeanFactory.html

Categories