#ExceptionHandler annotation in controller does not catching MaxUploadSizeExceededException - spring

I'm trying a very straightforward thing - catching the MaxUploadSizeExceededException errors associated with file uploads.
Here's the relevant bit in my spring-servlet.xml :
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000" />
</bean>
And here's the #ExceptionHandler method in the controller that also handles the file upload stuff
#ExceptionHandler(MaxUploadSizeExceededException.class)
public String handleException(MaxUploadSizeExceededException e, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("uploadErrorMessage", e.getCause().getMessage());
return "redirect:/page";
}
File upload is working fine. However, when I test with a file that exceeds the size limit - it throws the error, and the method for ExceptionHanler is never called.
Any help or pointers on what else to look for / at would be greatly appreciated.

Can you try changing the ExceptionHandler to look for LimitExceededException and MultiPartException instead of the sub Exceptions?

Try creating a separate class with #ControllerAdvice this will then take care of exception coming from all controllers.
#ControllerAdvice
public class ExceptionControllerAdvice {
#ExceptionHandler(MaxUploadSizeExceededException.class)
public String handleException(MaxUploadSizeExceededException e, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("uploadErrorMessage", e.getCause().getMessage());
return "redirect:/page";
}
}
Thus if we define our #ExceptionHandler annotation on method in #ControllerAdvice class, it will be applied to all the controllers.
You must define following in your spring-servlet.xml file.
<mvc:annotation-driven/>

Related

Is my app's Controllers thread safe ? Spring 4.1

