Подтвердить что ты не робот

Как я могу эффективно поддерживать JSR-303 валидацию и сопоставление Jackson JSON?

При создании веб-службы RESTful с использованием Spring MVC я чувствую, что столкнулся с сложной ситуацией при попытке объединить десериализацию Jackson JSON и проверку JSR-303 bean.

Одна из опрятных вещей о проверке 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",
      }
   ]
}

Простым способом решения этой проблемы было бы просто указать поле "возраст" как тип "String", а затем преобразовать значение при его передаче, скажем, в слой сохранения. Тем не менее, мне не очень нравится идея использовать объекты передачи данных, которые используют Strings в обложке, - просто кажется, что это неправильно с точки зрения сохранения чистого дизайна.

Другой вариант, о котором я думал, - создать класс, например:

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 и т.д., конечно же, для написания адаптеров пользовательского типа для Jackson. И тогда мой класс Person мог бы быть:

public class Person {

   @NotNull
   private StringValue firstname;

   @NotNull
   private StringValue surname;

   @Min(value = 0)
   private IntegerValue age;

   ...
}

Это почти то, что я хочу, но, к сожалению, аннотации JSR-303, такие как @NotNull и @Min, не будут распознавать мои реализации BindableValue.

Итак, может ли кто-нибудь объяснить, как я мог бы решить эту проблему более чистым способом?

4b9b3361

Ответ 1

Теперь я понимаю, что наилучшим способом сделать это может быть просто использование Strings для всех полей, но инкапсулировать этот факт и по-прежнему предоставлять специализированные методы настройки и getters. например.

public class Person {

    @NotNull
    private String name;

    @NotNull
    @Min(value = 0)
    private String age;

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age != null ? new Integer(age) : null;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age == null ? null : String.valueOf(age);
    }

    @JsonSetter
    private void setAge(String age) {
        this.age = age;
    }
 }

Таким образом, я получаю поведение, которое я выполняю, в то время как объект public object по-прежнему "чист".

Ответ 2

Другая возможность заключается в том, чтобы просто отключить жалобы Джексона на непризнанные свойства (см. эту страницу wiki), "отказаться" от нераспознанных вещей и проверить достоверность это действительно связано. Вы также можете определить слушателя для непризнанных свойств. И затем вы можете использовать Bean Validation для проверки данных, которые получили привязку.

Ответ 3

Хорошо, так как это еще не упоминалось.... DropWizard - это путь, я думаю - он объединяет JAX- RS (Джерси) на Джексоне с Bean валидацией (спящий режим, я думаю), и все это "просто работает".