Jackson的Mixins,真香

Jackson mixins 是一种在类中添加 Jackson 注解而不修改实际类的机制。 它是为我们无法修改类的情况而创建的,例如在使用第三方类时。

我们可以使用任何Jackson注释,但不直接将它们添加到类中。我们在mixin类中使用它们,而mixin类既可以是抽象类,也可以是接口。它们既可以用于Jackson序列化也可以用于反序列化,并且必须将它们添加到ObjectMapper配置中。

在接下来的部分中,将展示一些使用 Jackson mixin 有用的常见案例。

使第三方类 Jackson 可序列化

我们展示的第一个案例是当我们需要使用无法由 Jackson 序列化或反序列化的第三方类时,因为它们不遵循 Jackson 约定。 由于我们无法修改这些类,我们必须使用 mixins 来添加 Jackson 序列化所需的所有必要部分。

假设我们要序列化这个第三方类:

public class Person {

  private final String firstName;
  private final String lastName;

  public Person(String firstName, String lastName) {
    this.firstName = firstName ;
    this.lastName = lastName;
  }

  @Override
  public String toString() {
    return new StringJoiner(", ", Person.class.getSimpleName() + "[", "]")
        .add("firstName='" + firstName + "'")
        .add("lastName='" + lastName + "'")
        .toString();
  }
}

我们不能用 Jackson 序列化这个类,因为属性是私有的并且没有 getter 和 setter。 因此,Jackson 不会识别任何属性并会抛出异常:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.grabanotherbyte.jackson.Person and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)

现在让我们创建一个 mixin 来解决这个问题! 在我们的 mixin 中,我们将添加我们想要序列化的属性:

public abstract class PersonMixin {
  @JsonProperty private String firstName;
  @JsonProperty private String lastName;
}

在这种情况下,我们创建了一个抽象类,因为稍后我们需要添加一个构造函数。

之后,我们需要告诉 Jackson 使用我们的 Mixin。 为此,我们需要在 ObjectMapper 中进行设置:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(Person.class, PersonMixin.class);

现在,Jackson将能够序列化我们的Person,并将序列化firstNamelastName

另一方面,如果我们还想使用Person类进行反序列化,我们需要在mixin类中添加一个jackson友好的构造函数:

public abstract class PersonMixin {
  // ... properties

  @JsonCreator
  public PersonMixin(@JsonProperty("firstName") String firstName, @JsonProperty("lastName") String lastName) {}

}

否则,Jackson将抛出异常。

忽略属性

现在,在序列化第三方类时,我们将考虑不同的场景。让我们假设现在我们的Person类拥有所需的所有getter、setter和构造函数,并且它的所有字段都将被序列化:

public class Person {

  private String firstName;
  private String lastName;

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
}

但是,我们希望只序列化firstName,并且和以前一样不能修改这个类。同样,我们可以通过使用mixin类来解决这个问题:

public abstract class PersonMixin {
  @JsonIgnore private String lastName;
}

这样,Jackson将忽略这个属性,只序列化firstName

改变属性名

按照前面的例子,我们还希望在序列化某些属性时更改它们的名称。

让我们修改mixin类,重命名属性lastName:

public abstract class PersonMixin {
  @JsonProperty("surname") private String lastName;
}

现在,我们的 lastName 属性将被序列化为 surname

重写自定义序列化器和反序列化器

在其他情况下,我们会发现使用自定义序列化器和反序列化器的类,但我们希望重写它们。当然,我们不能也不想修改这些类。

让我们扩展我们的Person类来包含一个自定义序列化器和反序列化器:

@JsonSerialize(using = PersonSerializer.class)
@JsonDeserialize(using = PersonDeserializer.class)
public class Person {

  private final String firstName;
  private final String lastName;

  // getters, setters, constructors...

  public static class PersonSerializer extends JsonSerializer<Person> {

    static final String SEPARATOR = " ";

    @Override
    public void serialize(
        Person person, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
        throws IOException {
      jsonGenerator.writeString(person.getFirstName() + SEPARATOR + person.getLastName());
    }
  }

  public static class PersonDeserializer extends JsonDeserializer<Person> {

    @Override
    public Person deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
        throws IOException {
      String[] fields = jsonParser.getValueAsString().split(PersonSerializer.SEPARATOR);
      return new Person(fields[0], fields[1]);
    }
  }
}

正如我们所见,Person 类现在通过连接firstNamelastName 进行序列化。

然而,在某些情况下,我们希望以不同的方式序列化这个类。 让我们为我们的类创建一个不同的序列化器和反序列化器:

public static class PersonReversedSerializer extends JsonSerializer<Person> {

  static final String SEPARATOR = ", ";

  @Override
  public void serialize(
      Person person, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
      throws IOException {
    jsonGenerator.writeString(person.getLastName() + SEPARATOR + person.getFirstName());
  }
}

public static class PersonReversedDeserializer extends JsonDeserializer<Person> {

  @Override
  public Person deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
      throws IOException {
    String[] fields = jsonParser.getValueAsString().split(PersonReversedSerializer.SEPARATOR);
    return new Person(fields[1], fields[0]);
  }
}

现在,我们的 Person 将被序列化为“lastName, firstName”。

正如我们之前所做的那样,要在不修改 Person 的情况下使用这个新的序列化器和反序列化器,我们需要在我们的 mixin 类中指定它:

@JsonSerialize(using = PersonReversedSerializer.class)
@JsonDeserialize(using = PersonReversedDeserializer.class)
public abstract class PersonMixin {}

现在,Jackson将使用这些序列化器,并将忽略Person中指定的序列化器。

如果我们只是想对一个特定的属性这样做也是一样的。


<<<<<<<<<<<< [完] >>>>>>>>>>>>

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱游泳的老白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值