Spring #Autowired not working with DWR - dwr

Here is my service layer:
#Service
#RemoteProxy
public class ReturnToDWR{
#Autowired
private DAOLayer daoLayer;
#RemoteMethod
public List<String> returnRecord(String id){
List<String> list = daoLayer.returnPendingRecords(id);
return list;
}
}
DWR configuratin setting in applicationContext.xml file:
<dwr:configuration />
<dwr:controller id="dwrController" debug="true" />
<bean id="returnToDWR" class="com.service.ReturnToDWR">
<dwr:remote javascript="returnToDWR">
<dwr:include method="returnRecord" />
</dwr:remote>
</bean>
When i am calling returnRecord() from my Controller, it is working. But when i am calling same method from jsp using DWR it shows me NullPointerException on List<String> list = daoLayer.returnPendingRecords(id); line.
I think spring is unable to autowire private DAOLayer daoLayer; in the case of DWR.
Please tell me how can i fix my code to work with DWR?
Thanks
Shams

When you place a brakepoint on that line, can you see in the debugger, that value of daoLayer is really null? Isn't it possible that the id value is null and that causes that NullPointerException inside the returnPendingRecords method?

Related

Mixing <mvc:annotation-driven conversion-service with #Autowired dependency coming back as null

I have a spring mvc 3.0 web application and am using a conversion-service as follows...
<bean id="applicationConversionService"
class="com.myer.reporting.converter.ApplicationConversionServiceFactoryBean"/>
<context:component-scan base-package="com.myer.reporting.controller" />
<context:component-scan base-package="com.myer.reporting.manager" />
<context:component-scan base-package="com.myer.reporting.dao"/>
<context:component-scan base-package="com.myer.reporting.dao.mapper"/>
<mvc:annotation-driven conversion-service="applicationConversionService"/>
In my controllers when i use the conversion service it all works fine.
#Autowired
private ApplicationConversionServiceFactoryBean applicationConversionService; '
But for the first time I am now trying to use the applicationConversionService in my mapper using the same method but the applicationConversionService is always coming back as null.
package com.myer.reporting.dao.mapper;
public class ImportHistoryRowMapper implements RowMapper<ImportHistory> {
private static final String BUSINESS_DATE = "businessdate";
private static final String TOTAL_TRAN_COUNT = "total_tran_count";
#Autowired
private ApplicationConversionServiceFactoryBean applicationConversionService;
public ImportHistory mapRow(ResultSet rs, int rowNum) throws SQLException {
Date businessDate = rs.getDate(BUSINESS_DATE);
Integer totalTranCount = rs.getInt(TOTAL_TRAN_COUNT);
ImportHistory importHistory = new ImportHistory();
importHistory.setBusinessDate(businessDate);
importHistory.setTransactionCount(totalTranCount);
// status
TrafficLightStatus status =
applicationConversionService.
getImportThresholdToStatusConverter()
.convert(totalTranCount);
importHistory.setStatus(status);
return importHistory;
}
}
I tried to add #Component to the top of the class but that doesn't seem to work either. I think I am lacking some understanding of the #Autowired annotation and therefore can't get this to work.
Can someone give me some advice on this please.
thanks
You need to make the ImportHistoryRowMapper spring managed for this to work.
I believe your dao class making the reference to this mapper class is singleton. For every request (i.e., call to method getJdbcTemplate().query ( sql, object array, new instance of ImportHistoryRowMapper);), you need to create new instance of ImportHistoryRowMapper i.e., it should be prototype.
You can inject prototype bean into singleton in 2 ways:
1) Lookup Method injection
2) Scoped proxies
Take a look at this.

Inject properties via annotation

