Exemplos de anotações de Jackson

Exemplos de anotações de Jackson

1. Visão geral

Neste artigo, vamos mergulhar profundamente emJackson Annotations.

Veremos como usar as anotações existentes, como criar anotações personalizadas e, finalmente, como desativá-las.

Leitura adicional:

Mais anotações de Jackson

Este artigo aborda algumas anotações de processamento JSON menos conhecidas fornecidas por Jackson.

Read more

Jackson - Relacionamentos bidirecionais

Como usar Jackson para quebrar o problema da recursão infinita em relacionamentos bidirecionais.

Read more

Introdução à desserialização personalizada em Jackson

Use Jackson para mapear JSON personalizado para qualquer gráfico de entidade java com controle total sobre o processo de desserialização.

Read more

2. Jackson Serialization Annotations

Primeiro, vamos dar uma olhada nas anotações de serialização.

2.1. @JsonAnyGetter

A anotação@JsonAnyGetter permite a flexibilidade de usar um campoMap como propriedades padrão.

Aqui está um exemplo rápido - a entidadeExtendableBean tem a propriedadename e um conjunto de atributos extensíveis na forma de pares chave / valor:

public class ExtendableBean {
    public String name;
    private Map properties;

    @JsonAnyGetter
    public Map getProperties() {
        return properties;
    }
}

Quando serializamos uma instância dessa entidade, obtemos todos os valores-chave emMap como propriedades simples e padrão:

{
    "name":"My bean",
    "attr2":"val2",
    "attr1":"val1"
}

E aqui como a serialização dessa entidade se parece na prática:

@Test
public void whenSerializingUsingJsonAnyGetter_thenCorrect()
  throws JsonProcessingException {

    ExtendableBean bean = new ExtendableBean("My bean");
    bean.add("attr1", "val1");
    bean.add("attr2", "val2");

    String result = new ObjectMapper().writeValueAsString(bean);

    assertThat(result, containsString("attr1"));
    assertThat(result, containsString("val1"));
}

Também podemos usar o argumento opcionalenabled comofalse para desativar@JsonAnyGetter(). Nesse caso, oMap será convertido como JSON e aparecerá na variávelproperties após serialização.

2.2. @JsonGetter

A anotação@JsonGetter é uma alternativa à anotação@JsonProperty para marcar um método como um método getter.

No exemplo a seguir - especificamos o métodogetTheName() como o método getter da propriedadename da entidadeMyBean:

public class MyBean {
    public int id;
    private String name;

    @JsonGetter("name")
    public String getTheName() {
        return name;
    }
}

E aqui está como isso funciona na prática:

@Test
public void whenSerializingUsingJsonGetter_thenCorrect()
  throws JsonProcessingException {

    MyBean bean = new MyBean(1, "My bean");

    String result = new ObjectMapper().writeValueAsString(bean);

    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("1"));
}

2.3. @JsonPropertyOrder

Podemos usar a anotação@JsonPropertyOrder para especificarthe order of properties on serialization.

Vamos definir uma ordem personalizada para as propriedades de uma entidadeMyBean:

@JsonPropertyOrder({ "name", "id" })
public class MyBean {
    public int id;
    public String name;
}

E aqui está a saída da serialização:

{
    "name":"My bean",
    "id":1
}

E um teste simples:

@Test
public void whenSerializingUsingJsonPropertyOrder_thenCorrect()
  throws JsonProcessingException {

    MyBean bean = new MyBean(1, "My bean");

    String result = new ObjectMapper().writeValueAsString(bean);
    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("1"));
}

Também podemos usar@JsonPropertyOrder(alphabetic=true) para ordenar as propriedades em ordem alfabética. E nesse caso, a saída da serialização será:

{
    "id":1,
    "name":"My bean"
}

2.4. @JsonRawValue

A anotação@JsonRawValue podeinstruct Jackson to serialize a property exactly as is.

