Search code examples
javajerseyjax-rs

How do you map multiple query parameters to the fields of a bean on Jersey GET request?


A service class has a @GET operation that accepts multiple parameters. These parameters are passed in as query parameters to the @GET service call.

@GET
@Path("find")
@Produces(MediaType.APPLICATION_XML)
public FindResponse find(@QueryParam("prop1") String prop1, 
                         @QueryParam("prop2") String prop2, 
                         @QueryParam("prop3") String prop3, 
                         @QueryParam("prop4") String prop4, ...) 

The list of these parameters are growing, so I would like to place them into a single bean that contains all these parameters.

@GET
@Path("find")
@Produces(MediaType.APPLICATION_XML)
public FindResponse find(ParameterBean paramBean) 
{
    String prop1 = paramBean.getProp1();
    String prop2 = paramBean.getProp2();
    String prop3 = paramBean.getProp3();
    String prop4 = paramBean.getProp4();
}

How would you do this? Is this even possible?


Solution

  • You can use com.sun.jersey.spi.inject.InjectableProvider.

    import java.util.List;
    import java.util.Map.Entry;
    
    import javax.ws.rs.QueryParam;
    import javax.ws.rs.core.Context;
    import javax.ws.rs.core.MultivaluedMap;
    import javax.ws.rs.ext.Provider;
    
    import org.springframework.beans.BeanUtils;
    
    import com.sun.jersey.api.core.HttpContext;
    import com.sun.jersey.api.model.Parameter;
    import com.sun.jersey.core.spi.component.ComponentContext;
    import com.sun.jersey.core.spi.component.ComponentScope;
    import com.sun.jersey.spi.inject.Injectable;
    import com.sun.jersey.spi.inject.InjectableProvider;
    
    @Provider
    public final class ParameterBeanProvider implements InjectableProvider<QueryParam, Parameter> {
    
        @Context
        private final HttpContext hc;
    
        public ParameterBeanProvider(@Context HttpContext hc) {
            this.hc = hc;
        }
    
        @Override
        public ComponentScope getScope() {
            return ComponentScope.PerRequest;
        }
    
        @Override
        public Injectable<ParameterBean> getInjectable(ComponentContext ic, final QueryParam a, final Parameter c) {
    
            if (ParameterBean.class != c.getParameterClass()) {
                return null;
            }
    
            return new Injectable<ParameterBean>() {
    
                public ParameterBean getValue() {
                    ParameterBean parameterBean = new ParameterBean();
                    MultivaluedMap<String, String> params = hc.getUriInfo().getQueryParameters();
                    // Populate the parameter bean properties
                    for (Entry<String, List<String>> param : params.entrySet()) {
                        String key = param.getKey();
                        Object value = param.getValue().iterator().next();
    
                        // set the property
                        BeanUtils.setProperty(parameterBean, key, value);
                    }
                    return parameterBean;
                }
            };
        }
    }
    

    In your resource you just have to use @QueryParam("valueWeDontCare").

    @GET
    @Path("find")
    @Produces(MediaType.APPLICATION_XML)
    public FindResponse find(@QueryParam("paramBean") ParameterBean paramBean) {
        String prop1 = paramBean.getProp1();
        String prop2 = paramBean.getProp2();
        String prop3 = paramBean.getProp3();
        String prop4 = paramBean.getProp4();
    }
    

    The provider will be automatically called.