jackson java 版本_java – 根据与Jackson的API版本指定不同的JSON属性名称

我需要能够使用Jackson同时支持多个API版本来序列化/反序列化对象.我已经探索过如下解决方案:

> @JsonProperty

> PropertyNamingStrategy

> Mixin注释

但是,每一个都会导致自己的问题. @JsonProperty是一个完美的解决方案,如果我可以直接在注释中添加具有正确名称的多个版本:

@JsonProperty(api="1.5", "fname")

@JsonProperty(api="1.6", "firstname")

String firstName;

随着时间的推移,可能会有很长的时间,但它肯定很容易理解.但是,这似乎不太可能.

PropertyNamingStrategy和mixins也是一个好主意.实际上,我尝试使用mixin注释(例如,Inherit model with different JSON property names)并且它们有效,但这两种解决方案都存在一个问题.你必须在某处指定和使用ObjectMapper(也可能是ObjectReader / Writer).

这很痛苦,因为对象的层次结构如下所示:

实体

| –User

| –group

| –Credential

实体包含公共属性,如名称,ID,描述,状态和API版本.我们假设您现在执行以下操作:

User user = new User("catherine", "stewardess", "active");

user.setApiVersion(Entity.ApiVersion.V2);

if(user.getVersion() == Entity.ApiVersion.V2) {

MAPPER.addMixin(Entity.class, EntityMixinV2.class);

}

String userJson = MAPPER.writeValueAsString(user);

User user2 = MAPPER.readValue(userJson);

System.out.println(MAPPER.writeValueAsString(user2));

其中MAPPER只是在其他地方定义的ObjectMapper,而EntityMixinV2是这样的:

public abstract class EntityMixinV2 {

@JsonProperty("employmentState")

String state;

}

在User的父类Entity中覆盖其中一个变量(在本例中为state).这有几个问题:

>每次版本号增加时,您必须添加另一个if块

>这只处理基类.如果子类需要更改一些属性怎么办?如果只有少数几个类,那不是问题,但很快就会失控.

>更重要的是,将映射器/读取器/写入器设置为正确的类来映射将是一个巨大的痛苦和错误的来源,因为有人会不可避免地忘记这样做.此外,将mapper,reader或writer放在类本身中只会导致堆栈溢出或无限递归.

>最后,根据API版本设置正确的类,并且必须手动完成被映射的类,除非我遗漏了一些东西.反思可以解决这个问题

> a)它很慢,这种东西经常被称为使用它和

> b)如果它在父类中使用,它将无法看到子类,从而迫使您在子类本身中使用反射来设置映射器.

理想情况下,我希望能够使用类似上面的@JsonProperty示例,因为名称更改是问题,而不是我对变量所做的事情.我也考虑过使用

@JsonSerialize(using = EntitySerializer.class)

@JsonDeserialize(using = EntityDeserializer.class)

注释,但这只会改变变量的内容,而不是属性名称本身.

解决方法:

您可以创建自定义注释以定义字段的可能版本的属性名称列表,并创建自定义JacksonAnnotationIntrospector以根据给定版本解析属性名称.

自定义注释看起来像:

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD})

public @interface VersioningProperties {

Property[] value();

@interface Property {

String version();

String value();

}

}

并且自定义JacksonAnnotationIntrospector将如下所示:

public class VersioningPropertiesIntrospector {

private String version;

public VersioningPropertiesIntrospector(String version) {

this.version = version;

}

@Override

pubilc PropertyName findNameForSerialization(Annotated a) {

PropertyName propertyName = findNameFromVersioningProperties(a);

if (propertyName != null) {

return propertyName;

}

return super.findNameForSerialization(a);

}

@Override

pubilc PropertyName findNameForDeserialization(Annotated a) {

PropertyName propertyName = findNameFromVersioningProperties(a);

if (propertyName != null) {

return propertyName;

}

return super.findNameForDeserialization(a);

}

private PropertyName findNameFromVersioningProperties(Annotated a) {

VersioningProperties annotation = a.getAnnotation(VersioningProperties.class);

if (annotation == null) {

return null;

}

for (Property property : annotation.value()) {

if (version.equals(property.version()) {

return new PropertyName(property.value());

}

}

return null;

}

}

使用注释的示例:

public class User {

@VersioningProperties({

@Property(version = "1.5", value = "fname"),

@Property(version = "1.6", value = "firstName")

})

private String firstName;

// constructors, getters and setters

}

以及将ObjectMapper与introspector一起使用的示例:

User user = new User();

user.setFirstName("catherine");

user.setVersion("1.5");

ObjectMapper mapper = new ObjectMapper();

mapper.setAnnotationIntrospector(new VersioningPropertiesIntrospector(user.getVersion()));

String userJson = mapper.writeValueAsString(user);

User userRead = mapper.readValue(userJson, User.class);

您还可以考虑通过传递版本信息来实现工厂来获取ObjectMapper.

标签:json,java,jackson

来源: https://codeday.me/bug/20190702/1353418.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值