Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Spring initBinder for Handling Large List of Java Objects

DZone's Guide to

Spring initBinder for Handling Large List of Java Objects

Java developers face a slew of problems. Here's a look at probing a Spring MVC features that devs may require for apps.

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

Introduction:

In this blog, I will be explaining one of the most common problems Java developers face while developing Spring MVC application, but invest lot of time and efforts understanding the issue and fixing it as any site does not easily state the solution.

My intention here is to provide an understanding of a feature of Spring MVC which developers may need to fine tune for their applications.

Scenario:

In any typical web application where we need to submit the data (which is filled by the user on the browser) from client side to server side.

In a Spring MVC based web application, all the data which is submitted from the UI comes to the Controller classes where the request is mapped.

Sometimes what may happen is request is not reaching the controller methods and in your AJAX calls you may get an HTTP 404 response in your error handling block.

Developers try to investigate these sort of issues by putting a debug on the controller method or request interceptors(if you have one) or filters ,check the data which is sent through AJAX,check request mappings etc.

But none of the above approaches helps them to resolve the problem because you are getting 404 on the browser and everything else seems to be working fine.

Now next step you may try is putting a breakpoint in the DispatcherServlet code as this is the first entry point java class invoked by the Spring framework before executing interceptors/filters and controllers in the chain.

For details on how can we put a breakpoint in Spring's Dispatcher Servlet refer http://www.coderanch.com/t/605222/vc/Eclipse-IDE-set-break-Spring

And finally you figure out you are getting some exception as below

org.springframework.beans.InvalidPropertyException : 
Invalid property arraylist[256]' of bean class [packagename.ObjectClassName]: 
Index of out of bounds in property path arraylist [256]'; 
nested exception is java.lang.IndexOutOfBoundsException: Index: 256, Size: 256 
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:830)
at org.springframework.beans.BeanWrapperImpl.getNestedBeanWrapper(BeanWrapperImpl.java:574) 
at org.springframework.beans.BeanWrapperImpl.getBeanW rapperForPropertyPath(BeanWrapperImpl.java:551) 
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:911) 
at org.springframework.beans.AbstractPropertyAccessor .setPropertyValues(AbstractPropertyAccessor.java:7 6) 
at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:692) 
at org.springframework.validation.DataBinder.doBind(DataBinder.java:588) at org.springframework.web.bind.WebDataBinder.doBind( WebDataBinder.java:191)
at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:111) 
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodIn voker.doBind(AnnotationMethodHandlerAdapter.java:7 57) 
at org.springframework.web.bind.annotation.support.Ha ndlerMethodInvoker.doBind(HandlerMethodInvoker.jav a:805) 
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(Handler MethodInvoker.java:359) 
at org.springframework.web.bind.annotation.support.Ha dlerMethodInvoker.invokeHandlerMethod(HandlerMeth odInvoker.java:171)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(An notationMethodHandlerAdapter.java:436) 
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424) 
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790) 
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:669) at org.springframework.web.servlet.FrameworkServlet.d oPost(FrameworkServlet.java:585) at javax.servlet.http.HttpServlet.service(HttpServlet.java:763) at javax.servlet.http.HttpServlet.service(HttpServlet .java:856) at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1213) at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1154) at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:145) at org.springframework.web.filter.CharacterEncodingFi lter.doFilterInternal(CharacterEncodingFilter.java :88) at org.springframework.web.filter.OncePerRequestFilte r.doFilter(OncePerRequestFilter.java:76)

Looking at the exception you may figure out that Spring framework is trying to retrieve more than 255 objects and hence failing with IndexOutOfBoundsException.

You may be wondering why this is the case and how do I solve this?

Is this a problem with Spring framework or is the developer doing something wrong?

Well, the answer is no one is doing anything wrong and the framework is also working as intended.

These kinds of issues you may not face during initial development and testing because you will require large data sets to reproduce these kinds of issues.

Generally, you may face these issues in Data migration or pre-production environment where you have huge data sets.

Solution:

Before moving onto solution lets see why this happened and what is the root cause of the issue.

Issue is by default spring only maps only 255 objects to the java bean.

DataBinder.html # setAutoGrowCollectionLimit (int) 

Spring developers has done this to prevent OutOfMemory problem.

The solution is very simple as below, in your controller class, you need to override init Binder method and configure the limit size which needs so that you can pass those many objects to your controller classes.

You have to be very careful while setting the max size as you may get OutOfMemory issues in your application if you set this value very high.

Just put some buffer while setting the size to say if you are passing 500 objects then you may configure it as 600 or 700 if it increases in future.

Also do not hardcode this value in java code externalize it in some property file or XML file.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;

/**
 * @author Nitin Prabhu
 */
@Controller
public class Controller {

   //Externalize this value
    @Value("${myApplication.autoGrowCollectionLimit:600}")
    private int autoGrowCollectionLimit;


    @InitBinder
    public void initBinder(WebDataBinder dataBinder) {
        dataBinder.setAutoGrowCollectionLimit(autoGrowCollectionLimit);
    }

}

@InitBinder plays the role to identify the methods which initialize the WebDataBinder. The @InitBinder method supports many arguments as by @RequestMapping methods.

@InitBinder method does not support command or form arguments. Mostly used argument is WebDataBinder in @InitBinder method.

WebDataBinder is a DataBinder that binds request parameter to JavaBean objects.

Hope this article helped you.

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:
spring mvc ,spring framework

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}