Jackson Annotation Beispiele

Beispiele für Jackson-Anmerkungen

1. Überblick

In diesem Artikel werden wir uns eingehend mitJackson Annotations befassen.

Wir werden sehen, wie Sie die vorhandenen Anmerkungen verwenden, benutzerdefinierte erstellen und schließlich - wie Sie sie deaktivieren.

Weitere Lektüre:

Weitere Jackson-Anmerkungen

Dieser Artikel behandelt einige weniger bekannte Anmerkungen zur JSON-Verarbeitung, die von Jackson bereitgestellt wurden.

Read more

Jackson - bidirektionale Beziehungen

Wie man Jackson benutzt, um das Problem der unendlichen Rekursion in bidirektionalen Beziehungen zu lösen.

Read more

Erste Schritte mit der benutzerdefinierten Deserialisierung in Jackson

Verwenden Sie Jackson, um benutzerdefiniertes JSON einem beliebigen Java-Entitätsdiagramm mit vollständiger Kontrolle über den Deserialisierungsprozess zuzuordnen.

Read more

2. Anmerkungen zur Jackson-Serialisierung

Zunächst werfen wir einen Blick auf die Anmerkungen zur Serialisierung.

2.1. @JsonAnyGetter

Die Annotation@JsonAnyGetter ermöglicht die Flexibilität, ein FeldMap als Standardeigenschaften zu verwenden.

Hier ein kurzes Beispiel: Die EntitätExtendableBeanverfügt über die Eigenschaftnameund eine Reihe erweiterbarer Attribute in Form von Schlüssel / Wert-Paaren:

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

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

Wenn wir eine Instanz dieser Entität serialisieren, erhalten wir alle Schlüsselwerte inMap als standardmäßige, einfache Eigenschaften:

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

Und so sieht die Serialisierung dieser Entität in der Praxis aus:

@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"));
}

Wir können auch das optionale Argumentenabled alsfalse verwenden, um@JsonAnyGetter(). zu deaktivieren. In diesem Fall werden dieMap als JSON konvertiert und erscheinen danach unter der Variablenproperties Serialisierung.

2.2. @JsonGetter

Die Annotation@JsonGetter ist eine Alternative zur Annotation@JsonProperty, um eine Methode als Getter-Methode zu markieren.

Im folgenden Beispiel geben wir die MethodegetTheName() als Getter-Methode für die Eigenschaftnameder EntitätMyBeanan:

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

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

Und so funktioniert das in der Praxis:

@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

Wir können die Annotation@JsonPropertyOrder verwenden, umthe order of properties on serialization anzugeben.

Legen Sie eine benutzerdefinierte Reihenfolge für die Eigenschaften einerMyBean-Entität fest:

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

Und hier ist die Ausgabe der Serialisierung:

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

Und ein einfacher Test:

@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"));
}

Wir können auch@JsonPropertyOrder(alphabetic=true) verwenden, um die Eigenschaften alphabetisch zu ordnen. In diesem Fall lautet die Ausgabe der Serialisierung:

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

2.4. @JsonRawValue

Die Annotation@JsonRawValue kanninstruct Jackson to serialize a property exactly as is.

Im folgenden Beispiel verwenden wir@JsonRawValue, um einen benutzerdefinierten JSON als Wert einer Entität einzubetten:

public class RawBean {
    public String name;

    @JsonRawValue
    public String json;
}

Die Ausgabe der Serialisierung der Entität lautet:

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

Und ein einfacher Test:

@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}"));
}

Wir können auch das optionale boolesche Argumentvalue verwenden, das definiert, ob diese Annotation aktiv ist oder nicht.

2.5. @JsonValue

@JsonValue gibt eine einzelne Methode an, mit der die Bibliothek die gesamte Instanz serialisiert.

In einer Aufzählung kommentieren wir beispielsweisegetName mit@JsonValue, sodass eine solche Entität über ihren Namen serialisiert wird:

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;
    }
}

Unser Test:

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

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

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

2.6. @JsonRootName

Die Annotation@JsonRootName wird verwendet, wenn der Umbruch aktiviert ist, um den Namen des zu verwendenden Root-Wrappers anzugeben.

