'Reset' scoped session bean using Spring - spring

I have a webservice with a session bean like that;
#Scope(value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES)
private DocumentModel docModel;
I want to maintain the state of all objects inside DocumentModel during a process and when it is over reset that object, because I don't want that the sessions keeps all the data related with that object generated during the previous process. Is possible do that in some way different than put a docModel.reset() than set all the objects inside it to null?
Thanks

Related

Spring #SessionAttribute and session.getAttribute clash

I am experiencing a weird issue using spring mvc and session items.
We have a controller class annotated as follows:
#SessionAttributes({"customerPosition"})
according to the Spring doc, if I put into the model an object with the key customerPosition it gets automatically put into the session.
When I "manually" set the item with session.setAttribute("customerPosition",customerPosition) I exepect the item to be saved in session. if I get this item from the session by means of session.getAttribute("customerPosition") I get a different Item, not the one I expect. Actually what I get is data from previous iterations of the software flow.
It looks like that session.setAttribute("customerPosition",customerPosition) is not overwriting the object in session.
Does using #SessionAttributes prevents the possibility to manually control the session by means of session.setAttribute("customerPosition", customerPosition)

Storing session-scope beans in #controller

I am trying to store my session-scoped user beans in a singleton-scoped controller throughout their lifecycle in session. So whenever a user is being connected, I want to store it in an array with the rest of the users those who keep their sessions.
I know about injecting a session-scoped bean into a #Controller through proxy beans so that i have defined my session-scoped user beans as follow,
#Bean
#Scope(value="session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public IUser user ()
{
IUser user = new MyUser();
return user;
}
I have used #Autowire annotation to inject that bean into my controller class as below,
#Autowired
private IUser sessionUser;
So whenever a user is getting connected, I am storing that user in a ConcurrentHashMap which is defined and added as below,
private ConcurrentHashMap<Integer,IUser> userMap = new ConcurrentHashMap<>(50,0.9f,2);
public void addUser(IUser user)
{
if(user == null) return;
IUser retUser = userMap.putIfAbsent(user.getDbid(),user);
//...
}
So everything is working when the first user gets connected, I store its reference to map. Let's assume first user reference is
us.com.soemthing.orm.model.MyUser#135debf
Then let us assume the second user gets connected whose reference is,
us.com.soemthing.orm.model.MyUser#28zbdh
From the references, I can see that my session-scoped beans work fine as their reference is different. However, problems start when execution goes into addUser method. Even before adding the second user to the map, I check my userMap and see that user object it is storing replaced with the second one which is MyUser#28zbdh. So at the end, after adding the second user, My user map looks like this,
Map --> "1"- us.com.soemthing.orm.model.MyUser#28zbdh
Map --> "2"- us.com.soemthing.orm.model.MyUser#28zbdh
So that references are being updated always with the last one. I know that they are the proxy object to real objects but how I can store them?
Thanks
[EDIT] I wanted to provide additional information.
I am calling addUser from another singleton bean as, userInDBMemory.addUser(sessionUser); userInDBMemory is another singleton bean where i add my session user to a ConcurrentHashMap actually. I want to store my current online users on a map as I would like to search and query them without going to the database. So i would like to keep online users (who has a session in context) in memory for easier and faster access. To handle session expires, every online user sends a heartbeat to server to show he is online, I have a scheduled thread on server running in every X minutes and if it finds any user who didn't get heartbeat from the user for a while then it removes it from the map as it means user went offline. To summary my case I have a main controller where i get requests then the chain is like this: #Controller->singleton application bean->Singleton inMemoryDB bean (where I define my map and add user) My SessionUser session-scoped bean is #Autowired in #Controller and i pass it to other singleton beans as a parameter.Thanks for the response.
I have solved my problem by not storing session-scoped beans directly but their object copies.
//IMyUser sessionUser; --let say sessionUser is session-scoped bean in a singleton bean
so instead of ;
userInDBMemory.addUser(sessionUser);
I have copied the user first and added that object instead.
IMyUser copyUser = new MyUser();
BeanUtils.copyProperties(sessionUser, copyUser);
userInDBMemory.addUser(copyUser);