No exemplo a seguir, usamos@JsonRawValue para incorporar algum JSON personalizado como um valor de uma entidade:

public class RawBean {
    public String name;

    @JsonRawValue
    public String json;
}

A saída de serializar a entidade é:

{
    "name":"My bean",
    "json":{
        "attr":false
    }
}

E um teste simples:

@Test
public void whenSerializingUsingJsonRawValue_thenCorrect()
  throws JsonProcessingException {

    RawBean bean = new RawBean("My bean", "{\"attr\":false}");

    String result = new ObjectMapper().writeValueAsString(bean);
    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("{\"attr\":false}"));
}

Também podemos usar o argumento booleano opcionalvalue que define se esta anotação está ativa ou não.

2.5. @JsonValue

@JsonValue indica um único método que a biblioteca usará para serializar a instância inteira.

Por exemplo, em um enum, anotamosgetName com@JsonValue para que qualquer entidade seja serializada por meio de seu nome:

public enum TypeEnumWithValue {
    TYPE1(1, "Type A"), TYPE2(2, "Type 2");

    private Integer id;
    private String name;

    // standard constructors

    @JsonValue
    public String getName() {
        return name;
    }
}

Nosso teste:

@Test
public void whenSerializingUsingJsonValue_thenCorrect()
  throws JsonParseException, IOException {

    String enumAsString = new ObjectMapper()
      .writeValueAsString(TypeEnumWithValue.TYPE1);

    assertThat(enumAsString, is(""Type A""));
}

2.6. @JsonRootName

A anotação@JsonRootName é usada - se o wrapper estiver habilitado - para especificar o nome do wrapper raiz a ser usado.

Empacotamento significa que, em vez de serializar aUser para algo como:

{
    "id": 1,
    "name": "John"
}

Vai ser embrulhado assim:

{
    "User": {
        "id": 1,
        "name": "John"
    }
}

Então, vamos ver um exemplo -we’re going to use the @JsonRootName annotation to indicate the name of this potential wrapper entity:

@JsonRootName(value = "user")
public class UserWithRoot {
    public int id;
    public String name;
}

Por padrão, o nome do wrapper seria o nome da classe -UserWithRoot. Usando a anotação, obtemos a aparência mais limpauser:

@Test
public void whenSerializingUsingJsonRootName_thenCorrect()
  throws JsonProcessingException {

    UserWithRoot user = new User(1, "John");

    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
    String result = mapper.writeValueAsString(user);

    assertThat(result, containsString("John"));
    assertThat(result, containsString("user"));
}

Aqui está a saída da serialização:

{
    "user":{
        "id":1,
        "name":"John"
    }
}

Desde Jackson 2.4, um novo argumento opcionalnamespace está disponível para uso com formatos de dados como XML. Se o adicionarmos, ele se tornará parte do nome completo:

@JsonRootName(value = "user", namespace="users")
public class UserWithRootNamespace {
    public int id;
    public String name;

    // ...
}

Se o serializarmos comXmlMapper, a saída será:


    1
    John
    

2.7. @JsonSerialize

@JsonSerialize indicates a custom serializer to use when empacotandothe entity.

Vejamos um exemplo rápido. Vamos usar@JsonSerialize para serializar a propriedadeeventDate com umCustomDateSerializer:

public class EventWithSerializer {
    public String name;

    @JsonSerialize(using = CustomDateSerializer.class)
    public Date eventDate;
}

Aqui está o serializador Jackson personalizado simples:

public class CustomDateSerializer extends StdSerializer {

    private static SimpleDateFormat formatter
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateSerializer() {
        this(null);
    }

    public CustomDateSerializer(Class t) {
        super(t);
    }

    @Override
    public void serialize(
      Date value, JsonGenerator gen, SerializerProvider arg2)
      throws IOException, JsonProcessingException {
        gen.writeString(formatter.format(value));
    }
}

Vamos usá-los em um teste:

@Test
public void whenSerializingUsingJsonSerialize_thenCorrect()
  throws JsonProcessingException, ParseException {

    SimpleDateFormat df
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    String toParse = "20-12-2014 02:30:00";
    Date date = df.parse(toParse);
    EventWithSerializer event = new EventWithSerializer("party", date);

    String result = new ObjectMapper().writeValueAsString(event);
    assertThat(result, containsString(toParse));
}

3. Anotações de desserialização de Jackson

A seguir - vamos explorar as anotações de desserialização de Jackson.

3.1. @JsonCreator

Podemos usar a anotação@JsonCreator para ajustar o construtor / fábrica usado na desserialização.

É muito útil quando precisamos desserializar algum JSON que não corresponda exatamente à entidade de destino que precisamos obter.

Vejamos um exemplo; digamos que precisamos desserializar o seguinte JSON:

{
    "id":1,
    "theName":"My bean"
}

No entanto, não há campotheName em nossa entidade de destino - há apenas um camponame. Agora, não queremos alterar a própria entidade - precisamos apenas de um pouco mais de controle sobre o processo de desempacotamento - anotando o construtor com@JsonCreatore usando a anotação@JsonProperty também:

public class BeanWithCreator {
    public int id;
    public String name;

    @JsonCreator
    public BeanWithCreator(
      @JsonProperty("id") int id,
      @JsonProperty("theName") String name) {
        this.id = id;
        this.name = name;
    }
}

Vamos ver isso em ação:

@Test
public void whenDeserializingUsingJsonCreator_thenCorrect()
  throws IOException {

    String json = "{\"id\":1,\"theName\":\"My bean\"}";

    BeanWithCreator bean = new ObjectMapper()
      .readerFor(BeanWithCreator.class)
      .readValue(json);
    assertEquals("My bean", bean.name);
}

3.2. @JacksonInject

@JacksonInject indica que uma propriedade obterá seu valor da injeção e não dos dados JSON.

No exemplo a seguir - usamos@JacksonInject para injetar a propriedadeid:

public class BeanWithInject {
    @JacksonInject
    public int id;

    public String name;
}

E é assim que funciona:

@Test
public void whenDeserializingUsingJsonInject_thenCorrect()
  throws IOException {

    String json = "{\"name\":\"My bean\"}";

    InjectableValues inject = new InjectableValues.Std()
      .addValue(int.class, 1);
    BeanWithInject bean = new ObjectMapper().reader(inject)
      .forType(BeanWithInject.class)
      .readValue(json);

    assertEquals("My bean", bean.name);
    assertEquals(1, bean.id);
}

3.3. @JsonAnySetter

@JsonAnySetter nos permite a flexibilidade de usarMap como propriedades padrão. Na desserialização, as propriedades do JSON serão simplesmente adicionadas ao mapa.

Vamos ver como isso funciona - usaremos@JsonAnySetter para desserializar a entidadeExtendableBean:

public class ExtendableBean {
    public String name;
    private Map properties;

    @JsonAnySetter
    public void add(String key, String value) {
        properties.put(key, value);
    }
}

Este é o JSON que precisamos desserializar:

{
    "name":"My bean",
    "attr2":"val2",
    "attr1":"val1"
}

E aqui está como tudo se conecta:

@Test
public void whenDeserializingUsingJsonAnySetter_thenCorrect()
  throws IOException {
    String json
      = "{\"name\":\"My bean\",\"attr2\":\"val2\",\"attr1\":\"val1\"}";

    ExtendableBean bean = new ObjectMapper()
      .readerFor(ExtendableBean.class)
      .readValue(json);

    assertEquals("My bean", bean.name);
    assertEquals("val2", bean.getProperties().get("attr2"));
}

3.4. @JsonSetter

@JsonSetter é uma alternativa a@JsonProperty - que marca o método como um método setter.

