gstackoverflow
gstackoverflow

Reputation: 37034

Spring mvc. case insensitive get parameters mapping

according this answer I try to write my code:

pojo:

class MyBean{

    public String getValueName() {
        return valueName;
    }

    public void setValueName(String valueName) {
        this.valueName = valueName;
    }

    String valueName;
}

inside controller:

    @ModelAttribute
    public MyBean createMyBean() {
        return new MyBean();
    }
    @RequestMapping(value = "/getMyBean", method = RequestMethod.GET)
    public String getMyBean(@ModelAttribute MyBean myBean) {
        System.out.println(myBean.getValueName());
        return "pathToJsp";
    }

web.xml configuration:

<filter>
    <filter-name>caseInsensitiveFilter</filter-name>
    <filter-class>com.terminal.interceptor.CaseInsensitiveRequestFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>caseInsensitiveFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Filter:

@Component
public class CaseInsensitiveRequestFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(new CaseInsensitiveHttpServletRequestWrapper(request), response);
    }

    private static class CaseInsensitiveHttpServletRequestWrapper extends HttpServletRequestWrapper {

        private final LinkedCaseInsensitiveMap params = new LinkedCaseInsensitiveMap();

        /**
         * Constructs a request object wrapping the given request.
         *
         * @param request
         * @throws IllegalArgumentException if the request is null
         */
        private CaseInsensitiveHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
            params.putAll(request.getParameterMap());
        }

        @Override
        public String getParameter(String name) {
            String[] values = getParameterValues(name);
            if (values == null || values.length == 0) {
                return null;
            }
            return values[0];
        }

        @Override
        public Map getParameterMap() {
            return Collections.unmodifiableMap(this.params);
        }

        @Override
        public Enumeration getParameterNames() {
            return Collections.enumeration(this.params.keySet());
        }

        @Override
        public String[] getParameterValues(String name) {
            return (String[]) params.get(name);
        }
    }
}

In debug I see that filter method invoke but I cannot achieve case insentive get parameters mapping.

for example localhost:8081/getMyBean?valueName=trololo works but localhost:8081/getMyBean?valuename=trololo - not

Upvotes: 11

Views: 7449

Answers (4)

tonnoz
tonnoz

Reputation: 502

Your enum param:

enum YourEnum {
    ENUM1, ENUM2, ENUM3
}

Add this converter class:

class StringToEnumConverter implements Converter<String, YourEnum> {
    @Override
    YourEnum convert(String source) {
        return YourEnum.valueOf(source.toUpperCase());
    }
}

and this Configuration:

class ApiWebConfiguration implements WebMvcConfigurer {

    @Override
    void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToEnumConverter());
    }
...
}

voila, case-unsensitive enum parameter.

Upvotes: 0

SaviNuclear
SaviNuclear

Reputation: 861

Actually, you have to change the things in the CaseInsensitiveRequestFilter class as per your bean variable name. In your case the variable is valueName, so for every request it will convert it as per your variable setter method camel case injection and then match as per your request. Just try for your custom requirements:

package biz.deinum.web.filter;

import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.web.filter.OncePerRequestFilter;

public class CaseInsensitiveRequestFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(new CaseInsensitiveHttpServletRequestWrapper(request), response);
    }

    private static class CaseInsensitiveHttpServletRequestWrapper extends HttpServletRequestWrapper {

        private final LinkedCaseInsensitiveMap<String[]> params = new LinkedCaseInsensitiveMap<>();

        private CaseInsensitiveHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
            Map<String, String[]> map = request.getParameterMap();
            Set set = map.entrySet();
            Iterator it = set.iterator();
            Map<String, String[]> tempMap = new HashMap<String, String[]>(); 
            while (it.hasNext()) {
                Map.Entry<String, String[]> entry = (Entry<String, String[]>) it.next();
                String key = entry.getKey();
                // Keep your parameter bean name here in your case it is "valueName"
                String beanParamaterName = "valueName";
                if(key.equalsIgnoreCase(beanParamaterName)){
                    tempMap.put(key.toLowerCase(), entry.getValue());
                }
            }
            params.putAll(tempMap);
        }

        @Override
        public String getParameter(String name) {
            String[] values = getParameterValues(name);
            System.out.println(values.toString()+"-");
            if (values == null || values.length == 0) {
                return null;
            }
            return values[0];
        }

        @Override
        public Map<String, String[]> getParameterMap() {
            return Collections.unmodifiableMap(this.params);
        }

        @Override
        public Enumeration<String> getParameterNames() {
            return Collections.enumeration(this.params.keySet());
        }

        @Override
        public String[] getParameterValues(String name) {
            System.out.println(name);
            return (String[])params.get(name);
        }
    }
}

Upvotes: 1

Neeraj Gupta
Neeraj Gupta

Reputation: 173

Here is what you can do...

Create the domain(POJO) with all lowercase variables

public class MyBean{
    private String valuename;

    public String getValuename() {
        return valuename;
    }

    public void setValuename(String valuename) {
        this.valuename = valuename;
    }
}

Then create a class which will extend HttpServletRequestWrapper

public class CustomWrappedRequest extends HttpServletRequestWrapper
{
    private final Map<String, String[]> modifiableParameters;
    private Map<String, String[]> allParameters = null;

    public CustomWrappedRequest(final HttpServletRequest request, 
                                                    final Map<String, String[]> additionalParams)
    {
        super(request);
        modifiableParameters = new TreeMap<String, String[]>();
        modifiableParameters.putAll(additionalParams);
    }

    @Override
    public String getParameter(final String name)
    {
        String[] strings = getParameterMap().get(name);
        if (strings != null)
        {
            return strings[0];
        }
        return super.getParameter(name);
    }

    @Override
    public Map<String, String[]> getParameterMap()
    {
        if (allParameters == null)
        {
            allParameters = new TreeMap<String, String[]>();
            allParameters.putAll(super.getParameterMap());
            allParameters.putAll(modifiableParameters);
        }
        return Collections.unmodifiableMap(allParameters);
    }

    @Override
    public Enumeration<String> getParameterNames()
    {
        return Collections.enumeration(getParameterMap().keySet());
    }

    @Override
    public String[] getParameterValues(final String name)
    {
        return getParameterMap().get(name);
    }
}

Last add a filter with appropriate web.xml config the doFilter() will look like this

public void doFilter(ServletRequest request, ServletResponse reponse, FilterChain chain)
            throws IOException, ServletException {
        Map<String, String[]> params = request.getParameterMap();
        Map<String, String[]> extraParams = new TreeMap<String, String[]>();
        Iterator<String> i = params.keySet().iterator();

        while ( i.hasNext() )
          {
            String key = (String) i.next();
            String value = ((String[]) params.get( key ))[ 0 ];
            extraParams.put(key.toLowerCase(), new String[] {value});

          }
        HttpServletRequest wrappedRequest = new CustomWrappedRequest((HttpServletRequest)request, extraParams);

        chain.doFilter(wrappedRequest, reponse);

    }

Here the filter will convet the params into lowercase and attach it to your custom made request. Then use can use @ModelAttribute in the controller code to get the desired object.

Hope it helps :)

Upvotes: 1

Gokhan Oner
Gokhan Oner

Reputation: 3257

Your problem, I believe, is @ModelAttribute. You're asking Spring to map the parameters to MyBean object, and the property inside this object is valueName.

In order Spring to reflect the params to the object, it needs to be in the correct case.

You have 2 options:

  • change the property name to valuename in your MyBean object, and all property names to lowercase, it should work with help of your solution.
  • remove @ModelAttribute and put @RequestParam for each property. If you have many props, this could be painful.

Upvotes: 5

Related Questions