Дополнительные параметры в запросе REST API с использованием Джерси 2.21

Я играю с Jersey 2.21 и я хотел бы знать, возможно ли иметь "необязательный" параметр, который может или нет присутствовать в запросе, сделанном на сервер.

Я хочу успешно получить доступ к этим двум методам:

http://localhost:8080/my_domain/rest/api/myMethod/1
http://localhost:8080/my_domain/rest/api/myMethod

как вы можете видеть, я пытаюсь сделать целое число (id) param необязательный.

я объявил myMethod следующим образом:

@GET
@Path("myMethod/{id}")
@Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
public String myMethod(@PathParam("id") Integer id, @Context HttpHeaders hh)

это работает:

http://localhost:8080/my_domain/rest/api/myMethod/1

и это работает тоже:

http://localhost:8080/my_domain/rest/api/myMethod/

но это не будет работать и я не понимаю, почему. Он бросает!--8--> ошибка:

http://localhost:8080/my_domain/rest/api/myMethod

можете ли вы мне точку в правильном направлении, чтобы решить эту проблему? Мне не нравится, что косая черта обязательна для всех моих вызовов метода REST, и я хотел бы подавить ее, если это возможно.

2 ответов


Итак, после некоторого баловства с некоторыми ответами в необязательно @PathParam в Jax-RS проблема в том, что, используя этот

@Path("/myMethod{id: (/\d+)?}") 
public Response get(@PathParam("id") int id) {}

вызывает / быть в группе захвата. Поэтому, когда Джерси пытается разобрать /1 он получит исключение и отправит 404. Мы могли бы использовать строку, но потом она становится уродливой, так как нам нужно избавиться от ведущего / и разберем сами.

@Path("/myMethod{id: (/\d+)?}") 
public Response get(@PathParam("id") String id) {
    id = id.replace("/", "");
    int parsed = Integer.parseInt(id);
}

другое решение, которое я придумал с (тот, который работает для OP), должен отделить / из цифр в два разных выражения пути, так что ведущий / не захватывается в фактическом id и не терпит неудачу в разборе

@Path("/method{noop: (/)?}{id: ((?<=/)\d+)?}")
public Response get(@PathParam("id") int id) {}

на {noop: (/)?} захватывает факультативного /. И {id: ((?<=/)\d+)?} использует положительный lookbehind, говоря, что числа (\d+) допускаются, если и только если есть / прежде чем он ((?<=/)). Это необходимо как / is необязательный. Если мы не использовали это утверждение, то /myMethod123 будет разрешено.

вот полный тестовый случай с помощью Джерси Тест Рамки

public class OptionalParamTest extends JerseyTest {

    @Path("optional")
    public static class Resource {
        @GET
        @Path("/method{noop: (/)?}{id: ((?<=/)\d+)?}")
        public String get(@PathParam("id") int id) {
            return String.valueOf(id);
        }
    }

    @Override
    public ResourceConfig configure() {
        return new ResourceConfig(Resource.class);
    }

    @Test
    public void should_return_id_1() {
        Response response = target("optional/method/1").request().get();
        System.out.println("status=" + response.getStatus());
        assertEquals("1", response.readEntity(String.class));
    }

    @Test
    public void should_return_id_0_with_no_id() {
        Response response = target("optional/method").request().get();
        assertEquals(200, response.getStatus());
        assertEquals("0", response.readEntity(String.class));
    }

    @Test
    public void should_return_404_with_numbers_and_no_slash() {
        Response response = target("optional/method12").request().get();
        assertEquals(404, response.getStatus());
    } 

    @Test
    public void should_return_404_with_numbers_and_letters() {
        Response response = target("optional/method/12b").request().get();
        assertEquals(404, response.getStatus());
    }

    @Test
    public void should_return_404_with_only_letters() {
        Response response = target("optional/method/ab").request().get();
        assertEquals(404, response.getStatus());
    } 
}

вот зависимость для теста

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>${jersey2.version}</version>
    <scope>test</scope>
</dependency>

редактировать

для тестов, было бы лучше использовать коробочную Integer вместо int в качестве параметра метода. С первым вы сможете сделать нулевую проверку, вместо того, чтобы получать значение по умолчанию 0 для примитив.


есть путь более простой способ сделать это:

@GET
@Path("myMethod/{id}")
public String myMethod(@PathParam("id") Integer id) {
}

@GET
@Path("myMethod")
public String myMethod() {
  return myMethod(null);
}

не требуется сложное регулярное выражение.