Note: upon seeing Phoste's answer, I'd go with his/her solution. I'm leaving this answer up, as there is still some useful information here.
Is there a more elegant way of defining it than declaring the parameter to be String and converting it myself? Like e.g. a class javax.rs.BooleanFlag
or similar?
No such type (BooleanFlag
), If you look at the javadoc for @QueryParam, you'll see a list of options for how we can create a custom type to use a @QueryParam
value (for the most part the same holds true for other @XxxParam
s also)
- 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
JAX-RS extension SPI that returns a ParamConverter
instance capable of a "from string" conversion for the type.
So from the first option, in theory, you should be able to do something like
public class Flag {
private final boolean isPresent;
public Flag(String param) { isPresent = param != null; }
public boolean isPresent() { return isPresent; }
}
@GET
public String get(@QueryParam("bar") Flag bar) {
if (bar.isPresent()) {
return "bar is present";
} else {
return "bar is not present";
}
}
Now this works when the query flag is present. But when it's not, it acts like any other non-primitive type; it's null. So the call to bar.isPresent
give an NPE. Tested with a fromString
and valueOf
with the same result. We could check if (bar == null)
, but that's no better that just using a String and checking if the String is null. It's not pretty.
So the last option is the ParamConverterProvider
. Which does actually work. Below is the implementation.
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;
@Provider
public class FlagParamConverterProvider implements ParamConverterProvider {
@Override
public <T> ParamConverter<T> getConverter(
Class<T> rawType, Type genericType, Annotation[] annotations) {
if (rawType != Flag.class) {
return null;
}
return new ParamConverter<T>() {
@Override
public T fromString(String value) {
return (T)new Flag(value);
}
@Override
public String toString(T value) { return null; }
};
}
}
Just make sure the provider is registered. It's a pretty clean solution in my opinion.