Статьи

Последние улучшения в интеграции Jackson весной


Первоначально написано 
Себастьеном Делузом   в блоге SpringSource

 Поддержка Spring  Jackson была улучшена в последнее время, чтобы стать более гибкой и мощной. В этой записи блога содержится обновленная информация о наиболее полезных функциях, связанных с Jackson, доступных в Spring Framework 4.x и Spring Boot. Все примеры кода взяты из этого  демонстрационного  приложения Spring-Jackson-Demo , не стесняйтесь взглянуть на код.

Джексона .

В следующем примере показано, как использовать  @JsonView для фильтрации полей в зависимости от контекста сериализации — например, получить представление «сводки» при работе с коллекциями и получить полное представление при работе с одним ресурсом:

public class View {
    interface Summary {}
}

public class User {

    @JsonView(View.Summary.class)
    private Long id;

    @JsonView(View.Summary.class)
    private String firstname;

    @JsonView(View.Summary.class)
    private String lastname;

    private String email;
    private String address;
    private String postalCode;
    private String city;
    private String country;
}

public class Message {

    @JsonView(View.Summary.class)
    private Long id;

    @JsonView(View.Summary.class)
    private LocalDate created;

    @JsonView(View.Summary.class)
    private String title;

    @JsonView(View.Summary.class)
    private User author;

    private List<User> recipients;

    private String body;
}

Благодаря @JsonView поддержке Spring MVC  можно выбрать для каждого метода обработчика, какое поле должно быть сериализовано:

@RestController
public class MessageController {

    @Autowired
    private MessageService messageService;

    @JsonView(View.Summary.class)
    @RequestMapping("/")
    public List<Message> getAllMessages() {
        return messageService.getAll();
    }

    @RequestMapping("/{id}")
    public Message getMessage(@PathVariable Long id) {
        return messageService.get(id);
    }
}

В этом примере, если все сообщения получены, сериализуются только самые важные поля благодаря  getAllMessages() методу, помеченному как @JsonView(View.Summary.class):

[ {
  "id" : 1,
  "created" : "2014-11-14",
  "title" : "Info",
  "author" : {
    "id" : 1,
    "firstname" : "Brian",
    "lastname" : "Clozel"
  }
}, {
  "id" : 2,
  "created" : "2014-11-14",
  "title" : "Warning",
  "author" : {
    "id" : 2,
    "firstname" : "Stéphane",
    "lastname" : "Nicoll"
  }
}, {
  "id" : 3,
  "created" : "2014-11-14",
  "title" : "Alert",
  "author" : {
    "id" : 3,
    "firstname" : "Rossen",
    "lastname" : "Stoyanchev"
  }
} ]

В Spring MVC для конфигурации по умолчанию  MapperFeature.DEFAULT_VIEW_INCLUSION установлено значение false. Это означает, что при включении JSON View неаннотированные поля или свойства, такие как body или  recipients не сериализуемые.

Когда конкретный объект  Message извлекается с использованием  getMessage() метода-обработчика (не указан JSON View), все поля сериализуются, как и ожидалось:

{
  "id" : 1,
  "created" : "2014-11-14",
  "title" : "Info",
  "body" : "This is an information message",
  "author" : {
    "id" : 1,
    "firstname" : "Brian",
    "lastname" : "Clozel",
    "email" : "[email protected]",
    "address" : "1 Jaures street",
    "postalCode" : "69003",
    "city" : "Lyon",
    "country" : "France"
  },
  "recipients" : [ {
    "id" : 2,
    "firstname" : "Stéphane",
    "lastname" : "Nicoll",
    "email" : "[email protected]",
    "address" : "42 Obama street",
    "postalCode" : "1000",
    "city" : "Brussel",
    "country" : "Belgium"
  }, {
    "id" : 3,
    "firstname" : "Rossen",
    "lastname" : "Stoyanchev",
    "email" : "[email protected]",
    "address" : "3 Warren street",
    "postalCode" : "10011",
    "city" : "New York",
    "country" : "USA"
  } ]
}

В @JsonView аннотации можно указать только один класс или интерфейс  , но вы можете использовать наследование для представления иерархий JSON View (если поле является частью JSON View, оно также будет частью родительского представления). Например, этот метод-обработчик будет сериализовать поля, отмеченные @JsonView(View.Summary.class) и  @JsonView(View.SummaryWithRecipients.class):

public class View {
    interface Summary {}
    interface SummaryWithRecipients extends Summary {}
}

public class Message {

    @JsonView(View.Summary.class)
    private Long id;

    @JsonView(View.Summary.class)
    private LocalDate created;

    @JsonView(View.Summary.class)
    private String title;

    @JsonView(View.Summary.class)
    private User author;