Isso é muito útil quando precisamos ler alguns dados JSON, excetothe target entity class doesn’t exactly match that data, e então precisamos ajustar o processo para torná-lo adequado.

No exemplo a seguir, especificaremos o método setTheName() como o configurador da propriedadename em nossa entidadeMyBean:

public class MyBean {
    public int id;
    private String name;

    @JsonSetter("name")
    public void setTheName(String name) {
        this.name = name;
    }
}

Agora, quando precisamos desselecionar alguns dados JSON - isso funciona perfeitamente:

@Test
public void whenDeserializingUsingJsonSetter_thenCorrect()
  throws IOException {

    String json = "{\"id\":1,\"name\":\"My bean\"}";

    MyBean bean = new ObjectMapper()
      .readerFor(MyBean.class)
      .readValue(json);
    assertEquals("My bean", bean.getTheName());
}

3.5. @JsonDeserialize

@JsonDeserialize indica o uso de um desserializador personalizado.

Vamos ver como isso funciona - usaremos@JsonDeserialize para desserializar a propriedadeeventDate comCustomDateDeserializer:

public class EventWithSerializer {
    public String name;

    @JsonDeserialize(using = CustomDateDeserializer.class)
    public Date eventDate;
}

Este é o desserializador personalizado:

public class CustomDateDeserializer
  extends StdDeserializer {

    private static SimpleDateFormat formatter
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateDeserializer() {
        this(null);
    }

    public CustomDateDeserializer(Class vc) {
        super(vc);
    }

    @Override
    public Date deserialize(
      JsonParser jsonparser, DeserializationContext context)
      throws IOException {

        String date = jsonparser.getText();
        try {
            return formatter.parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}

E aqui está o teste consecutivo:

@Test
public void whenDeserializingUsingJsonDeserialize_thenCorrect()
  throws IOException {

    String json
      = "{"name":"party","eventDate":"20-12-2014 02:30:00"}";

    SimpleDateFormat df
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
    EventWithSerializer event = new ObjectMapper()
      .readerFor(EventWithSerializer.class)
      .readValue(json);

    assertEquals(
      "20-12-2014 02:30:00", df.format(event.eventDate));
}

3.6 @JsonAlias

O@JsonAlias defineone or more alternative names for a property during deserialization.

Vejamos como essa anotação funciona com um exemplo rápido:

public class AliasBean {
    @JsonAlias({ "fName", "f_name" })
    private String firstName;
    private String lastName;
}

Aqui, temos um POJO e queremos desserializar JSON com valores comofName,f_name efirstName na variávelfirstName do POJO.

E aqui está um teste para garantir que esta anotação funcione conforme o esperado:

@Test
public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException {
    String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";
    AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);
    assertEquals("John", aliasBean.getFirstName());
}

4. Jackson Property Inclusion Annotations

4.1. @JsonIgnoreProperties

@JsonIgnoreProperties é uma anotação em nível de classe que marca uma propriedade ou uma lista de propriedades que Jackson irá ignorar.

Vejamos um exemplo rápido ignorando a propriedadeid da serialização:

@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
    public int id;
    public String name;
}

E aqui está o teste para garantir que o ignorar aconteça

@Test
public void whenSerializingUsingJsonIgnoreProperties_thenCorrect()
  throws JsonProcessingException {

    BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");

    String result = new ObjectMapper()
      .writeValueAsString(bean);

    assertThat(result, containsString("My bean"));
    assertThat(result, not(containsString("id")));
}

Para ignorar quaisquer propriedades desconhecidas na entrada JSON sem exceção, podemos definirignoreUnknown=true de@JsonIgnoreProperties annotation.

4.2. @JsonIgnore

A anotação@JsonIgnore é usada para marcar uma propriedade a ser ignorada no nível do campo.

Vamos usar@JsonIgnore para ignorar a propriedadeid da serialização:

public class BeanWithIgnore {
    @JsonIgnore
    public int id;

    public String name;
}

