Search code examples
javajerseyjersey-2.0hk2

Injection provider with injected MultivaluedMap (application/x-www-form-urlencoded)


The Jersey docs give an example of how to inject HttpSession on resources. How should I inject (or otherwise gain access to) form parameters sent on requests with "Content-Type: application/x-www-form-urlencoded"? I see that these are passed as parameters on methods, and do not seem to be annotated, letting me believe there is some quirk here?

The (naive) factory I'm currently working with is implemented as follows, JerseyHttpServletRequestWrapper being one of my own classes:

import org.glassfish.hk2.api.Factory;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MultivaluedMap;

public class JerseyHttpServletRequestWrapperFactory implements Factory<JerseyHttpServletRequestWrapper> {
    private final HttpServletRequest request;
    private final MultivaluedMap<String, String> formParams;

    @Inject
    public JerseyHttpServletRequestWrapperFactory(HttpServletRequest request, MultivaluedMap<String, String> formParams) {
        this.request = request;
        this.formParams = formParams;
    }

    @Override
    public JerseyHttpServletRequestWrapper provide() {
        return new JerseyHttpServletRequestWrapper(request, formParams);
    }

    @Override
    public void dispose(JerseyHttpServletRequestWrapper jerseyHttpServletRequestWrapper) {
    }
}

I'm thinking here that an entity provider should be injected into the instance so that I can check if there is actually an entity sent with the request. Trying to directly inject MultivaluedMap errors out with:

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=MultivaluedMap<String,String>,parent=JerseyHttpServletRequestWrapperFactory,qualifiers={},position=1,optional=false,self=false,unqualified=null,2067821943)

Solution

  • When you do

    @POST
    public Response post(MultivaluedMap<String, String> params) {}
    

    this method parameter injection is handled differently than with regular field/constructor injection. So you can't try to inject the MultivaluedMap into a field.

    What you can do though is inject the ContainerRequest, and then read the body. You'll want to check that it's a POST request and the Content-Type is application/x-www-form-urlencoded. If you don't, there's a chance you will get an exception when you try to read the entity.

    @Inject
    ContainerRequest request;
    
    if (request.getMethod().toUpperCase().equals("POST")
         && request.getMediaType().equals(MediaType.APPLICATION_FORM_URLENCODED_TYPE)) {
        request.bufferEntity();
        Form form = request.readEntity(Form.class);
        MultivaluedMap<String, String> params = form.asMap();
    }