    @JsonView(View.SummaryWithRecipients.class)
    private List<User> recipients;

    private String body;
}

@RestController
public class MessageController {

    @Autowired
    private MessageService messageService;

    @JsonView(View.SummaryWithRecipients.class)
    @RequestMapping("/with-recipients")
    public List<Message> getAllMessagesWithRecipients() {
        return messageService.getAll();
    }
}

Представления JSON также могут быть указаны при использовании  RestTemplate HTTP-клиента или MappingJackson2JsonView путем помещения значения для сериализации в,  MappingJacksonValue как показано в этом  примере кода .

справочной документации , вы можете включить  JSONP  для  @ResponseBody и ResponseEntity методы, объявив  @ControllerAdvice компонент, который расширяется, AbstractJsonpResponseBodyAdvice как показано ниже:

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

    public JsonpAdvice() {
        super("callback");
    }
}

После регистрации такого  @ControllerAdvice компонента будет возможно запросить веб-службу JSON из другого домена с помощью  <script /> тега:

<script type="application/javascript"
            src="http://mydomain.com/1.json?jsonp=parseResponse">
</script>

В этом примере полученная полезная нагрузка будет:

parseResponse({
  "id" : 1,
  "created" : "2014-11-14",
  ...
});

JSONP также поддерживается и автоматически включается при использовании  MappingJackson2JsonViewс запросом, у которого есть параметр запроса с именем jsonp или callback. Имена параметров запроса JSONP можно настроить с помощью  jsonpParameterNames свойства.

jackson-dataformat-xml зависимость в ваш проект, она автоматически используется вместо JAXB2.

Использование расширения Jackson XML имеет несколько преимуществ перед JAXB2:

  • Аннотации Джексона и JAXB признаны
  • Поддерживаются JSON View, что позволяет легко создавать веб-сервисы REST с одинаковым фильтрованным выводом для форматов данных XML и JSON.
  • Нет необходимости аннотировать ваш класс  @XmlRootElement, каждый класс, сериализуемый в JSON, будет сериализуем в XML

Обычно вы также хотите убедиться, что используемой библиотекой XML является Woodstox, поскольку:

  • Это быстрее, чем реализация Stax, предоставляемая JDK
  • Это позволяет избежать некоторых известных проблем, таких как добавление ненужных префиксов пространства имен
  • Некоторые функции, такие как красивая печать, не работают без нее

Чтобы использовать его, просто добавьте последнюю  woodstox-core-asl доступную зависимость для вашего проекта.

Jackson2ObjectMapperBuilder была введена новая  . Это эквивалент JavaConfig хорошо известного,  Jackson2ObjectMapperFactoryBean используемого в конфигурации XML.

Jackson2ObjectMapperBuilder предоставляет приятный API для настройки различных параметров Jackson, сохраняя Spring Framework по умолчанию. Это также позволяет создавать ObjectMapper и  XmlMapper экземпляры, основанные на той же конфигурации.

И то, Jackson2ObjectMapperBuilder и  другое  Jackson2ObjectMapperFactoryBean определяет лучшую конфигурацию Джексона по умолчанию. Например, для DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES свойства установлено значение false, чтобы разрешить десериализацию объектов JSON с несопоставленными свойствами.

Поддержка Джексоном типов данных API даты и времени Java 8 автоматически регистрируется при использовании Java 8 и  jackson-datatype-jsr310 находится на пути к классам. Поддержка Joda-Time также регистрируется, когда она  jackson-datatype-joda является частью вашего проекта.

Эти классы также позволяют легко регистрировать миксины Джексона  модулисериализаторы  или даже стратегии именования свойств, например,  PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES если вы хотите userName преобразовать свое  свойство java  user_name в JSON.

настройки Jackson ObjectMapper .

Например , вы можете включить / выключить Джексон особенности легко добавляя свойства , как spring.jackson.serialization.indent_output=true в  application.properties.

В качестве альтернативы, в следующей версии 1.2 Spring Boot также позволяет настроить конфигурацию Джексона (JSON и XML), используемую Spring MVC  HttpMessageConverter, объявив  Jackson2ObjectMapperBuilder @Bean:

@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
    return builder;
}

Это полезно, если вы хотите использовать расширенную конфигурацию Джексона, не доступную через обычные ключи конфигурации.

HandlerInstantiator (см.  SPR-10768  для более подробной информации) вы сможете автоматически связывать обработчики Jackson (сериализаторы, десериализаторы, преобразователи идентификаторов типов и типов).

Это позволит вам создать, например, пользовательский десериализатор, который заменит поле, содержащее только ссылку в полезной нагрузке JSON, на полное,  Entity извлеченное из базы данных.