Почему метод Джерси UriBuilder.build кодирует # и%, но не /?

У меня есть REST API, который довольно типичен, за исключением того, что идентификаторы ресурсов не целые числа, а строки, которые часто содержат символы /. Итак, если идентификатор клиента string/with/slashes, то URI для этого клиента должен быть http://localhost/customers/string%2Fwith%2Fslashes. При возврате списка клиентов я хочу создать этот URI с UriBuilder, чтобы я мог поместить его в href элементов ссылки в стиле ATOM. Но это не совсем работает; вот небольшой тестовый класс, который показывает, что я имею в виду:

@Path("/customers")
public class JerseyTest {

  @Path("{id}")
  public Customer getCustomer(@PathParam("{id}") String id) {
    return null;
  }

  public static void main(String[] args) {
    buildURI("string#with#hashes"); // => http://localhost/customers/string%23with%23hashes
    buildURI("string/with/slashes"); // => http://localhost/customers/string/with/slashes
  }

  public static void buildURI(String id) {
    UriBuilder builder = UriBuilder.fromUri("http://localhost");
    builder.path(JerseyTest.class).path(JerseyTest.class, "getCustomer");
    URI uri = builder.build(id);
    System.out.println(uri);
  }
}

# кодируются так, как я ожидал, а / - нет. Я попытался использовать вместо этого builder.build(URLEncoder.encode(id)), но затем UriBuilder кодирует %, так что вы получите .../string%252Fwith%252Fslashes!

Мне кажется непоследовательным, что он кодирует # и %, но не /, но я подозреваю, что для этого есть веская причина, которую я не вижу. Итак, мой вопрос:

  1. Как я могу заставить UriBuilder выдать мне .../string%2Fwith%2Fslashes, который является URI, который заставляет Джерси вызывать getCustomer с id равным string/with/slashes? изменить: я нашел способ решить эту проблему: builder.buildFromEncoded(URLEncoder.encode(id)). Но оставим этот вопрос открытым в надежде получить ответ на вторую часть ...
  2. В общем, почему UriBuilder.build кодирует одни специальные символы, а другие нет?

Я нашел Как мне закодировать значения параметров URI?, где принято ответ гласит: «Используйте UriBuilder». Ну, пользуюсь, но видимо неправильно использую.


person MatrixFrog    schedule 09.06.2011    source источник
comment
Снимок в темноте, но что произойдет, если вы используете экранированное значение юникода: buildURI("string\u002fwith\u002fslashes")?   -  person stand    schedule 09.06.2011
comment
Для информации: метод URI.toString изменяет адрес. URI.getPath не надо. Взгляните на com.sun.jersey.api.uri.UriComponent.encode(s, t), там выполняется преобразование в %7.... / являются частью URI, поэтому, возможно, есть способ избежать их. (Я продолжаю копать)   -  person yves amsellem    schedule 09.06.2011
comment
@stand Я почти уверен, что "string\u002fwith\u002fslashes" компилируется в тот же байт-код, что и "string/with/slashes", но попробовать стоит. Итак, я попробовал; такой же выход. Спасибо за идею!   -  person MatrixFrog    schedule 09.06.2011
comment
@yves Я нашел решение для части 1 и отредактировал его в вопросе. Дайте мне знать, если вы найдете что-нибудь, относящееся к части 2!   -  person MatrixFrog    schedule 09.06.2011
comment
Обратной стороной URLEncoder является то, что он заменяет пробелы на плюс (foo bar - ›foo + bar), где вы ожидаете% 20 (foo bar -› foo% 20bar)   -  person Daniel Hepper    schedule 20.07.2011


Ответы (1)


Кажется, это подтвержденная проблема:

http://java.net/jira/browse/JAX_RS_SPEC-70

Ваш обходной путь звучит хорошо.

person Doug Moscrop    schedule 01.09.2011
comment
Хорошая находка. По словам команды Джерси, это не ошибка в Джерси, но она требуется спецификацией JAX-RS, потому что они пытались исправить ее, но заметили, что TCK обеспечивает такое странное поведение. :( - person MatrixFrog; 01.09.2011