I am new for spring security. I've seen many posts on how to inject values via annotation from external property file. I've tried many ways, but I always end up with java.lang.IllegalArgumentException: Could not resolve placeholder 'val.id' exception.
Can you provide me some tips how to handle this exception please?
My java class is the following one:
#Controller
public class Employee {
#Value("${val.id}")
public String valId;
public String getValId() {
return valId;
}
public void setValId(String valId) {
this.valId = valId;
}
My property file is called val.properties which is located under WEB-INF, and its content is
val.id=xyz
I put the following in my main context bean.
<context:property-placeholder location="/WEB-INF/*.properties" />
<bean id="valProp" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/val.properties"/>
A continuous question:
The injecting values from properties file to annotated beans works fine as I accepted the answer above. However, I cannot able to inject it to #PreAuthorize(...) annotation by following the same procedure.
Assume I want to secure a method called 'update'. This method is allowed if and only if valId is equal to empId. values of valId and empId are initialized in the val.properties file.
my java bean is:
public class Employee {
public String valId;
public String empId;
public String getValId() {
return valId;
}
public void setValId(String valId) {
this.valId = valId;
}
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
}
my property file contains:
val.id=nn
emp.id=nn
I have the place holder configuration in my main context file:
<context:property-placeholder location="/WEB-INF/*.properties" />
<bean id="valProp" class="org.springframework.beans.factory.config.PropertiesFactoryBean"
p:location="/WEB-INF/val.properties"/>
My PreAuthorize annotation (method security) is:
#PreAuthorize("(#{valProp['val.id']} == #{valProp['emp.id']})")
public boolean update(){
//if accessable
return true;
}
But the expression #{valProp['val.id']} == #{valProp['emp.id']} is not evaluated.
Did I do any mistake to inject values? It was worked when I annotate member variables, but it doesn't work here. Any idea please? Thanks in advance.
try to consider the following
1). change your annotation to:
#Value("#{valProp['val.id']}")
2). Replace PropertyPlaceholderConfigurer by PropertiesFactoryBean.
Hope this will resolve the exception.
The reason why the exception is thrown is, because the property placeholder by default throws an exception when a values cannot be resolved.
Furthermore you have two property placeholders, via which probably not all values can be resolved.
You can change this behaviour via setting the ignore-unresolvable property:
<context:property-placeholder location="/WEB-INF/*.properties" ignore-unresolvable="true" />
<bean id="valProp" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/val.properties" p:ignoreUnresolvablePlaceholders="true" />
Note however that b< turning off this feature typos in a property file will not be detected.

Using session attributes in spring MVC

I am developing a web application using spring MVC. I just want a simple example of how to do session management in this. I have seen lot of forums but I am not able to get a clear picture of this
My requirement is
I have an object, which I would like to be accessible in all controllers and JSP's I
would like to set that in the controller and get that in JSP
I am looking for something like
Session.setAtribute();
Could you please let me know a very simple instance . Thank you
There are different ways of accessing servlet session in Spring MVC. But I think this one is the one that best suits your problem. You can create a session scoped bean, which holds your desired info:
#Component("myObjectHolder")
#Scope(WebApplicationContext.SCOPE_SESSION)
public class MyObjectHolderImpl implements MyObjectHolder {
private long userId;
private String username;
private Theme theme;
// Getters & Setter
}
Then, you can access to it from other beans:
#Controller
public class MyController {
#Autowired private MyObjectHolder myObjectHolder;
#RequestMapping
public ModelAndView switchTheme(String themeId) {
...
Theme newTheme = themeService.get(themeId);
myObjectHolder.setTheme(newTheme);
...
}
}
You can access directly from your view too, but you must configure it:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
...
<property name="exposedContextBeanNames" value="myObjectHolder" />
</bean>
And in your JSP:
Hi ${myObjectHolder.username}, you switched
application theme to ${myObjectHolder.theme.name}
The simplest approach is to access HttpSession directly by injecting it into your handler method:
#RequestMapping("/page")
public ModelAndView page(HttpSession session) {
session.getAttribute("foo");
}

Internationalized drop downs using Spring 3

