I tried to override/implement all the attribute in JSR311 but the Jersey binding seems case sensitive:
- 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))
- Be List, Set or SortedSet, where T satisfies 2 or 3 above. The resulting collection is read-only.
How can I make Jersey binding for enum case insensitive?
EDIT:
Here's the code:
The enum:
public enum Color {
GREEN,
BLUE;
public Color fromString(String param) {
String toUpper = param.toUpperCase();
try {
return valueOf(toUpper);
} catch (Exception e) {
return null;
}
}
}
Bean Param:
public class FooQueryParam {
@QueryParam(value = "color")
private Color color;
public Color getColor() {
return color;
}
public void setStatus(Color Color) {
this.color = color;
}
}
The resource:
public Response get(@BeanParam FooQueryParam fooQueryParam) {
//...
}
If you're doing it right it shouldn't be a problem. For example in case 3, using a fromString
public static enum Color {
RED, GREEN, BLUE;
public static Color fromString(String param) {
String toUpper = param.toUpperCase();
try {
return valueOf(toUpper);
} catch (Exception e) {
// default behavior is to send 404 on error.
// do something else if you want
throw new WebApplicationException(400);
}
}
}
Every enum already has a static valueOf
method which tries to match the enum value exactly, so we override this behavior by defining the fromString
. We first call toUpperCase()
then call valueOf
as it's looking for upper case. If anything fails, like a wrong enum value, we send a 400. You can send something else or stick with the normal 404. Up to you.
I already did this, it is not working
Here is a complete test case.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class EnumTest extends JerseyTest {
public static enum Color {
RED, GREEN, BLUE;
public static Color fromString(String param) {
String toUpper = param.toUpperCase();
try {
return valueOf(toUpper);
} catch (Exception e) {
// default behavior is to send 404 on error.
// do something else if you want
throw new WebApplicationException(400);
}
}
}
@Path("enum")
public static class ColorResource {
@GET
public String color(@QueryParam("color") Color color) {
return color.toString();
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(ColorResource.class);
}
@Test
public void doit() {
Response response = target("enum").queryParam("color", "blue").request().get();
assertEquals(200, response.getStatus());
assertEquals("BLUE", response.readEntity(String.class));
response.close();
response = target("enum").queryParam("color", "gReEn").request().get();
assertEquals(200, response.getStatus());
assertEquals("GREEN", response.readEntity(String.class));
response.close();
response = target("enum").queryParam("color", "RED").request().get();
assertEquals(200, response.getStatus());
assertEquals("RED", response.readEntity(String.class));
response.close();
response = target("enum").queryParam("color", "orange").request().get();
assertEquals(400, response.getStatus());
response.close();
}
}
Use this dependency
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.19</version>
<scope>test</scope>
</dependency>
UPDATE
Test using @BeanParam
import javax.ws.rs.BeanParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class EnumTest extends JerseyTest {
public static enum Color {
RED, GREEN, BLUE;
public static Color fromString(String param) {
String toUpper = param.toUpperCase();
System.out.println("--- toUpper " + toUpper + "---");
try {
return valueOf(toUpper);
} catch (Exception e) {
System.out.println(" --- ERROR ---");
// default behavior is to send 404 on error.
// do something else if you want
throw new WebApplicationException(400);
}
}
}
public static class FooQueryParam {
@QueryParam("color")
private Color color;
public Color getColor() { return color; }
public void setColor(Color color) { this.color = color; }
}
@Path("enum")
public static class ColorResource {
@GET
public String color(@BeanParam FooQueryParam foo) {
return foo.getColor().toString();
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(ColorResource.class);
}
@Test
public void doit() {
Response response = target("enum").queryParam("color", "blue").request().get();
assertEquals(200, response.getStatus());
assertEquals("BLUE", response.readEntity(String.class));
response.close();
response = target("enum").queryParam("color", "gReEn").request().get();
assertEquals(200, response.getStatus());
assertEquals("GREEN", response.readEntity(String.class));
response.close();
response = target("enum").queryParam("color", "RED").request().get();
assertEquals(200, response.getStatus());
assertEquals("RED", response.readEntity(String.class));
response.close();
response = target("enum").queryParam("color", "orange").request().get();
assertEquals(400, response.getStatus());
response.close();
}
}
The only thing that fails is the error case where I am sending a bad color. It seems with @BeanParam
the behavior is different. Instead of the expected 400, there is a 500. The other case sentiviity issues are fine