Wrapping bedeutet, dass anstelle vonUser Folgendes wie folgt serialisiert wird:

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

Es wird so verpackt:

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

Schauen wir uns also ein Beispiel an -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;
}

Standardmäßig ist der Name des Wrappers der Name der Klasse -UserWithRoot. Durch Verwendung der Annotation erhalten wir die sauberer aussehendenuser:

@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"));
}

Hier ist die Ausgabe der Serialisierung:

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

Seit Jackson 2.4 steht ein neues optionales Argumentnamespace zur Verfügung, das mit Datenformaten wie XML verwendet werden kann. Wenn wir es hinzufügen, wird es Teil des vollständig qualifizierten Namens:

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

    // ...
}

Wenn wir es mitXmlMapper serialisieren, lautet die Ausgabe:


    1
    John
    

2.7. @JsonSerialize

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

Schauen wir uns ein kurzes Beispiel an. Wir werden@JsonSerialize verwenden, um die EigenschafteventDate mitCustomDateSerializer zu serialisieren:

public class EventWithSerializer {
    public String name;

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

Hier ist der einfache benutzerdefinierte Jackson-Serializer:

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));
    }
}

Verwenden wir diese in einem Test:

@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. Jackson Deserialization Annotations

Als Nächstes untersuchen wir die Anmerkungen zur Jackson-Deserialisierung.

3.1. @JsonCreator

Wir können die Annotation@JsonCreator verwenden, um den Konstruktor / die Factory zu optimieren, der bei der Deserialisierung verwendet wird.

Dies ist sehr hilfreich, wenn wir JSON deserialisieren müssen, das nicht genau mit der Zielentität übereinstimmt, die wir benötigen.

Schauen wir uns ein Beispiel an. Angenommen, wir müssen den folgenden JSON deserialisieren:

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

In unserer Zielentität gibt es jedoch keintheName-Feld - es gibt nur einname-Feld. Jetzt möchten wir die Entität selbst nicht ändern - wir brauchen nur etwas mehr Kontrolle über den Unmarshalling-Prozess -, indem wir den Konstruktor mit@JsonCreator annotieren und auch die Annotation@JsonProperty verwenden:

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;
    }
}

Lassen Sie uns dies in Aktion sehen:

@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 gibt an, dass eine Eigenschaft ihren Wert aus der Injektion und nicht aus den JSON-Daten erhält.

Im folgenden Beispiel verwenden wir@JacksonInject, um die Eigenschaftid zu injizieren:

public class BeanWithInject {
    @JacksonInject
    public int id;

    public String name;
}

Und so funktioniert das:

@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 ermöglicht uns die Flexibilität,Map als Standardeigenschaften zu verwenden. Bei der Deserialisierung werden die Eigenschaften von JSON einfach zur Karte hinzugefügt.

Mal sehen, wie das funktioniert - wir werden@JsonAnySetter verwenden, um die EntitätExtendableBean zu deserialisieren:

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

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

Dies ist der JSON, den wir deserialisieren müssen:

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

Und so hängt das alles zusammen:

@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 ist eine Alternative zu@JsonProperty - das markiert die Methode als Setter-Methode.

Dies ist sehr nützlich, wenn wir einige JSON-Daten, aberthe target entity class doesn’t exactly match that data lesen müssen, und daher den Prozess optimieren müssen, damit er passt.

Im folgenden Beispiel geben wir die Methode setTheName() als Setter der Eigenschaftnamein unserer EntitätMyBeanan:

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

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

Wenn wir nun einige JSON-Daten entfernen müssen, funktioniert dies einwandfrei:

@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 gibt die Verwendung eines benutzerdefinierten Deserialisierers an.

Mal sehen, wie sich das auswirkt - wir werden@JsonDeserialize verwenden, um die EigenschafteventDate mitCustomDateDeserializer zu deserialisieren:

public class EventWithSerializer {
    public String name;

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

Hier ist der benutzerdefinierte Deserializer:

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);
        }
    }
}

Und hier ist der Back-to-Back-Test:

@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

Das@JsonAlias definiertone or more alternative names for a property during deserialization.

Sehen wir uns anhand eines kurzen Beispiels an, wie diese Anmerkung funktioniert:

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

