序言

@JsonProperty

当一个Java对象转换成Json字符串后,如果不是正确的实际名称有可能会出现异常。比如数据库中的坐标名称是x_axis,而定义Java对象是是xAxis,那么这时就需要使用到@JsonProperty注解,并且配合ObjectMapper.writeValueAsString方法使用去序列化对象成字符串。如下示例demo,

@JsonProperty(value = "", index = 1, access = JsonProperty.Access.xxx)

其中value为成员变量真实名称,index为序列化之后所展示的顺序,access为该对象的访问控制权限。

@Slf4j
public class JsonPropertyDemo {@Data@AllArgsConstructor@NoArgsConstructor@Builder@ToStringprivate static class Coordinate {@JsonProperty(value = "x_axis", index = 1, access = JsonProperty.Access.WRITE_ONLY)private String xAxis;@JsonProperty(value = "y_axis", index = 2, access = JsonProperty.Access.READ_WRITE)private String yAxis;@JsonProperty(value = "z_axis", index = 3, access = JsonProperty.Access.READ_WRITE)private String zAxis;}public static void main(String[] args) {Coordinate coordinate = Coordinate.builder().xAxis("113.58").yAxis("37.86").zAxis("40.05").build();String jsonStr = JSON.toJSONString(coordinate);log.info("serializes the specified object into its equivalent Json representation :" + jsonStr);ObjectMapper mapper = new ObjectMapper();try {String str = mapper.writeValueAsString(coordinate);log.info("serialize any Java value as a String : " + str);Object bean = mapper.readerFor(Coordinate.class).readValue(str);log.info("read or update instances of specified type : " + bean);} catch (JsonProcessingException e) {log.error("error message : " + e);}}
}

注解一般都是通过反射拿到对映的成员变量然后再进行增强,@JsonProperty把成员变量序列化成另外一个名称,并且它在序列化和反序列化的过程中都是使用的实际名称。

@JsonAlias

com.fasterxml.jackson.annotation中的@JsonProperty是可以在序列化和反序列化中使用,而@JsonAlias只在反序列化中起作用,指定Java属性可以接受的更多名称。文末链接也有JsonAlias的实例源码,下面就简单举一个例子,

@Slf4j
public class JsonAliasDemo {@Data@AllArgsConstructor@NoArgsConstructor@Builder@ToStringprivate static class Coordinate {@JsonAlias(value = "x_location")@JsonProperty(value = "x_axis")private String xAxis;@JsonProperty(value = "y_axis")@JsonAlias(value = "y_location")private String yAxis;@JsonProperty(value = "z_axis")@JsonAlias(value = "z_location")private String zAxis;}public static void main(String[] args) {String location = "{\"x_location\":\"113.58\",\"y_location\":\"37.86\",\"z_location\":\"40.05\"}";ObjectMapper mapper = new ObjectMapper();try {Object bean = mapper.readValue(location, Coordinate.class);log.info("read or update instances of specified type : " + bean);} catch (JsonProcessingException e) {log.error("error message : " + e);}}
}

@JsonAlias里的别名的json字符串,在反序列化时可以识别出来,不会反序列化失败,结果如下图,

@JsonProperty源码

JsonProperty的源码是一个注解类,注解类上的几个元注解就不解释了,可以参考文末链接7,该注解的主要作用就是在pojo属性上执行自定义处理器流程。

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonProperty {String USE_DEFAULT_NAME = "";int INDEX_UNKNOWN = -1;String value() default "";boolean required() default false;int index() default -1;String defaultValue() default "";JsonProperty.Access access() default JsonProperty.Access.AUTO;public static enum Access {AUTO,READ_ONLY,WRITE_ONLY,READ_WRITE;private Access() {}}
}

那么下面就看一下处理器流程做了一些什么事,找到JacksonAnnotationIntrospector类,

先看在jackson 2.6版本之后找到添加了@JsonProperty注解的pojo属性做了什么事,注意这里是一个过期的旧方法,保留是为了兼容使用老版本jackson的方法(@Deprecated注解)。首先该方法通过反射拿到成员变量,然后再获取注解中的属性值(eg:@JsonProperty(value = "x_axis")),如果找到则返回value值,否则就返回原成员变量的name。

    /*** Since 2.6, we have supported use of {@link JsonProperty} for specifying* explicit serialized name*/@Override@Deprecated // since 2.8public String findEnumValue(Enum<?> value){// 11-Jun-2015, tatu: As per [databind#677], need to allow explicit naming.//   Unfortunately cannot quite use standard AnnotatedClass here (due to various//   reasons, including odd representation JVM uses); has to do for nowtry {// We know that values are actually static fields with matching name so:Field f = value.getClass().getField(value.name());if (f != null) {JsonProperty prop = f.getAnnotation(JsonProperty.class);if (prop != null) {String n = prop.value();if (n != null && !n.isEmpty()) {return n;}}}} catch (SecurityException e) {// 17-Sep-2015, tatu: Anything we could/should do here?} catch (NoSuchFieldException e) {// 17-Sep-2015, tatu: should not really happen. But... can we do anything?}return value.name();}

