MultiException, когда исключение пользовательского jersey param исключает
ПРИМЕЧАНИЕ. Весь код для воспроизведения этой проблемы можно найти в https://gist.github.com/SrikanthRao/c9fc35e6fe22a74ab40c
http://localhost:8080/date/bean?date=2014-13-23 (используя BeanParam) производит
"{" code ": 500," message ":" Произошла ошибка обработки вашего запроса. Он был зарегистрирован (ID 48be9aa43bd49547). "}" Без добавления MultiExceptionMapper в трикотаж.
Если я добавлю MultiExceptionMapper в jersey, указанный выше URL-адрес приведет к
"Дата либо не в формате ГГГГ-ММ-ДД, либо недействительна"
http://localhost:8080/date?date=2014-13-23 (прямой параметр @QueryParam) производит
"Дата не указана в формате ГГГГ-ММ-ДД или недействительна"
Пара вопросов:
- Является ли это правильным способом обработки ввода с помощью более чистого способа?
- Я ожидал, что это сработает без необходимости добавления моего собственного MultiExceptionMapper. Не поддерживает ли Джерси пользовательские * Парамы внутри POJO, которые вводятся как @BeanParam в методах ресурсов?
Вот трассировка стека, создаваемая при запросе (без добавления MultiExceptionMapper в трикотаж). Конечно, удалены длинные следы. Дайте мне знать, если вам нужна полная трассировка стека.
ERROR [2015-05-04 18:48:33,366] io.dropwizard.jersey.errors.LoggingExceptionMapper: Error handling a request: 0f23e4de758653d6
! javax.ws.rs.WebApplicationException: HTTP 400 Bad Request
! at io.dropwizard.jersey.params.AbstractParam.<init>(AbstractParam.java:28) ~[dropwizard-jersey-0.8.1.jar:0.8.1]
! at com.fun.myapp.LocalDateTimeParam.<init>(LocalDateTimeParam.java:20) ~[classes/:na]
! at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_45]
...
...
Causing: org.glassfish.hk2.api.MultiException: A MultiException has 3 exceptions. They are:
! 1. javax.ws.rs.WebApplicationException: HTTP 400 Bad Request
! 2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.fun.myapp.PaginationFilters errors were found
! 3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.fun.myapp.PaginationFilters
!
! at org.jvnet.hk2.internal.Collector.throwIfErrors(Collector.java:88) ~[hk2-locator-2.4.0-b10.jar:na]
! at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:252) ~[hk2-locator-2.4.0-b10.jar:na]
! at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:360) ~[hk2-locator-2.4.0-b10.jar:na]
! at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471) ~[hk2-locator-2.4.0-b10.jar:na]
....
....
WARN [2015-05-04 18:48:33,401] org.glassfish.jersey.internal.Errors: The following warnings have been detected: WARNING: Unknown HK2 failure detected:
MultiException stack 1 of 3
javax.ws.rs.WebApplicationException: HTTP 400 Bad Request
at io.dropwizard.jersey.params.AbstractParam.<init>(AbstractParam.java:28)
at com.fun.myapp.LocalDateTimeParam.<init>(LocalDateTimeParam.java:20)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
...
...
MultiException stack 2 of 3
java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.fun.myapp.PaginationFilters errors were found
at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:249)
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:360)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471)
...
...
MultiException stack 3 of 3
java.lang.IllegalStateException: Unable to perform operation: resolve on com.fun.myapp.PaginationFilters
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:389)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471)
at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:162)
Я задал этот вопрос в группе google-группы dropwizard - https://groups.google.com/forum/#!topic/dropwizard-user/yW-RXSSlspY
Ответы
Ответ 1
Вопрос 1
В соответствии с документацией ядра dropwizard я вижу две возможные реализации для проверки ввода:
вы можете добавить аннотации проверки к полям ваших классов представления и проверить их...
Это не подходит для вашего дела. Фактически, нет никакой аннотации для LocalDateTime, и создание одного приводит к анализу LocalDateTime дважды: для проверки и для установки поля bean.
Если вы хотите большего контроля, вы также можете объявить JerseyProviders в своей среде для сопоставления Исключения с определенными ответами, вызвав файл JerseyEnvironment # register (Object) с реализацией javax.ws.rs.ext.ExceptionMapper...
Чтобы ответить на ваш первый вопрос, я бы сказал, что использование оптимизатора исключений отлично подходит для вашего случая.
Вопрос 2
Отладка методов isValidDate показывает, что версия @BeanParam использует ClazzCreator.java, а @QueryParam этого не делает. Этот класс отвечает за создание экземпляра класса bean. Если вы проверите строку 226 класс, вы увидите, что она собирает несколько исключений при анализе ввода с несколькими ошибками. Это должно позволить сообщать о нескольких ошибках, связанных с разными полями bean, включая некоторые последующие исключения.
Ответ заключается в том, что Jeysey поддерживает * Params внутри POJO. Однако связанное исключение инкапсулируется в MultiException в контексте @BeanParam.
Следовательно, если вы планируете добавлять другие поля в PaginationFilters, вам следует рассмотреть возможность представления нескольких ошибок в отображаемом сообщении об исключении.
Ответ 2
1/, чтобы подтвердить дату, я предпочитаю самостоятельно разбирать "даты". Это просто и чисто. Вот какой рабочий код:
package com.rizze.stackoverflow;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
@Path("/test")
public class TestRessource {
@GET
@Path("is")
@Produces({"application/json"})
public Response isDateValid(@QueryParam("date") String dateString){
if(dateString == null)
return Response.status(400).entity("date is null").build();
Date thedate =null;
try {
thedate = new SimpleDateFormat("yyyy-mm-dd").parse(dateString);
}
catch (ParseException e) {
return Response.status(400).entity("date malformed").build();
}
System.out.println("time:"+thedate.getTime());
return Response.ok()
.entity("{\"time\":"+ thedate.getTime() +"}")
.header("source", "com.rizze")
.build();
}
}
в этом коде вы вызываете
http://localhost:8080/test/is?date=2014-12-12
вернется:
{"time":1389496320000}
взгляните на gist: https://gist.github.com/jeorfevre/6e46ae8d9232f7f9d7cc
2/, чтобы поймать исключения, рекомендуется перехватить исключение на уровне сервера с помощью Провайдеров (зарегистрировав провайдера в своем приложении).
И для исключения на уровне приложения, используйте свое исключение самостоятельно, используя response.status(статус исключения).....
Пожалуйста, взгляните на мою вилку, я добавил _ServerError.class, и я зарегистрировал его в приложении:
//register a mapper by rizze
environment.jersey().register(_ServerError.class);
Пожалуйста, взгляните на официальный документ, который является четким:
официальный представитель dersey