Hier haben wir ein POJO und möchten JSON mit Werten wiefName,f_name undfirstName in die VariablefirstName des POJO deserialisieren.

Und hier ist ein Test, der sicherstellt, dass diese Annotation wie erwartet funktioniert:

@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 ist eine Annotation auf Klassenebene, die eine Eigenschaft oder eine Liste von Eigenschaften markiert, die Jackson ignoriert.

Lassen Sie uns ein kurzes Beispiel durchgehen und die Eigenschaftid aus der Serialisierung ignorieren:

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

Und hier ist der Test, um sicherzustellen, dass das Ignorieren erfolgt:

@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")));
}

Um unbekannte Eigenschaften in der JSON-Eingabe ausnahmslos zu ignorieren, können SieignoreUnknown=true der@JsonIgnoreProperties -Sannotation festlegen.

4.2. @JsonIgnore

Die Annotation@JsonIgnore wird verwendet, um eine Eigenschaft zu markieren, die auf Feldebene ignoriert werden soll.

Verwenden wir@JsonIgnore, um die Eigenschaftid aus der Serialisierung zu ignorieren:

public class BeanWithIgnore {
    @JsonIgnore
    public int id;

    public String name;
}

Und der Test, der sicherstellt, dassid erfolgreich ignoriert wurde:

@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 markiert alle Eigenschaften eines mit Anmerkungen versehenen Typs, die ignoriert werden sollen.

Verwenden Sie die Anmerkung, um alle Eigenschaften vom TypNamezu markieren, die ignoriert werden sollen:

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

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

Hier ist der einfache Test, um sicherzustellen, dass das Ignorieren korrekt funktioniert:

@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

Wir können@JsonInclude verwenden, um Eigenschaften mit leeren / null / Standardwerten auszuschließen.

Schauen wir uns ein Beispiel an - Nullen von der Serialisierung ausschließen:

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

Hier ist der vollständige Test:

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 kann die Standardsemantik vonwhich properties are visible and which are not überschreiben.

Schauen wir uns anhand eines einfachen Beispiels an, wie hilfreich die Annotation sein kann. Aktivieren Sie die Serialisierung privater Eigenschaften:

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

Und der Test:

@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. Anmerkungen zum Umgang mit polymorphen Jackson-Typen

Als Nächstes werfen wir einen Blick auf die Anmerkungen zum Umgang mit polymorphen Jackson-Typen:

  • @JsonTypeInfo - Gibt Details dazu an, welche Typinformationen in die Serialisierung einbezogen werden sollen

  • @JsonSubTypes - gibt Untertypen des mit Anmerkungen versehenen Typs an

  • @JsonTypeName - Definiert einen logischen Typnamen, der für kommentierte Klassen verwendet werden soll

Schauen wir uns ein komplexeres Beispiel an und verwenden Sie alle drei -@JsonTypeInfo,@JsonSubTypes, und@JsonTypeName –, um die EntitätZoo zu serialisieren / deserialisieren:

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;
    }
}

Wenn wir die Serialisierung durchführen:

@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"));
}

Folgendes führt dazu, dass die Instanz vonZoomitDog serialisiert wird:

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

Beginnen wir nun mit der De-Serialisierung mit der folgenden JSON-Eingabe:

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

Und mal sehen, wie das für eineZoo-Instanz nicht mehr gemarshallt wird:

@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

Als nächstes wollen wir einige allgemeinere Anmerkungen von Jackson diskutieren.

6.1. @JsonProperty

Wir könnenthe @JsonProperty annotation to indicate the property name in JSON hinzufügen.

Verwenden wir@JsonProperty, um die Eigenschaftname zu serialisieren / deserialisieren, wenn es sich um nicht standardmäßige Getter und Setter handelt:

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;
    }
}

Unser Test:

@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

Die Annotation@JsonFormat gibt ein Format an, wenn Datums- / Zeitwerte serialisiert werden.

Im folgenden Beispiel verwenden wir@JsonFormat, um das Format der EigenschafteventDate zu steuern:

public class EventWithFormat {
    public String name;

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

Und hier ist der Test:

@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 definiert Werte, die beim Serialisieren / Deserialisieren entpackt / abgeflacht werden sollen.

Mal sehen, wie das genau funktioniert. Wir werden die Annotation verwenden, um die Eigenschaftname zu entpacken:

public class UnwrappedUser {
    public int id;

    @JsonUnwrapped
    public Name name;

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

Lassen Sie uns nun eine Instanz dieser Klasse serialisieren:

@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")));
}

So sieht die Ausgabe aus: Die Felder der statisch verschachtelten Klasse werden zusammen mit dem anderen Feld entpackt:

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

6.4. @JsonView

@JsonView gibt die Ansicht an, in der die Eigenschaft für die Serialisierung / Deserialisierung enthalten sein wird.

Ein Beispiel zeigt genau, wie das funktioniert. Wir verwenden@JsonView, um eine Instanz der EntitätItemzu serialisieren.

Beginnen wir mit den Ansichten:

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

Und hier ist die EntitätItemunter Verwendung der Ansichten:

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

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

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

Endlich - der vollständige Test:

@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 relationships und umgehen Schleifen.

Im folgenden Beispiel verwenden wir@JsonManagedReference und@JsonBackReference, um unsereItemWithRef-Entität zu serialisieren:

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

    @JsonManagedReference
    public UserWithRef owner;
}

UnsereUserWithRefEntität:

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

    @JsonBackReference
    public List userItems;
}

Und der Test:

@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 gibt an, dass die Objektidentität beim Serialisieren / Deserialisieren von Werten verwendet werden sollte, um beispielsweise Probleme mit unendlicher Rekursion zu lösen.

Im folgenden Beispiel haben wir eine Entität vonItemWithIdentitymit der bidirektionalen Beziehung vonazur Entität vonUserWithIdentity:

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

Und die Entität vonUserWithIdentity:

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

Nunlet’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"));
}

Hier ist die vollständige Ausgabe des serialisierten Elements und Benutzers:

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

6.7. @JsonFilter

Die Annotation@JsonFilter gibt einen Filter an, der während der Serialisierung verwendet werden soll.

Schauen wir uns ein Beispiel an. Zuerst definieren wir die Entität und zeigen auf den Filter:

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

Im vollständigen Test definieren wir nun den Filter, der alle anderen Eigenschaften außername von der Serialisierung ausschließt:

@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. Benutzerdefinierte Jackson-Anmerkung

Als Nächstes sehen wir uns an, wie Sie eine benutzerdefinierte Jackson-Anmerkung erstellen. We can make use of the @JacksonAnnotationsInside annotation:

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

Wenn wir nun die neue Annotation für eine Entität verwenden:

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

Wir können sehen, wie die vorhandenen Annotationen zu einer einfacheren, benutzerdefinierten Annotation kombiniert werden, die wir als Kurzform verwenden können:

@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")));
}

Die Ausgabe des Serialisierungsprozesses:

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

8. Jackson MixIn Anmerkungen

Weiter - sehen wir uns an, wie Jackson MixIn-Anmerkungen verwendet werden.

Verwenden Sie die MixIn-Annotationen, um beispielsweise Eigenschaften vom TypUserzu ignorieren:

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

Lassen Sie uns dies in Aktion sehen:

@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. Deaktivieren Sie die Jackson-Anmerkung

Zum Schluss wollen wir sehen, wie wirdisable all Jackson annotations können. Wir können dies tun, indem wirMapperFeature.USE_ANNOTATIONS wie im folgenden Beispiel deaktivieren:

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

Nach dem Deaktivieren von Anmerkungen sollten diese nun keine Auswirkungen mehr haben und die Standardeinstellungen der Bibliothek sollten gelten:

@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"));
}

Das Ergebnis der Serialisierung vor dem Deaktivieren von Anmerkungen:

{"id":1}

Das Ergebnis der Serialisierung nach dem Deaktivieren von Anmerkungen:

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

10. Fazit

Dieses Tutorial hat einen tiefen Einblick in Jackson-Annotationen gegeben und nur die Oberfläche der Flexibilität verkratzt, mit der Sie sie richtig einsetzen können.

Die Implementierung all dieser Beispiele und Codefragmente finden Sie inGitHub project - dies ist ein Maven-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.