I am developing an app in spring 4.1 . I know that Controllers / any other bean in spring are not thread safe . ie: Singleton. That mean same instance of Controller will be used to process multiple concurrent requests. Till here I am clear . I want to confirm that do I need to explicitly set #Scope("prototype") or request in the Controller class ? I read on StackOverflow previous post that even if scope is not set as request/prototype , Spring container will be able to process each request individually based on #RequestParams passed or #ModelAttribute associated with method arguements .
So i want to confirm is my below code is safe to handle multiple request concurrently ?
#Controller
public class LogonController {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
#Autowired
SimpleProductManager productManager;
#Autowired
LoginValidator validator;
#RequestMapping( "logon")
public String renderForm(#ModelAttribute("employee") Logon employeeVO)
{
return "logon";
}
#RequestMapping(value="Welcome", method = RequestMethod.POST)
public ModelAndView submitForm(#ModelAttribute("employee") Logon employeeVO,
BindingResult result)
{
//Check validation errors
validator.validate(employeeVO, result);
if (result.hasErrors()) {
return new ModelAndView("logon");
}
if(!productManager.chkUserValidation(employeeVO.getUsername(), employeeVO.getPassword())){
return new ModelAndView("logon");
}
ModelAndView model = new ModelAndView("Welcome");
return model ;
}
}
Also i have another doubt.
since i am using SimpleProductManager productManager; Do i need to specify scope="prototype in its bean declaration in app-servlet.xml ?
Below is my configuration.xml
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource"><ref bean="dataSource"/></property>
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<bean id="productManager" class="com.BlueClouds.service.SimpleProductManager" >
<property name="productDao" ref="productDao"/>
</bean>
<bean id="productDao" class="com.BlueClouds.dao.HbmProductDao">
<property name="sessionFactory"><ref bean="mySessionFactory"/></property>
</bean>
<bean id="loginValidator" class="com.BlueClouds.service.LoginValidator" >
</bean>
Being singleton single instance of validator is being shared among all request , for that do i need to add scope=request in bean configuration xml or do i need to surround validate() in synchronized block ? Please advise.
Thanks much .
You can tell your code is thread safe or not by answering following questions
Are there threads might modify a static field, which is not thread safe(ex: arrayList), in the same time?
Are there threads might modify a field of an instance, which is not thread safe, in the same time?
If any answer of the above is yes, then your code is not thread safe.
Since your code doesn't change any field, so it should be thread safe.
The general idea about thread safe is that if there are threads might change/access the same memory section in the same time, then it's not thread safe, which means "synchronized" is needed.
You'd better learn more about stack memory, heap memory and global memory in JAVA. So that you can understand if your code changes the same memory section in the same time or not.

cxf out interceptor - reference to response pojo object

I need to get the response Java object that is returned from my service for some processing of the data. I don't want to write the code to process this data in the ServiceImpl class itself since I want to keep it configuration based. I have written the out interceptor.
As per answer to this question , the POJO object should be available in the out interceptor, however I see that the object is actually an intermediate class of response. I get a ClassCastException with the code mentioned in above link.
Am I missing something? Can the same POJO object returned by Service class be available in the Out interceptor?
Any other approach to accomplish this is also welcome.
MyOutInterceptor.java:
public class MyOutInterceptor extends AbstractPhaseInterceptor<Message> {
public MyOutInterceptor() {
super(Phase.MARSHAL); // Tried Phase.PRE_LOGICAL as well
}
public void handleMessage(Message message) throws Fault {
MessageContentsList objs = MessageContentsList.getContentsList(message);
if (objs != null && objs.size() == 1) {
Object responseObj = objs.get(0);
MyData data = (MyData) responseObj; // fails here with ClassCastException
...
}
applicationContext.xml
<bean class="com.xyz.interceptor.MyOutInterceptor" id="outInterceptor" />
<jaxws:endpoint id="dataService" implementor="#masterDataService" address="/MasterDataService">
...
<jaxws:outInterceptors>
<ref bean="outInterceptor" />
</jaxws:outInterceptors>
</jaxws:endpoint>
Pre-logical phase will work, but you would need to do an:
addBefore(WrapperClassOutInterceptor.class.getName());
to make sure it's run before that interceptor.

How do I use Spring/JUnit to verify a controller is not sending me to a non-existent view?

I'm using Spring 3.1.1.RELEASE and JUnit 4.11. I setup my JUnit tests like so
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MySpringTest
{
protected MockHttpServletRequest request;
protected MockHttpServletResponse response;
protected MockHttpSession session;
#Autowired
protected RequestMappingHandlerAdapter handlerAdapter;
#Autowired
protected RequestMappingHandlerMapping handlerMapping;
When testing controllers, I have this line to verify that the view the controller's method is returning is the right view …
import static org.springframework.test.web.ModelAndViewAssert.assertViewName;
...
final ModelAndView mav = submitMyForm(…);
assertViewName(mav, "folder/myView");
...
protected ModelAndView submitMyForm(… params ...) throws Exception {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
request.setRequestURI("/myurl");
request.setMethod("POST");
request.addParameter("param1", param1);
...
final Object handler = handlerMapping.getHandler(request).getHandler();
return handlerAdapter.handle(request, response, handler);
}
My question is, once I verify the view returned my the controller is the expected view, how do I verify it won't result in a 404? The main problem I'm gaving now is testing whether or not the view actually maps to an underlying page in my WAR file.
why don't use spring-mvc-test and do something like this ?
#Autowired
private ViewResolver viewResolver;
// code
View view = viewResolver.resolveViewName(viewName, locale);
//assert view not null
or something like this, in wich you can check both if the view is ok and the returned status (is status 200/404?)
(more code here: http://goo.gl/fMqBsl)
#Test
public void indexTest() throws Exception {
mockMvc.perform(get("/")).andDo(print())
.andExpect(handler().handlerType(MainController.class))
.andExpect(handler().methodName("index"))
.andExpect(view().name("index"))
.andExpect(forwardedUrl("/WEB-INF/tiles/template.jsp"))
.andExpect(status().isOk());
}
i am using standard jsp view
basically, you need to know the view resolver(s). can a specific view be resolved? that means, if you DON'T have a file called abc.xml, it might still be a valid view.
for simplicity sake, lets assume that we have only one view resolver, and, its
"org.springframework.web.servlet.view.UrlBasedViewResolver"
and here is the bean definition
spring 3.2.4 documentation pdf, page 477
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
eg: the view name "page1" => /WEB-INF/jsp/page1.jsp and "admin/page2" => /WEB-INF/jsp/admin/page2.jsp
using this, you can Inject the view resolved to your junit test using #Autowired and/or #Qualifier
then read the "prefix" and suffix value and find the full path like "src/main/webapp/" + prefix + viewname + suffix
and check if the file exists.
you may have multiple view resolvers, so you may want to inject the context and handle the view => filename resolution using a strategy pattern.
something like
foreach resolver
{
if i can resolve the view to a file (resolver type, viewname)
return the physical filename
else
try next resolver
}

Spring HTTP cache management

I've seen that you can control cache http headers with the AnnotationMethodHandlerAdapter bean.
My problem is that I need to have a fine grane control on the cache (at method level).
The best think would be to have something like an annotation like "#RequestCache(expire=60)".
Is there anything like this?
What is the best way to accomplish this task?
Thanks,
Andrea
Update:
pap suggest to use an HandlerInterceptor, but I've seen multiple forum's post saying that it's not possible to get the target method inside an HandlerInterceptor and suggest to use regular AOP instead (not specifically for caching).
The problem is that I don't want to add the request parameter to all my methods, only to make it accessible to the aspect. Is there a way to avoid this?
You can use the following approach described in
Spring mvc reference manual
Support for the 'Last-Modified' Response Header To Facilitate Content Caching
#RequestMapping(value = "/modified")
#ResponseBody
public String getLastModified(WebRequest request) {
if (request.checkNotModified(lastModified.getTime())) {
logger.error("Was not modified.");
return null;
}
logger.error("Was modified.");
//processing
return "viewName";
}
One way (that I have used myself) is to create your own HandlerInterceptor.
public class CacheInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
Class<?> o = AopUtils.getTargetClass(handler);
if (o.isAnnotationPresent(RequestCache.class)) {
response.setDateHeader("Expires", o.getAnnotation(RequestCache.class).expire());
}
return true;
}
...
}
and then
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<array>
<bean class="bla.bla.CacheInterceptor " />
</array>
</property>
</bean>

Spring MVC: a better way to get localized messages from within controller method?

I have a Spring controller it needs to set a message in the request scope and sends the user back to a form because of errors. Here is the method signature:
public String update(HttpServletRequest request,
Model model,
#ModelAttribute("command") User user,
BindingResult result, SessionStatus status)
In the method the request object is available, here is my way of setting a message in the request scope, which I feel is convoluted.
.....
WebApplicationContext ctx = RequestContextUtils.getWebApplicationContext(reque st);
Locale locale = RequestContextUtils.getLocale(request);
request.setAttribute("formError", ctx.getMessage("errors.unique.value", new Object[]{new DefaultMessageSourceResolvable(new String[]{"label.userName"})}, locale));
.......
Here are my questions:
Is the above way correct for setting a message?
Is any better or simpler way?
Thanks for help!
Are you trying to give a feedback to the user? Then you should have a look at result.rejectValue(field, property)
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/validation/Errors.html#rejectValue%28java.lang.String,%20java.lang.String%29
Example:
if the field on which the validation didnt passed is called "new_password" and the language property is named "new_passwort_invalid" then you could handle it like this:
result.rejectValue("new_password", "new_passwort_invalid");
greets
(Even if the post is old, I hope this can be useful for others)
In servlet-context.xml configuration we declare the bean:
<beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<beans:property name="basename" value="/WEB-INF/locale/messages" />
<beans:property name="defaultEncoding" value="UTF-8" />
</beans:bean>
Then in controller we autowire the messageSource:
#Controller
public class SomeCtrl {
#Autowired
private MessageSource messageSource;
...
Finally in the action we can use the locale (by adding the locale formal parameter and using the message):
#RequestMapping(value="/doLogin", method=RequestMethod.POST)
#ResponseBody
public String tryLogin(
#ModelAttribute("loginBean") LoginBean loginBean,
BindingResult result, SessionStatus status,
Locale locale) {
....
....
String generalErrorMsg = messageSource.getMessage("login.generalError",new Object[] {}, locale);
....
....

Resources