lathspell
lathspell

Reputation: 3310

How can @QueryParam translate a parameter without value to boolean "false"?

I'd like to use an URL like http://www.example.com/rest/foo?bar where the bar query parameter has no value and its presence alone should denote if a variable is true or false.

Currently the missing value is assumed to be "" (empty) and passed to new Boolean() which treats it as false.

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?

Upvotes: 15

Views: 22961

Answers (3)

Paul Samsotha
Paul Samsotha

Reputation: 209062

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 @XxxParams 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.

Upvotes: 10

cassiomolin
cassiomolin

Reputation: 131017

You could try the following:

@GET
@Path("/some-path")
public Response myMethod(@Context HttpServletRequest request) {

    boolean isParameterPresent = request.getParameterMap().contains("bar");

    ...
}

But the solutions shown in peeskillet's answer are the cleverest ways to achieve it.

Upvotes: 8

Phoste
Phoste

Reputation: 1209

I know it's an old question but I had the same trouble.

To solve my problem, I used the Annotation @DefaultValue :

@GET
@Path("/path")
public Response myMethod(@DefaultValue("true") @QueryParam("foo") boolean foo) {
    if (foo) {
       ...
    }
}

So, when the request contains the parameter foo the boolean value will be false and if not it will be true. It shows the opposite of reality but if you're aware of it, it's quite simple to use.

Upvotes: 21

Related Questions