2

Our query parameters have a structure (effectively, they form a Map<String,Bindings>) which is causing repetition in the JAX-RS bindings.

Can we change the bindings to eliminate repetition?

@GET @Produces("application/json;charset=UTF-8")
List<BoundThings> getSomeBoundThings(
        @PathParam("id") UUID id,
        @QueryParam("bindings.organisation") Bindings orgBindings,
        @QueryParam("bindings.person") Bindings personBindings,
        @QueryParam("bindings.location") Bindings locBindings,
        @QueryParam("bindings.brand") Bindings brandBindings,
        @QueryParam("bindings.genre") Bindings genreBindings,
        @QueryParam("bindings.icb") Bindings icbBindings,
        @QueryParam("bindings.iptc") Bindings iptcBindings,
        @QueryParam("bindings.section") Bindings sectionBindings,
        @QueryParam("bindings.subject") Bindings subjBindings,
        @QueryParam("bindings.topic") Bindings topicBindings,
        @QueryParam("bindings.specialreport") Bindings rptBindings) {
}

Just for context, the method looks up metadata for a specific entity identified by UUID. Bindings is an enum identifying the type of binding to use. Each binding defines a relationship.

Would it be possible to use Map<String,Bindings>? How?

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
Simon Gibbs
  • 4,737
  • 6
  • 50
  • 80
  • You could Json-encode all GET parameters and then decode them with a library like Jackson. – V G Aug 24 '15 at 15:22

1 Answers1

0

There are a few ways to clean it up.

Note: this is only for DW [8.0, )

You could...

Just inject UriInfo and get a MultivaluedMap<String, String>. (Though you can't get MultivaluedMap<String, Bindings>)

@GET
public Response get(@Context UriInfo uriInfo) {
    MultivaluedMap<String, String> queryMap = uriInfo.getQueryParameters();
}

You could...

Use @BeanParam to just put everything into a bean.

public class BindingsBean {

    @QueryParam("bindings.organisation") 
    Bindings orgBindings;

    @QueryParam("bindings.person") 
    Bindings personBindings;
}

@GET
public Response get(@BeanParam BindingsBean bindingsBean) {}

You could...

Create a map-like bean class and create a Factory[1] so you can inject it with @Context. For example

Map wrapper

public class BindingsMap {

    public static final String BINDINGS_ORGANIZATION = "bindings.organisation";
    public static final String BINDINGS_PERSON = "bindings.person";

    private final Map<String, Bindings> bindings = new HashMap<>();

    public void put(String key, Bindings bindings) {
        this.bindings.put(key, bindings);
    }

    public Bindings get(String key) {
        return this.bindings.get(key);
    }
}

Factory

public class QueryBindingsFactory
        extends AbstractContainerRequestValueFactory<BindingsMap> {

    @Override
    public BindingsMap provide() {
        BindingsMap bindingsMap = new BindingsMap();
        put(bindingsMap, BindingsMap.BINDINGS_ORGANIZATION);
        put(bindingsMap, BindingsMap.BINDINGS_PERSON);
        return bindingsMap;
    }

    private void put(BindingsMap bindingsMap, String key) {
        ContainerRequest request = getContainerRequest();
        MultivaluedMap<String, String> queryParams
                = request.getUriInfo().getQueryParameters();
        bindingsMap.put(key, Bindings.fromString(queryParams.getFirst(key)));
    }

    @Override
    public void dispose(BindingsMap t) {
    }
}

Resource method

@GET
public Response get(@Context BindingsMap bindingsMap) {}

Then you need to register the factory

env.jersey().register(new AbstractBinder(){
    @Override
    public void configure() {
        bindFactory(QueryBindingsFactory.class)
                .to(BindingsMap.class)
                .in(RequestScoped.class);
    }
});

[1] See Custom Injection and Lifecycle Management

You could...

Create a custom annotation to inject the above BindingsMap, if you don't like the @Context annotation. You can see a complete example in this answer. It pretty much just builds on top of the above option. It requires extra:

  1. A custom annotation
  2. An InjectionResolver.
  3. And an AbstractValueFactoryProvider

All examples can be seen in the link. If you're ok with the @Context annotation, it may be simpler just to go with that.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720