E o teste certificando-se de queid foi ignorado com sucesso:

@Test
public void whenSerializingUsingJsonIgnore_thenCorrect()
  throws JsonProcessingException {

    BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");

    String result = new ObjectMapper()
      .writeValueAsString(bean);

    assertThat(result, containsString("My bean"));
    assertThat(result, not(containsString("id")));
}

4.3. @JsonIgnoreType

@JsonIgnoreType marca todas as propriedades de um tipo anotado para serem ignoradas.

Vamos usar a anotação para marcar todas as propriedades do tipoName a serem ignoradas:

public class User {
    public int id;
    public Name name;

    @JsonIgnoreType
    public static class Name {
        public String firstName;
        public String lastName;
    }
}

Este é o teste simples para garantir que ignorar funcione corretamente:

@Test
public void whenSerializingUsingJsonIgnoreType_thenCorrect()
  throws JsonProcessingException, ParseException {

    User.Name name = new User.Name("John", "Doe");
    User user = new User(1, name);

    String result = new ObjectMapper()
      .writeValueAsString(user);

    assertThat(result, containsString("1"));
    assertThat(result, not(containsString("name")));
    assertThat(result, not(containsString("John")));
}

4.4. @JsonInclude

Podemos usar@JsonInclude para excluir propriedades com valores vazios / nulos / padrão.

Vejamos um exemplo - excluindo nulos da serialização:

@JsonInclude(Include.NON_NULL)
public class MyBean {
    public int id;
    public String name;
}

Aqui está o teste completo:

public void whenSerializingUsingJsonInclude_thenCorrect()
  throws JsonProcessingException {

    MyBean bean = new MyBean(1, null);

    String result = new ObjectMapper()
      .writeValueAsString(bean);

    assertThat(result, containsString("1"));
    assertThat(result, not(containsString("name")));
}

4.5. @JsonAutoDetect

@JsonAutoDetect pode substituir a semântica padrão dewhich properties are visible and which are not.

Vamos dar uma olhada em como a anotação pode ser muito útil com um exemplo simples - vamos habilitar a serialização de propriedades privadas:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class PrivateBean {
    private int id;
    private String name;
}

E o teste:

@Test
public void whenSerializingUsingJsonAutoDetect_thenCorrect()
  throws JsonProcessingException {

    PrivateBean bean = new PrivateBean(1, "My bean");

    String result = new ObjectMapper()
      .writeValueAsString(bean);

    assertThat(result, containsString("1"));
    assertThat(result, containsString("My bean"));
}

5. Anotações de manipulação de tipo polimórfico de Jackson

A seguir - vamos dar uma olhada nas anotações de manipulação de tipo polimórfico de Jackson:

  • @JsonTypeInfo - indica detalhes de que tipo de informação incluir na serialização

  • @JsonSubTypes - indica subtipos do tipo anotado

  • @JsonTypeName - define um nome de tipo lógico a ser usado para a classe anotada

Vejamos um exemplo mais complexo e use todos os três -@JsonTypeInfo,@JsonSubTypes,e@JsonTypeName – para serializar / desserializar a entidadeZoo:

public class Zoo {
    public Animal animal;

    @JsonTypeInfo(
      use = JsonTypeInfo.Id.NAME,
      include = As.PROPERTY,
      property = "type")
    @JsonSubTypes({
        @JsonSubTypes.Type(value = Dog.class, name = "dog"),
        @JsonSubTypes.Type(value = Cat.class, name = "cat")
    })
    public static class Animal {
        public String name;
    }

    @JsonTypeName("dog")
    public static class Dog extends Animal {
        public double barkVolume;
    }

    @JsonTypeName("cat")
    public static class Cat extends Animal {
        boolean likesCream;
        public int lives;
    }
}

Quando fazemos serialização:

@Test
public void whenSerializingPolymorphic_thenCorrect()
  throws JsonProcessingException {
    Zoo.Dog dog = new Zoo.Dog("lacy");
    Zoo zoo = new Zoo(dog);

    String result = new ObjectMapper()
      .writeValueAsString(zoo);

    assertThat(result, containsString("type"));
    assertThat(result, containsString("dog"));
}

Aqui está o que serializar a instânciaZoo comDog resultará em:

{
    "animal": {
        "type": "dog",
        "name": "lacy",
        "barkVolume": 0
    }
}

Agora, para a desserialização - vamos começar com a seguinte entrada JSON:

{
    "animal":{
        "name":"lacy",
        "type":"cat"
    }
}

E vamos ver como isso é desempacotado para uma instânciaZoo:

@Test
public void whenDeserializingPolymorphic_thenCorrect()
throws IOException {
    String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}";

    Zoo zoo = new ObjectMapper()
      .readerFor(Zoo.class)
      .readValue(json);

    assertEquals("lacy", zoo.animal.name);
    assertEquals(Zoo.Cat.class, zoo.animal.getClass());
}

6. Jackson General Annotations

A seguir - vamos discutir algumas das anotações mais gerais de Jackson.

6.1. @JsonProperty

Podemos adicionarthe @JsonProperty annotation to indicate the property name in JSON.

Vamos usar@JsonProperty para serializar / desserializar a propriedadename quando estivermos lidando com getters e setters não padrão:

public class MyBean {
    public int id;
    private String name;

    @JsonProperty("name")
    public void setTheName(String name) {
        this.name = name;
    }

    @JsonProperty("name")
    public String getTheName() {
        return name;
    }
}

Nosso teste:

@Test
public void whenUsingJsonProperty_thenCorrect()
  throws IOException {
    MyBean bean = new MyBean(1, "My bean");

    String result = new ObjectMapper().writeValueAsString(bean);

    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("1"));

    MyBean resultBean = new ObjectMapper()
      .readerFor(MyBean.class)
      .readValue(result);
    assertEquals("My bean", resultBean.getTheName());
}

6.2. @JsonFormat

A anotação@JsonFormat especifica um formato ao serializar valores de data / hora.

No exemplo a seguir - usamos@JsonFormat para controlar o formato da propriedadeeventDate:

public class EventWithFormat {
    public String name;

    @JsonFormat(
      shape = JsonFormat.Shape.STRING,
      pattern = "dd-MM-yyyy hh:mm:ss")
    public Date eventDate;
}

E aqui está o teste:

@Test
public void whenSerializingUsingJsonFormat_thenCorrect()
  throws JsonProcessingException, ParseException {
    SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
    df.setTimeZone(TimeZone.getTimeZone("UTC"));

    String toParse = "20-12-2014 02:30:00";
    Date date = df.parse(toParse);
    EventWithFormat event = new EventWithFormat("party", date);

    String result = new ObjectMapper().writeValueAsString(event);

    assertThat(result, containsString(toParse));
}

6.3. @JsonUnwrapped

@JsonUnwrapped define valores que devem ser desembrulhados / nivelados quando serializados / desserializados.

Vamos ver exatamente como isso funciona; usaremos a anotação para desembrulhar a propriedadename:

public class UnwrappedUser {
    public int id;

    @JsonUnwrapped
    public Name name;

    public static class Name {
        public String firstName;
        public String lastName;
    }
}

Agora vamos serializar uma instância desta classe:

@Test
public void whenSerializingUsingJsonUnwrapped_thenCorrect()
  throws JsonProcessingException, ParseException {
    UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe");
    UnwrappedUser user = new UnwrappedUser(1, name);

    String result = new ObjectMapper().writeValueAsString(user);

    assertThat(result, containsString("John"));
    assertThat(result, not(containsString("name")));
}

Esta é a aparência da saída - os campos da classe aninhada estática desembrulhada junto com o outro campo:

{
    "id":1,
    "firstName":"John",
    "lastName":"Doe"
}

6.4. @JsonView

