Search code examples
javaspring-mvcspring-bootservlet-filterslibphonenumber

Spring (instantiation of Google Lib phone number) using a Filter to change a Model instance variable


I'm currently trying to modify, (via a Spring filter) some of the request variables being posted into a form.

Reason being, I would like to implement better phone number validation, and better control how telephone numbers are formatted. For that part of the puzzle, I intend to use Google's Lib phone number in my model so like so:

 private PhoneNumber mobileNumber;

One getter, with no mention of the prefix at all, given that the filter will hopefully do the hard work for me.

I initially thought that perhaps I could use an attribute converter to do this i.e.

@Convert(converter = PhoneNumberConverter.class )
 private PhoneNumber mobileNumber;

However, there is a problem with that, in that if the field is a composite type, the JPA doesn't support it: https://github.com/javaee/jpa-spec/issues/105 (compositie because PREFIX is needed as well as NUMBER) to build a lib phone object.

So. A filter (or Interceptor?) is what I'm left with. My question is, I'm new to the Spring framework and I'm not 100% sure whether just modifying the raw request will allow instantiation of the PhoneNumber object in the model - (I presume not), but any guidance on how Spring manages to do its magic tying up of request variables into an object (by mapping getters and setters) and how I would go about doing this manually in the filter would be helpful. Is there any way of access this Model object in the filter so I can set it directly?

   public class PhonePrefixFilter extends OncePerRequestFilter
    {

        @Override
        protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain )
                throws ServletException, IOException
        {
            String prefix = request.getParameter( "phonePrefix" );
            if( StringUtils.isNotEmpty( prefix ) )
                request.setAttribute( "mobileNumber", prefix + request.getAttribute( "mobileNumber" ) );

            filterChain.doFilter( request, response );

        }

    }

Solution

  • AFAIK you cannot modify your request parameter directly. You need a HttpServletRequestWrapper to provide custom getter to your parameter:

    public static class PhoneRequestWrapper extends HttpServletRequestWrapper {
    
        public PhoneRequestWrapper(HttpServletRequest request) {
            super(request);
        }
    
        @Override
        public String getParameter(String name) {
            if (!("mobileNumber").equals(name)) {
                return super.getParameter(name);
            }
            String prefix = getParameter("phonePrefix");
            String mobileNumber = getRequest().getParameter("mobileNumber");
            if (StringUtils.isNotEmpty(prefix) && StringUtils.isNotEmpty(mobileNumber)) {
                return prefix + getRequest().getParameter("mobileNumber");
            } else {
                return mobileNumber;
            }
        }
    }
    

    Then create your filter:

    public static class PhoneNumberFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws
                                                                                                        ServletException,
                                                                                                        IOException {
            filterChain.doFilter(new PhoneRequestWrapper((HttpServletRequest) request), response);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    And register it in your @Configuration class:

    @Bean
    public Filter filterRegistrationBean() {
       return new PhoneNumberFilter();
    }
    

    From now on, your request.getParamter("mobileNumber") will have the value appended with phonePrefix

    Since your question is not very clear, if you want to override the behaviour of @RequestParam to get your phone number string, you can use custom HandlerMethodArgumentResolver to resolve your parameter