Add dynamically created String into Spring Context

I am creating a String based on some input parameters when a rest call is executed. I have created my own Annotation to intercept certain methods which will be called later on (within the same request). The Interceptor needs to know the String created at the beginning. My initial thought was to add the String into the Spring context like this:
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) context).getBeanFactory();
beanFactory.registerSingleton("myValue", "generatedString");
And just inject it to the interceptor. However i can only add it once this way and i really dont want it to be a singleton. Each request has its own "generatedString". I could not find a suitable way of solving this. What i actually want is to register an object on runtime for the current thread so i can inject it later on. When the Thread is done it should disappear.

Spring: new() operator and autowired together

If I use Spring, which of these two methods is more correct.
Can I use the new() operator even if I use dipendency injection?.Can I mix both?
I would like to have some clarification on these concepts.
Thanks
First method:
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(new User());
return "index";
}
Second Method:
#Autowired
User user;
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(user);
return "index";
}
By using dependency injection does not mean that the use of new operator is automatically prohibited throughout your code. It's just different approaches applied to different requirements.
A web application in spring is composed of a number of collaborating beans that are instantiated by the framework and (unless overriding the default scope) are singletons. This means that they must not preserve any state since they are shared across all requests (threads). In other words if you autowire the User object (or any other model attribute), it is created on application context initialization and the same instance is given to any user request. This also means that if a request modifies the object, other requests will see the modification as well. Needless to say this is erroneous behavior in multithreaded applications because your User object (or other model attribute) belongs to the request, so it must have the very narrow scope of a method invocation, or session at most.
You can also have spring create beans with different scopes for you, but for a simple scenario of a model attribute initialization, the new operator is sufficient. See the following documentation if interested in bean scopes : Bean scopes
So in your use case, the second method is totally wrong.
But you can also delegate the creation of your model attributes to spring if they are used as command objects (i.e. if you want to bind request parameters to them). Just add it in the method signature (with or without the modelattribute annotation).
So you may also write the above code as
#RequestMapping(method=RequestMethod.GET)
public String create(#ModelAttribute User user){
return "index";
}
see also : Supported method argument types
If you want your beans to be "managed" by Spring (for e.g. to use with Dependency Injection or PropertySources or any other Spring-related functionality), then you do NOT create new objects on your own. You declare them (via XML or JavaConfig) and let Spring create and manage them.
If the beans don't need to be "managed" by Spring, you can create a new instance using new operator.
In your case, is this particular object - User - used anywhere else in code? Is it being injected into any other Spring bean? Or is any other Spring bean being injected in User? How about any other Spring-based functionality?
If the answer to all these questions is "No", then you can use the first method (create a new object and return it). As soon as the create() method execution is complete, the User object created there would go out of scope and will be marked for GC. The User object created in this method will eventually be GC-ed.
Things can be injected in two ways in a Spring MVC applications. And yes, you can you can mix injection and creation if doing right.
Components like the controller in your example are singletons managed by the application context. If you inject anything to them it is global, not per request or session! So a user is not the right thing to inject, a user directory can be. Be aware of this as you are writing a multithreaded application!
Request related things can be injected to the method like the used locale, the request, the user principal may be injected as parameters, see a full list at Spring MVC Documentation.
But if you create a model attribute you may use new() to create it from scratch. I will not be filled by spring but to be used by your view to display data created by the controller. When created in the request mapped method that is ok.

How to prevent #ModelAttribute from creating command objects from request parameters?

I.e. I only want a nice way to retrieve existing objects from my Model (mostly some SessionAttributes).
I don't want new objects to be created and I especially don't want objects to be instantiated from request parameters and put into the model. This just sounds like a back door to me.
It would also be great if an Exception can be thrown if no matching parameter is in the model.
I got the answer to this by reading the source code. According to the implementation of org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveModelAttribute, a new bind Object will not be created if the name of the model attribute is declared as a session attribute using the #SessionAttributes annotation.
If the attribute is not present in the session, an Exception will be thrown.
So it is relatively safe to bind session attributes this way.

Resources