@JsonView indica a visualização na qual a propriedade será incluída para serialização / desserialização.

Um exemplo mostrará exatamente como isso funciona - usaremos@JsonView para serializar uma instância da entidadeItem.

Vamos começar com as visualizações:

public class Views {
    public static class Public {}
    public static class Internal extends Public {}
}

E agora aqui está a entidadeItem, usando as visualizações:

public class Item {
    @JsonView(Views.Public.class)
    public int id;

    @JsonView(Views.Public.class)
    public String itemName;

    @JsonView(Views.Internal.class)
    public String ownerName;
}

Finalmente - o teste completo:

@Test
public void whenSerializingUsingJsonView_thenCorrect()
  throws JsonProcessingException {
    Item item = new Item(2, "book", "John");

    String result = new ObjectMapper()
      .writerWithView(Views.Public.class)
      .writeValueAsString(item);

    assertThat(result, containsString("book"));
    assertThat(result, containsString("2"));
    assertThat(result, not(containsString("John")));
}

6.5. @JsonManagedReference, @JsonBackReference

The @JsonManagedReference and @JsonBackReference annotations can handle parent/child relationshipse contornar loops.

No exemplo a seguir - usamos@JsonManagedReferencee@JsonBackReference para serializar nossa entidadeItemWithRef:

public class ItemWithRef {
    public int id;
    public String itemName;

    @JsonManagedReference
    public UserWithRef owner;
}

Nossa entidadeUserWithRef:

public class UserWithRef {
    public int id;
    public String name;

    @JsonBackReference
    public List userItems;
}

E o teste:

@Test
public void whenSerializingUsingJacksonReferenceAnnotation_thenCorrect()
  throws JsonProcessingException {
    UserWithRef user = new UserWithRef(1, "John");
    ItemWithRef item = new ItemWithRef(2, "book", user);
    user.addItem(item);

    String result = new ObjectMapper().writeValueAsString(item);

    assertThat(result, containsString("book"));
    assertThat(result, containsString("John"));
    assertThat(result, not(containsString("userItems")));
}

6.6. @JsonIdentityInfo

@JsonIdentityInfo indica que a identidade do objeto deve ser usada ao serializar / desserializar valores - por exemplo, para lidar com tipos de problemas de recursão infinita.

No exemplo a seguir - temos uma entidadeItemWithIdentity com relação bidirecionala com a entidadeUserWithIdentity:

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class,
  property = "id")
public class ItemWithIdentity {
    public int id;
    public String itemName;
    public UserWithIdentity owner;
}

E a entidadeUserWithIdentity:

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class,
  property = "id")
public class UserWithIdentity {
    public int id;
    public String name;
    public List userItems;
}

Agora,let’s see how the infinite recursion problem is handled:

@Test
public void whenSerializingUsingJsonIdentityInfo_thenCorrect()
  throws JsonProcessingException {
    UserWithIdentity user = new UserWithIdentity(1, "John");
    ItemWithIdentity item = new ItemWithIdentity(2, "book", user);
    user.addItem(item);

    String result = new ObjectMapper().writeValueAsString(item);

    assertThat(result, containsString("book"));
    assertThat(result, containsString("John"));
    assertThat(result, containsString("userItems"));
}

Aqui está o resultado completo do item serializado e do usuário:

{
    "id": 2,
    "itemName": "book",
    "owner": {
        "id": 1,
        "name": "John",
        "userItems": [
            2
        ]
    }
}

6.7. @JsonFilter

A anotação@JsonFilter especifica um filtro a ser usado durante a serialização.

Vamos dar uma olhada em um exemplo; primeiro, definimos a entidade e apontamos para o filtro:

@JsonFilter("myFilter")
public class BeanWithFilter {
    public int id;
    public String name;
}

Agora, no teste completo, definimos o filtro - que exclui todas as outras propriedades, excetoname da serialização:

@Test
public void whenSerializingUsingJsonFilter_thenCorrect()
  throws JsonProcessingException {
    BeanWithFilter bean = new BeanWithFilter(1, "My bean");

    FilterProvider filters
      = new SimpleFilterProvider().addFilter(
        "myFilter",
        SimpleBeanPropertyFilter.filterOutAllExcept("name"));

    String result = new ObjectMapper()
      .writer(filters)
      .writeValueAsString(bean);

    assertThat(result, containsString("My bean"));
    assertThat(result, not(containsString("id")));
}

7. Anotação Jackson Personalizada

A seguir, vamos ver como criar uma anotação Jackson personalizada. We can make use of the @JacksonAnnotationsInside annotation:

@Retention(RetentionPolicy.RUNTIME)
    @JacksonAnnotationsInside
    @JsonInclude(Include.NON_NULL)
    @JsonPropertyOrder({ "name", "id", "dateCreated" })
    public @interface CustomAnnotation {}

Agora, se usarmos a nova anotação em uma entidade:

@CustomAnnotation
public class BeanWithCustomAnnotation {
    public int id;
    public String name;
    public Date dateCreated;
}

Podemos ver como ele combina as anotações existentes em uma mais simples e personalizada que podemos usar como uma abreviação:

@Test
public void whenSerializingUsingCustomAnnotation_thenCorrect()
  throws JsonProcessingException {
    BeanWithCustomAnnotation bean
      = new BeanWithCustomAnnotation(1, "My bean", null);

    String result = new ObjectMapper().writeValueAsString(bean);

    assertThat(result, containsString("My bean"));
    assertThat(result, containsString("1"));
    assertThat(result, not(containsString("dateCreated")));
}

A saída do processo de serialização:

{
    "name":"My bean",
    "id":1
}

8. Jackson MixIn Annotations

A seguir - vamos ver como usar as anotações Jackson MixIn.

Vamos usar as anotações MixIn para - por exemplo - ignorar propriedades do tipoUser:

public class Item {
    public int id;
    public String itemName;
    public User owner;
}
@JsonIgnoreType
public class MyMixInForIgnoreType {}

Vamos ver isso em ação:

@Test
public void whenSerializingUsingMixInAnnotation_thenCorrect()
  throws JsonProcessingException {
    Item item = new Item(1, "book", null);

    String result = new ObjectMapper().writeValueAsString(item);
    assertThat(result, containsString("owner"));

    ObjectMapper mapper = new ObjectMapper();
    mapper.addMixIn(User.class, MyMixInForIgnoreType.class);

    result = mapper.writeValueAsString(item);
    assertThat(result, not(containsString("owner")));
}

9. Desativar anotação de Jackson

Finalmente - vamos ver como podemosdisable all Jackson annotations. Podemos fazer isso desativandoMapperFeature.USE_ANNOTATIONS como no exemplo a seguir:

@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
    public int id;
    public String name;
}

Agora, depois de desativar as anotações, elas não terão efeito e os padrões da biblioteca deverão ser aplicados:

@Test
public void whenDisablingAllAnnotations_thenAllDisabled()
  throws IOException {
    MyBean bean = new MyBean(1, null);

    ObjectMapper mapper = new ObjectMapper();
    mapper.disable(MapperFeature.USE_ANNOTATIONS);
    String result = mapper.writeValueAsString(bean);

    assertThat(result, containsString("1"));
    assertThat(result, containsString("name"));
}

O resultado da serialização antes de desativar as anotações:

{"id":1}

O resultado da serialização após desativar as anotações:

{
    "id":1,
    "name":null
}

10. Conclusão

Este tutorial foi aprofundado nas anotações de Jackson, apenas arranhando a superfície do tipo de flexibilidade que você pode obter usando-as corretamente.

A implementação de todos esses exemplos e trechos de código pode ser encontrada emGitHub project - este é um projeto baseado em Maven, portanto, deve ser fácil de importar e executar como está.