При создании веб-службы RESTful с использованием Spring MVC мне кажется, что я столкнулся с непростой ситуацией, когда пытался объединить десериализацию JSON Джексона и проверку bean-компонента JSR-303.
Одна из интересных особенностей JSR-Проверка 303 заключается в том, что можно возвращать все ошибки проверки, связанные с целевым объектом, а не просто потерпеть неудачу при первом нарушении ограничения (хотя существует режим быстрого отказа, если вы хотите его использовать).
Представьте себе сценарий, в котором у вас есть полезная нагрузка JSON, такая как:
{
"firstname": "Joe",
"surname": "Bloggs",
"age": 25
}
И затем у вас есть объект, который вы хотите сопоставить:
public class Person {
@NotNull
private String firstname;
@NotNull
private String surname;
@Min(value = 0)
private int age;
...
}
Моя проблемас этой настройкой так: если клиент отправляет String в качестве значения для "age", весь процесс десериализации Джексона завершится неудачно, не имея возможности конкретно указать причину, по которой он завершился неудачей (т.е. мы никогда не доберемся до проверки).Представьте себе такую полезную нагрузку:
{
"age": "invalid"
}
В этом случае я хотел бы получить ответ "ошибки", такой как:
{
"errors" : [
"error": {
"field": "firstname",
"message": "Must not be null",
},
"error": {
"field": "surname",
"message": "Must not be null",
},
"error": {
"field": "age",
"message": "Must be numeric value greater than or equal 0",
}
]
}
Простой способ обойтиэта проблема будет заключаться в том, чтобы просто указать поле age в качестве типа «String», а затем преобразовать значение при его передаче, скажем, на уровень постоянства.Тем не менее, мне не очень нравится идея прибегать к объектам передачи данных, которые используют строки единообразно - просто неправильно делать это с точки зрения сохранения чистого дизайна.
Еще один вариант, о котором я подумалбыло бы создать класс, такой как:
public abstract class BindableValue<T> {
private String stringValue;
private T value;
public T getValue() {
if(value == null) {
value = fromString(stringValue);
}
return value;
}
protected abstract T fromString(String stringValue);
}
Затем я мог бы создать реализации, такие как IntegerValue, LongValue, DateTimeValue и т. д., конечно, также писать адаптеры пользовательских типов для Джексона.И тогда мой класс Person может быть:
public class Person {
@NotNull
private StringValue firstname;
@NotNull
private StringValue surname;
@Min(value = 0)
private IntegerValue age;
...
}
Это почти то, что я хочу, но, к сожалению, аннотации JSR-303, такие как @NotNull и @Min, не будут распознавать мои реализации BindableValue.
Итак, кто-нибудь может объяснить, как я мог бы решить эту проблему более чистым способом?