Jax-RS: Необязательные параметры пути не принимаются в сочетании с аннотацией метода @GET @POST

#java #rest #jersey #jax-rs

#java #rest #джерси #jax-rs

Вопрос:

Я использую jersey с jackson помощью maven :

     <jackson.version>2.9.6</jackson.version>
    <jersey.version>2.25.1</jersey.version>
    <jetty.version>9.2.11.v20150529</jetty.version>
     ....
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>${jackson.version}</version>
    </dependency> 
    <dependency>
      <groupId>com.fasterxml.jackson.jaxrs</groupId>
      <artifactId>jackson-jaxrs-base</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.jaxrs</groupId>
      <artifactId>jackson-jaxrs-json-provider</artifactId>
      <version>${jackson.version}</version>
    </dependency>   
    <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
     </dependency>
     <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
     </dependency>
     <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
      </dependency>
      <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
      </dependency>

    <!-- Jersey Server -->
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>${jersey.version}</version>
     </dependency>    
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet-core</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-jetty-http</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>${jersey.version}</version>
        <exclusions>
         <exclusion>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-base</artifactId>
          </exclusion>
           <exclusion>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
          </exclusion>
          <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
         </exclusion>
        </exclusions>
    </dependency>
  

У меня есть класс обслуживания со следующим методом метод POST:

 @GET
@Path("{Prefix}{p:/?}{id: ((\d )?)}/abc{p2:/?}{number: (([A-Za-z0-9]*)?)}")
@Produces(MediaType.APPLICATION_JSON)
public Response getMyToken(@Context ServletContext context, @Context Request request, @HeaderParam("If-None-Match") String ifMatch, @HeaderParam("Prefer") String prefer) {..}


@POST
@Path("{Prefix}{p:/?}{id: ((\d )?)}/abc/{myValueVariable}")
@Produces(MediaType.APPLICATION_JSON)
public Response setMyToken(@Context ServletContext context, @Context Request request, @HeaderParam("If-None-Match") String ifMatch, @HeaderParam("Prefer") String prefer) {..}
  

Этот GET URL-адрес ДОЛЖЕН принимать два необязательных параметра. Например. следующие URL-адреса должны совпадать:

  • P /1/abc/myNumber
  • P /abc/myNumber
  • P /1/abc

Однако, похоже, что первые два URL-адреса НЕ совпадают — второй необязательный параметр, похоже, не распознан (я получаю ошибку 405 — метод не вызывается). Я много чего протестировал и понял, что добавление дополнительного параметра в конце приводит к совпадению с моим URL. Итак, с помощью следующего метода

 @GET
@Path("{Prefix}{p:/?}{id: ((\d )?)}/abc{p2:/?}{number: (([A-Za-z0-9]*)?)}/endPath")
@Produces(MediaType.APPLICATION_JSON)
public Response getMyToken(@Context ServletContext context, @Context Request request, @HeaderParam("If-None-Match") String ifMatch, @HeaderParam("Prefer") String prefer) {..}
  

следующие URL-адреса совпадают:

  • P /1/abc/myNumber/endPath
  • P /abc/myNumber/endPath
  • P /1/abc/endPath

Я не хочу иметь этот последний параметр. Как я могу решить эту проблему? Что я делаю не так?

РЕДАКТИРОВАТЬ: я также заметил, что это работает, если я не использую имя, занимающее первое место:

 @GET
@Path("hardCodePrefix{p:/?}{id: ((\d )?)}/abc{p2:/?}{number: (([A-Za-z0-9]*)?)}")
  

Как только я пытаюсь заменить hardCodePrefix переменной или регулярным выражением, у меня возникает проблема, описанная выше (URL-адреса не совпадают)

EDIT2:
The really strange thing is, that even the .* wildcard does not work…

 @GET
@Path("hardCodePrefix{p:/?}{id: ((\d )?)}/abc{p2:/?}{number: .*}")
  

So e.g. P/1/abc/ is matching and I get / for p2. However something like P/1/abc/2 does not work anymore…. (no matching method error)


EDIT3: Finding — Optional Parameter of GET Method is not recognized if there is a POST Method existing

Now, I made an interesting observation. If I add an additonal POST Service to my service class the GET Service does NOT work (the URL P/abc/MyNumber returns no method found error), if I remove it works (the issues above occured because I was always using a POST method in addition):

 @GET
@Path("{Prefix}{p:/?}{id: ((\d )?)}/abc{p2:/?}{number: (([A-Za-z0-9]*)?)}")
public Response doAnything2() {
    return Response.ok("sdf").build();

}
/*with that code below the GET method does not work, if I remove it, it works*/
@POST
@Path("{Prefix}{p:/?}{id: ((\d )?)}/abc/{yeah}")
public Response doAnything3() {
    return Response.ok("sdf").build();

}
  

POST Кажется, что существование GET метода нарушает работу: это ошибка джерси?

Я тестирую свой код, используя Postman и явно устанавливаю GET метод. Как я могу решить эту проблему?

ПРАВКА 4: Ограниченный ответ

Учитывая следующий код:

 @POST
@Path("{Prefix2}{p4:/?}{id8: ((\d )?)}/abc/{yeah}")
public Response doAnything3() {
    return Response.ok("sdf").build();

}

@GET
@Path("{Prefix}{p:/?}{id: ((\d )?)}/abc{p2:/?}{number: (([A-Za-z0-9]*)?)}")
public Response doAnything2() {
    return Response.ok("sdf").build();

}
  

URL mypath/1/abc/dd Вызванный с помощью GET возвращает ошибку «Метод не найден».
Если я изменю метод, аннотированный с помощью POST, на

 /*adding the last to parameters as an optional parameters*/
@POST
@Path("{Prefix}{p:/?}{id: ((\d )?)}/abc{p8:/?}{number: (([A-Za-z0-9]*)?)}"
public Response doAnything3() {
    return Response.ok("sdf").build();

}

@GET
@Path("{Prefix}{p:/?}{id: ((\d )?)}/abc{p2:/?}{number: (([A-Za-z0-9]*)?)}")
public Response doAnything2() {
    return Response.ok("sdf").build();

}
  

решает проблему. Это грязный обходной путь (потому что последний используемый параметр POST не должен быть необязательным (см. Верхнюю часть вопроса)). Я не знаю, почему происходят эти странные вещи -> ответ должен прояснить, почему это происходит, и в ответе должно быть представлено хорошее решение.

Комментарии:

1. Первая мысль: вы пытались добавить только последнее «/»?

2. Да, не сработало….