下面再看一下jackson2.7之后是怎么做的,首先该方法不是根据成员变量的name获取类的属性,而是直接遍历类中所有的属性,然后用哈希表expl存属性的name和注解中的value映射关系,然后一次性遍历一遍把所有的属性的真实值集合返回出来(如果没有配置@JsonProperty的value则是属性原值,如果配有@JsonProperty的value则返回value值),这么做的好处在于不用一次一次的解析真实属性值而是一起解析真实属性值。

@Override // since 2.7public String[] findEnumValues(Class<?> enumType, Enum<?>[] enumValues, String[] names) {HashMap<String,String> expl = null;for (Field f : ClassUtil.getDeclaredFields(enumType)) {if (!f.isEnumConstant()) {continue;}JsonProperty prop = f.getAnnotation(JsonProperty.class);if (prop == null) {continue;}String n = prop.value();if (n.isEmpty()) {continue;}if (expl == null) {expl = new HashMap<String,String>();}expl.put(f.getName(), n);}// and then stitch them together if and as necessaryif (expl != null) {for (int i = 0, end = enumValues.length; i < end; ++i) {String defName = enumValues[i].name();String explValue = expl.get(defName);if (explValue != null) {names[i] = explValue;}}}return names;}

其他属性的解析也基本上如出一辙,代码如下,

    @Overridepublic Boolean hasRequiredMarker(AnnotatedMember m){JsonProperty ann = _findAnnotation(m, JsonProperty.class);if (ann != null) {return ann.required();}return null;}@Overridepublic JsonProperty.Access findPropertyAccess(Annotated m) {JsonProperty ann = _findAnnotation(m, JsonProperty.class);if (ann != null) {return ann.access();}return null;}@Overridepublic Integer findPropertyIndex(Annotated ann) {JsonProperty prop = _findAnnotation(ann, JsonProperty.class);if (prop != null) {int ix = prop.index();if (ix != JsonProperty.INDEX_UNKNOWN) {return Integer.valueOf(ix);}}return null;}@Overridepublic String findPropertyDefaultValue(Annotated ann) {JsonProperty prop = _findAnnotation(ann, JsonProperty.class);if (prop == null) {return null;}String str = prop.defaultValue();// Since annotations do not allow nulls, need to assume empty means "none"return str.isEmpty() ? null : str;}

序列化和反序列化配置

另外,序列化和反序列化中会有些常见配置,比如常见的如下,

DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES

在反序列化json字符串成Java对象时,遇到未知属性是否抛出异常信息。

@Slf4j
public class DeserializationFeatureDemo {/*** 注意上面的实例对象必须要有无参构造函数,否则在反序列化时创建实例对象* 会抛出异常com.fasterxml.jackson.databind.exc.InvalidDefinitionException*/@Data@Builder@AllArgsConstructor@NoArgsConstructorprivate static class Person {private String name;private Long age;}public static void main(String[] args) {String jsonStr = "{\"name\":\"张三\",\"age\":18,\"sex\":\"男\"}";System.out.println("serialize java object to json : " + jsonStr);Person A = parse(jsonStr, Person.class, false);System.out.println("after deserialize to object :" + JSON.toJSONString(A));Person B = parse(jsonStr, Person.class, true);System.out.println("after deserialize to object :" + JSON.toJSONString(B));}private static <T> T parse(String json, Class<T> tClass, boolean failOnUnknownProperties) {ObjectMapper objectMapper = new ObjectMapper();objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, failOnUnknownProperties);T result = null;try {result = objectMapper.readValue(json, tClass);} catch (JsonProcessingException e) {log.error("Failed to deserialize JSON content, json value : " + json);}return result;}
}

可以看到输出结果,配置设为true时在反序列化未知属性直接抛出异常信息,

JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS

是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)。 由于JSON规范要求对所有控制字符使用引号,这是一个非标准的特性,因此默认禁用。

更多配置参考文末链接6。

参考链接:

1、JSON在线 | JSON解析格式化—SO JSON在线工具

2、JsonProperty (Jackson JSON Processor)

3、Java类com.fasterxml.jackson.annotation.JsonProperty的实例源码 - 编程字典

