3 ways to solve it:
- use the generic context-parameter
UriInfo
, which is not very expressive
- add an explicit custom type that can parse a comma-separated list
- stay with
@QueryParam List<String>
requiring a concatenated query like ?id=1&id=2&id=3
given as URI
I would prefer the second as most-expressive, like answered already by Paul. This way you can concisely pass a single CSV like ?id=1,2,3,3
and also use a Set
to ensure unique ID values, e.g. resulting in only [1, 2, 3]
.
Generic context-param UriInfo
One way would be to use a generic parameter @Context UriInfo
to get the list in the method's body:
public List<Something> getFilteredList( @Context UriInfo uriInfo ) {
List<String> idList = uriInfo.getQueryParameters().get("id"); // before was @QueryParam("id")
System.out.println("idList: " + idList);
// filter a given list by ids
var somethingFiltered = getSomethingList().stream()
.filter(s -> idList.contains(s.getId()))
.collect(toList());
return Response.status(Status.OK).entity(somethingFiltered).build();
}
See the tutorial in Java Vogue(2015): QueryParam Annotation In Jersey -
Custom type with static valueOf(String)
factory-method
The other way is to design a custom type which can be constructed using a String:
class IdSet {
Set<String> values;
// a factory method, can also be named valueOf
public static IdSet fromString(String commaSeparated) {
return new HashSet( Arrays.asList( commaSeparated.split(",") ) );
}
}
public List<Something> getFilteredList(@QueryParam("id") IdSet ids) {
System.out.println("ids (Set): " + ids.values);
// filter a given list by ids
var somethingFiltered = getSomethingList().stream()
.filter(s -> ids.values.contains(s.getId()))
.collect(toList());
return Response.status(Status.OK).entity(somethingFiltered).build();
}
See Jersey's JavaDocs for @QueryParam
:
The type T of the annotated parameter, field or property must either:
- Be a primitive type
- Have a constructor that accepts a single String argument
- Have a static method named
valueOf
or fromString
that accepts a single String
argument (see, for example, Integer.valueOf(String)
)
- Have a registered implementation of
ParamConverterProvider
that returns a ParamConverter
instance capable of a "from string" conversion for the type.
- Be
List<T>
, Set<T>
or SortedSet<T>
, where T
satisfies 2, 3 or 4 above. The resulting collection is read-only.
Use a collection interface with multiple key-value pairs
When the calling client uses following URI pattern: /something?id=1&id=2&id=3
then JAX-RS can deserialize them to a single parameter of List<String> id
having given multiple elements:
public List<Something> getFilteredList(@QueryParam("id") List<String> ids) {
System.out.println("ids : "+ids);
// filter a given list by ids
var somethingFiltered = getSomethingList().stream()
.filter(s -> ids.contains(s.getId()))
.collect(toList());
return Response.status(Status.OK).entity(somethingFiltered).build();
}
See Mkyong: JAX-RS @QueryParam example where explained the multiple occurrences of orderBy
in the GET query:
@QueryParam will convert the query parameter “orderBy=age&orderBy=name” into java.util.List automatically.
See also