Story
I have a select control that represents user access level. I'm looking for a way to internationalize it. The label should be loaded from a message resource and the value should be used as is. I prepare all my drop down lists in controllers using a simple SelectOption class that has a label and a value properties. This way, my select's look consistent accross all jsp's.
Problem
I've found some examples but they are based on logic within jsp. Developer loops through his labels and manually constructs the option tag using a message resource. While this works, there just has to be a better way. I've also found some comments that Spring 3 will have support for internationalizing option labels but I can't find anything concrete on that.
Controller logic
Collection<SelectOption> optionList = new ArrayList<SelectOption>();
optionList.add(new SelectOption("-SELECT-", "-"));
optionList.add(new SelectOption("Administrator", "ADMIN"));
optionList.add(new SelectOption("Editor", "EDIT"));
bean.setFilterUserAccessLevelOptionList(optionList);
JSP logic
<form:select path="filterUserAccessLevel" items="${bean.filterUserAccessLevelOptionList}" itemLabel="label" itemValue="value"/>
Questions
I would like to add options in my controller in this way: optionList.add(new SelectOption("userAccessLevelAdministratorLabel", "ADMIN")); and have Spring convert userAccessLevelAdministratorLabel to a value from a message resource. Is this possible?
If Spring 3 cannot do this for me, how else can this be achieved without manually constructing the option tag within jsp?
=== 2012-01-15 ==============================================================
Still trying to work out a solution using aweigold's idea.
Controller
#Controller
public class UserController {
#Autowired
private UserService userService;
#Autowired
SelectOptionListBuilder listBuilder;
#RequestMapping("/userIndex/{pageNumber}")
public ModelAndView getUserList(#PathVariable Integer pageNumber, #ModelAttribute("userIndexBean") UserIndexBean phantomBean, Locale locale, Model model) {
UserIndexBean bean = new UserIndexBean();
// prepare filter form
Collection<SelectOption> optionList = listBuilder.getUserAccessLevelOptionList(true, SortOrder.NONE, locale);
bean.setFilterUserAccessLevelOptionList(optionList);
SelectOptionListBuilderImpl
#Component
public class SelectOptionListBuilderImpl implements SelectOptionListBuilder, MessageSourceAware {
private MessageSource messageSource;
#Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
#Override
public List<SelectOption> getUserAccessLevelOptionList(boolean addSelectPrompt, SortOrder sortOrder, Locale locale) {
List<SelectOption> optionList = new ArrayList<SelectOption>();
if(addSelectPrompt) {
optionList.add(new SelectOption(messageSource.getMessage("common.selectPromptLabel", null, locale), "-"));
}
messageSource mapping
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/i18n/messages" />
<property name="defaultEncoding" value="UTF-8"/>
<property name="UseCodeAsDefaultMessage" value="true"/>
</bean>
Exception
org.springframework.context.NoSuchMessageException: No message found under code 'common.selectPromptLabel' for locale 'en_CA'
When I need to do operations like this in a Controller outside of a jsp, I've been making my Controllers MessageSourceAware. Spring will then inject a new MessageSource when they are swapped, and you can interrogate it much like Spring does. In your example, you would do something like this:
#Controller
public class someController implements MessageSourceAware {
private MessageSource messageSource;
#Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
#RequestMapping
// Pass in the locale from the LocaleResolver
public void someMapping(Locale locale){
optionList.add(new SelectOption(
messageSource.getMessage("userAccessLevelAdministratorLabel", null, locale),
"ADMIN"))
}
}
Have a look at a spring roo project. They managed this kind of problem by creating tagx tags. This tags do what you already descibed (it contains a litte logic to load the messages from ressources and build the option tags). But because the logic is witten once and you can use this tags like normal tags in you jspx files, it feels like a tag that do what you want to have.

Spring: Inject bean depended on context (session/web or local thread/background process)

Is it possible to create a factory or proxy that can decide if thread is running in (Web)Request or background-process (ie. scheduler) and then depending on that information, it creates a session bean or a prototype bean?
Example (pseudo Spring config :)
<bean id="userInfoSession" scope="session" />
<bean id="userInfoStatic" scope="prototype" />
<bean id="currentUserInfoFactory" />
<bean id="someService" class="...">
<property name="userInfo" ref="currentUserInfoFactory.getCurrentUserInfo()" />
</bean>
I hope this makes my question easier to understand...
My Solution
It's never to late to update own questions ;). I solved it with two different instances of client session, one SessionScoped client session and one SingletonScoped session. Both are normal beans.
<bean id="sessionScopedClientSession" class="com.company.product.session.SessionScopedClientSession" scope="session">
<aop:scoped-proxy />
</bean>
<bean id="singletonScopedClientSession" class="com.company.product.session.SingletonScopedClientSession" />
<bean id="clientSession" class="com.company.product.session.ClientSession">
<property name="sessionScopedClientSessionBeanName" value="sessionScopedClientSession" />
<property name="singletonScopedClientSessionBeanName" value="singletonScopedClientSession" />
</bean>
The ClientSession will then decide if singleton or session scope:
private IClientSession getSessionAwareClientData() {
String beanName = (isInSessionContext() ? sessionScopedClientSessionBeanName : singletonScopedClientSessionBeanName);
return (IClientSession) ApplicationContextProvider.getApplicationContext().getBean(beanName);
}
Where session type could be gathered through this:
private boolean isInSessionContext() {
return RequestContextHolder.getRequestAttributes() != null;
}
All the classes implement a interface called IClientSession. Both singletonScoped and sessionScoped beans extends from a BaseClientSession where the implementation is found.
Every service then can use the client session ie:
#Resource
private ClientSession clientSession;
...
public void doSomething() {
Long orgId = clientSession.getSomethingFromSession();
}
Now if we go one step further we can write something like a Emulator for the session. This could be done by initializing the clientSession (which is in no context of a request) the singleton session. Now all services can use the same clientSession and we still can "emulate" a user ie:
clientSessionEmulator.startEmulateUser( testUser );
try {
service.doSomething();
} finally {
clientSessionEmulator.stopEmulation();
}
One more advice: take care about threading in SingletonScoped clientSession instance! Wouw, I thought I could do it with less lines ;) If you like to know more about this approach feel free to contact me.
I created small universal workaround to inject beans depends on context.
Guess we have two beans:
<bean class="xyz.UserInfo" id="userInfo" scope="session" />
<bean class="xyz.UserInfo" id="userInfoSessionLess" />
We want to use "userInfo" bean for web user actions and "userInfoSessionLess" bean for background services for example.
Wa also want to write code and don't want to think about context, for example:
#Autowired
//You will get "java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request?" for session less services.
//We can fix it and autowire "userInfo" or "userInfoSessionLess" depends on context...
private UserInfo userInfo;
public save(Document superSecureDocument) {
...
superSecureDocument.lastModifier = userInfo.getUser();
...
}
Now we need create custom session scope to make it worked:
public class MYSessionScope extends SessionScope implements ApplicationContextAware {
private static final String SESSION_LESS_POSTFIX = "SessionLess";
private ApplicationContext applicationContext;
public Object get(String name, ObjectFactory objectFactory) {
if (isInSessionContext()) {
log.debug("Return session Bean... name = " + name);
return super.get(name, objectFactory);
} else {
log.debug("Trying to access session Bean outside of Request Context... name = " + name + " return bean with name = " + name + SESSION_LESS_POSTFIX);
return applicationContext.getBean(name.replace("scopedTarget.", "") + SESSION_LESS_POSTFIX);
}
}
private boolean isInSessionContext() {
return RequestContextHolder.getRequestAttributes() != null;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
Register new scope:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="mySession">
<bean class="com.galantis.gbf.web.MYSessionScope" />
</entry>
</map>
</property>
</bean>
Now we need modify beans definions like this:
<bean class="xyz.UserInfo" id="userInfo" scope="mySession" autowire-candidate="true"/>
<bean class="xyz.UserInfo" id="userInfoSessionLess" autowire-candidate="false"/>
That's all. Bean with name "SessionLess" will be used for all "mySession" scoped beans if we use bean outside of actual web request thread.
Your rephrase is indeed considerably simpler :)
Your currentUserInfoFactory could make use of RequestContextHolder.getRequestAttributes(). If a session is present and associated with the calling thread, then this will return a non-null object, and you can then safely retrieve the session-scoped bean from the context. If it returns a null, then you should fetch the prototype-scoped bean instead.
It's not very neat, but it's simple, and should work.
Create two custom context loaders that bind the same scope defintion to different implementations:
public final class SessionScopeContextLoader extends GenericXmlContextLoader {
protected void customizeContext(final GenericApplicationContext context) {
final SessionScope testSessionScope = new SessionScope();
context.getBeanFactory().registerScope("superscope", testSessionScope);
}
...
}
Then you make a corresponding one for singleton (make your own scope with just statics)
Then you just specify the appropriate context loader in the xml startup for each of the two contexts.

Resources