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

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.

Related

Spring REST webservice serializing to multiple JSON formats

I have a Spring REST web service which populates a generic object based on data we have in a database, the goal is to have the users pass a parameter to the web service to to indicate the format they want the output to be in. Based on their input we will use the correct JSONSerializer to give them what they want.
I have set up my webservice as follows, in my spring-ws-servlet.xml I have set our company ObjectMapper to be used by the mvc:message-converters, I have also set it on the RestController so that it can adjust the ObjectMapper to register the serializer. It looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="endpoint" class="org.company.Controller">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
<bean id="jacksonObjectMapper" class="org.company.CompanyObjectMapper" />
</beans>
The controller looks like this:
#RestController
public class Controller {
private ObjectMapper objectMapper;
#RequestMapping(...)
public GenericObject getObject(#PathVariables ...) {
//Get Object from database, just creating an object for example
GenericObject object = new GenericObject();
//Based on the user input we will pick out
//a Serializer that extends JsonSerializer<GenericObject>
BaseSerializer serializer = getSerializer();
//Create a simpleModule and use it to register our serializer
SimpleModule module = new SimpleModule();
module.addSerializer(GenericObject.class, serializer);
//get module and register the serializer
ObjectMapper mapper = getObjectMapper();
mapper.registerModule(module);
return object;
}
public ObjectMapper getObjectMapper() {
return objectMapper;
}
public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
}
The issue is that when I publish my webapp, the first query works correctly, if I specify format=format1, I will get the output in format1. However, after that I can only receive format1. I may specify format=format2, but still get the output in format1. I believe the issue is that the ObjectMapper still has the module registered to it from the first query. I have read that I can avoid this problem by creating a new ObjectMapper every time, but I am not sure how to set that to be used by Spring when it outputs the JSON.
Could someone help me come up with a solution to either create a new ObjectMapper every time I run the code and set that ObjectMapper to the Spring rest service, or help me figure out how I can "unregister" any modules that are registered on the object mapper before setting the latest desired serializer?
An idea could be to create and configure all the mappers you need at startup time as a spring beans.
Then create the default object mapper that will work as a dispatcher for other object mappers (or as the fallback one), and it may be aware of the current http request.
You can register all the mappers in this object mapper, register this mapper to be used as the default one in spring.
Something like this maybe :
public class RequestAwareObjectMapper extends ObjectMapper{
private Map<String, ObjectMapper > mappers = new HashMap<>();
#Override
public String writeValueAsString(Object value) throws JsonProcessingException{
HttpServletRequest req = null;//get request from spring context, if any, this is a managed spring bean it wont be a prorblem
String param = null; // read the param from the query
ObjectMapper mapper = mappers.get(param);
if(mapper == null){
mapper = this;
}
return mapper.writeValueAsString(value);
}
public void registerMapper(String key, ObjectMapper mapper){...}
}
in this way you are not going to pollute your controller with references to the object mapper and you can carry on using #ResponseBody (thanks to #RestController)..
I am sure there's a cleaner way to achieve the same result integrating a similar solution in the spring flow, can't look on something better right now.
Create your customObjectMapper class and auto wire it to your controller using #Autowire annotation. You can then create different methods to create different formatted objects.
You can also send serialiser as parameters.
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
super();
super.setSerializationInclusion(JsonInclude.Include.ALWAYS);
super.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
..... etc.....
super.setDateFormat(df);
}
public byte[] generateJsonFormat1(Object value, BaseSerializer serializer) throws IOException, JsonGenerationException, JsonMappingException {
Hibernate4Module hm = new Hibernate4Module();
hm.configure(Hibernate4Module.Feature.USE_TRANSIENT_ANNOTATION, false);
hm.configure(Hibernate4Module.Feature.FORCE_LAZY_LOADING, false);
.....
.....
hm.addSerializer(Object.class, serializer);
return super.registerModule(hm).writeValueAsBytes(value);
}
public byte[] generateJsonFormat2(Object value, BaseSerializer serialiser) throws IOException, JsonGe nerationException, JsonMappingException {
SimpleModule sm = new SimpleModule();
sm.addSerializer(Object.class, serialiser);
return super.registerModule(hm).writeValueAsBytes(value);
}
}
Above code is a snippet from my own application. I hope it gives the idea.

How to use custom expressions in Spring Security #PreAuthorize/#PostAuthorize annotations