4、Java类com.fasterxml.jackson.annotation.JsonAlias的实例源码 - 编程字典

5、Jackson data binding - 知乎

6、4. JSON字符串是如何被解析的?JsonParser了解一下(中)-阿里云开发者社区

7、注解的使用_四问四不知的博客-CSDN博客

@JsonProperty注解相关推荐

  1. @JsonProperty注解解析

    1. 概述 来源: @JsonPrpperty是jackson包下的一个注解,详细路径(com.fasterxml.jackson.annotation.JsonProperty;)作用:@JsonP ...

  2. java中@JSONField和@JsonProperty注解有什么区别呢?

    下文笔者讲述Java中@JSONField和@JsonProperty的不同之处,如下所示: 今天在springboot的开发中, 可以使用 @JSONField可正常转换但@JsonProperty ...

  3. jsonproperty注解_Jackson注解详解

    1. 概述 在本文中,我们将深入研究Jackson注解. 我们将看到如何使用现有的注释,如何创建自定义的注释,最后-如何禁用它们. 2. Jackson序列化注解 首先,我们将查看序列化注释. 2.1 ...

  4. 关于用jackson的@JsonProperty注解属性名,会多出一个字段的问题

    问题描述 jackson2对pojo类型序列化的处理时(即以下三个包,导入即生效) Jackson2在初始化序列器时,对pojo类型对象会收集其属性信息,属性包括成员变量及方法,然后属性名称和处理过后 ...

  5. jackson中@JsonProperty、@JsonIgnore等常用注解总结

    最近用的比较多,把json相关的知识点都总结一下,jackjson的注解使用比较频繁, jackson的maven依赖 <dependency> <groupId>com.fa ...

  6. Jackson 通过自定义注解来控制json key的格式

    Jackson 通过自定义注解来控制json key的格式 最近我这边有一个需求就是需要把Bean中的某一些特殊字段的值进行替换.而这个替换过程是需要依赖一个第三方的dubbo服务的.为了使得这个转换 ...

  7. Jackson注解学习参考

    以下内容摘录.翻译自https://github.com/FasterXML/jackson-annotations  (1)初级  我们从几个简单的使用场景开始:重命名属性,忽略属性,以及修改属性所 ...

  8. @JsonProperty的使用

    jackson的maven依赖 <dependency><groupId>com.fasterxml.jackson.core</groupId><artif ...

  9. spring-boot注解详解(四)

    @repository @repository跟@Service,@Compent,@Controller这4种注解是没什么本质区别,都是声明作用,取不同的名字只是为了更好区分各自的功能.下图更多的作 ...

最新文章

  1. 面向软件工程师的卡尔曼滤波器
  2. 实战SSM_O2O商铺_40【前端展示】首页轮播图和一级商铺View层的实现
  3. 众筹网02_项目环境搭建
  4. 【Tiny4412】Tiny4412烧写uboot脚本分析
  5. java jar 源码乱码,java使用jar包时出现乱码的解决方法
  6. linux下的DNS服务器详解
  7. 本周ASP.NET英文技术文章推荐[10/21 – 10/27]
  8. 如何向github上传文件
  9. GDB简单调试linux内核与模块的方法
  10. [入门] Delphi XE2 的控件安装方法。
  11. Oracle、聚石塔
  12. 善于做“加减法”的百分点科技 成就数据智能的先行者
  13. win10便签常驻桌面_做备忘录,用win10自带的便笺工具就可以了,免费又方便
  14. 语音识别中的WFST和语言模型
  15. C# web references 调用出错 The underlying connection was closed: An unexpected error occurred on a send.
  16. 华为路由器:一次华为AR1220F-s的系统修复经历
  17. 三分钟学会数据库, UPDATE 更新
  18. mysql mysqldataadapter_MySql中MySqlDataAdapter类的用法
  19. Python学习——分支结构
  20. jacob 详解 语音_Java系列:Java实现文字转语音

热门文章

  1. 手把手教你搭建腾讯云服务器(图文并茂)
  2. 【Linux】文件解压缩、解打包命令解析(zip、unzip、tar)
  3. 金融危机寒意逼人 关注09年最热门IT技术
  4. Zookeeper纸上谈兵——Zookeeper与CAP原则
  5. 商务部发布首个“新零售”报告:一文读懂中国新零售现状
  6. nokia 5300 j2me开发问题
  7. MeeGo和Nokia
  8. DEBERTA: DECODING-ENHANCED BERT WITH DISENTANGLED ATTENTION
  9. 2017战略No.1:坚定不移地走全产业链发展路线
  10. Android 线程休眠方法