Is there a way to create more expressive statements in #Preauthorize blocks? Here's an example of something I find myself repeating, because the #Preauthorize is not terribly smart out of the box.
#RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public void deleteGame(#PathVariable int id, #ModelAttribute User authenticatingUser) {
Game currentGame = gameService.findById(id);
if(authenticatingUser.isAdmin() || currentGame.getOwner().equals(authenticatingUser)) {
gameService.delete(gameService.findById(id));
} else {
throw new SecurityException("Only an admin, or an owner can delete a game.");
}
}
What I would prefer is something like.
#RequestMapping(value = "{id}", method = RequestMethod.DELETE)
#Preauthorize(isAdmin(authenicatingUser) OR isOwner(authenicatingUser, id)
public void deleteGame(#PathVariable int id, #ModelAttribute User authenticatingUser, #ModelAttribute currentGame ) { //I'm not sure how to add this either :(
gameService.delete(gameService.findById(id));
}
Part of the problem is that I need to make a query to the database to fetch some of this stuff to verify permissions, such as querying the database to get a copy of the game, and then comparing the owner of the game to the person making the request. I'm not really sure how all of that operates within the context of a #Preauthorize annotation processor, or how I add things to the collection of objects made available in the #Preauthorize("") value attribute.
Since #PreAuthorize evaluates SpEl-expressions, the easiest way is just to point to a bean:
#PreAuthorize("#mySecurityService.someFunction()")
MySecurityService.someFunction should have return type boolean.
Spring-security will automatically provide a variable named authentication if you want to pass the Authentication-object. You can also use any valid SpEl-expressions to access any arguments passed to your secure method, evaluate regular expressions, call static methods, etc. E.g:
#PreAuthorize("#mySecurityService.someFunction(authentication, #someParam)")
1) First you have to reimplement MethodSecurityExpressionRoot which contains extra method-specific functionality. The original Spring Security implementation is package private and hence it is not possible to just extend it. I suggest checking the source code for the given class.
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
// copy everything from the original Spring Security MethodSecurityExpressionRoot
// add your custom methods
public boolean isAdmin() {
// do whatever you need to do, e.g. delegate to other components
// hint: you can here directly access Authentication object
// via inherited authentication field
}
public boolean isOwner(Long id) {
// do whatever you need to do, e.g. delegate to other components
}
}
2) Next you have to implement custom MethodSecurityExpressionHandler that will use the above defined CustomMethodSecurityExpressionRoot.
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
#Override
public void setReturnObject(Object returnObject, EvaluationContext ctx) {
((MethodSecurityExpressionRoot) ctx.getRootObject().getValue()).setReturnObject(returnObject);
}
#Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
3) Define expression handler bean in your context, e.g. via XML you can do it as follows
<bean id="methodSecurityExpressionHandler"
class="my.package.CustomMethodSecurityExpressionHandler">
<property name="roleHierarchy" ref="roleHierarchy" />
<property name="permissionEvaluator" ref="permissionEvaluator" />
</bean>
4) Register the above defined handler
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="methodSecurityExpressionHandler"/>
</security:global-method-security>
5) Then just use the defined expressions in your #PreAuthorize and/or #PostAuthorize annotations
#PreAuthorize("isAdmin() or isOwner(#id)")
public void deleteGame(#PathVariable int id, #ModelAttribute currentGame) {
// do whatever needed
}
And one more thing. It is not very common to use method level security to secure controller methods but rather to secure methods with business logic (a.k.a. your service layer methods). Then you could use something like the below.
public interface GameService {
// rest omitted
#PreAuthorize("principal.admin or #game.owner = principal.username")
public void delete(#P("game") Game game);
}
But keep in mind that this is just an example. It expects that the actual principal has isAdmin() method and that the game has getOwner() method returning username of the owner.
You could write your annotation something like:
#PreAuthorize("hasRole('ROLE_ADMIN') and hasPermission(#id, 'Game', 'DELETE')")
To get the hasPermission part working you need to implement PermissionEvaluator interface.
Then define an expression handler bean:
#Autowired
private PermissionEvaluator permissionEvaluator;
#Bean
public DefaultMethodSecurityExpressionHandler expressionHandler()
{
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
And inject in your security config:
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler" />
</global-method-security>

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 #Autowired not working with 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?

Resources