@JsonProperty注解

这篇具有很好参考价值的文章主要介绍了@JsonProperty注解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

序言

@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
    @ToString
    private 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注解

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

@JsonAlias

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

@Slf4j
public class JsonAliasDemo {
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @ToString
    private 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源码

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.8
    public 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 now
        try {
            // 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.7
    public 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 necessary
        if (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;
    }

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

    @Override
    public Boolean hasRequiredMarker(AnnotatedMember m)
    {
        JsonProperty ann = _findAnnotation(m, JsonProperty.class);
        if (ann != null) {
            return ann.required();
        }
        return null;
    }

    @Override
    public JsonProperty.Access findPropertyAccess(Annotated m) {
        JsonProperty ann = _findAnnotation(m, JsonProperty.class);
        if (ann != null) {
            return ann.access();
        }
        return null;
    }

    @Override
    public 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;
    }
    
    @Override
    public 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
    @NoArgsConstructor
    private 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时在反序列化未知属性直接抛出异常信息,

@JsonProperty注解

 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博客文章来源地址https://www.toymoban.com/news/detail-424791.html

到了这里,关于@JsonProperty注解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java面试八股文宝典:序言

    Java作为一门广泛应用于企业级应用开发的编程语言,一直以来都是技术面试中的重要话题。无论您是刚刚踏入编程世界的新手,还是经验丰富的Java开发工程师,都需要通过面试来展示自己的技能和知识。 在面试中,除了技术知识,还需要展现出解决问题、沟通能力和编程实

    2024年02月09日
    浏览(58)
  • Spring 更简单的读取和存储对象、使用注解存取对象

    我们知道物件都会随着时代的发展,越变越简单的。Spring 框架也不意外;我们在之前存储Bean对象是在配置文件中添加 bean/bean 来存入Bean对象到Spring当中的,使用那个类对象就要存入那个,一个两个类对象还好,如果需要的对象多了,就会非常麻烦。现在,随着 Spring 发展不用

    2024年02月11日
    浏览(47)
  • 3. Spring 更简单的读取和存储对象(五大类注解 & 方法注解)

    目录 1. 存储 Bean 对象 1.1 配置扫描路径 1.2 添加注解存储 Bean 对象 1.2.1 @Controller(控制器存储) 1.2.2 @Service(服务存储) 1.2.3 @Repository(仓库存储) 1.2.4 @Component(组件存储) 1.2.5 @Configuration(配置存储) 1.3 使用多个类注解的原因 1.3.1 五大注解之间的关系 1.3.1 Bean 的命名

    2024年02月15日
    浏览(33)
  • 如何高度优化适用于企业自定义的AI (一) 序言

    在当前信息时代的背景下, 社会对AI的需求在不断增长. AI的快速发展得益于大数据、云计算和计算能力的提升, 使得机器学习和深度学习等技术取得了重大突破. AI在图像识别、语音识别、自然语言处理等领域展现出惊人的能力, 为企业带来了巨大的商机. 然而, 通用的AI解决方案

    2024年02月11日
    浏览(43)
  • Rx.NET in Action 中文介绍 前言及序言

    目标 可选方式 Rx 处理器(Operator) 创建 Observable Creating Observables 直接创建 By explicit logic Create Defer 根据范围创建 By specification Range Repeat Generate Timer Interval Return 使用预设 Predefined primitives Throw Never Empty 从其他类型创建 From other types FromEventPattern FromEvent FromTask FromAsync 变换 Transform

    2024年02月13日
    浏览(51)
  • Spring 用注解更简单存取对象

    ​ 上一篇文章是最原始的创建使用,这篇主要是讲 Spring 更简单的存储和读取对象的核心是使用 注解 ,也是日常生活企业用的最多的方法 “注解” 所以这篇的内容是很重要的 !!! 1.1 前置工作 ​ 需要再 Spring 的配置文件中设置组件 Component 的根路径 这是很重要的一步,在

    2024年02月13日
    浏览(38)
  • Spring使用注解存储Bean对象

    在前一篇博客中( Spring项目创建与Bean的存储与读取(DL))介绍的是通过配置文件注册对象从而存储到 Spring 中,这种方式其实还是挺繁琐的。 实际上,在使用学习使用 Spring过程中,当我们要实现一个功能的时候,先应该考虑的是有没有相应的注解是实现对应功能的,Spring 中

    2024年02月16日
    浏览(39)
  • Spring使用注解存储和读取对象

    之前我们存储Bean时,需要在spring-config.xml中添加bean注册才行,这样的方式并不简单。我们要想 更简单的存储和读取对象的核心是使用注解 1.使用类注解(五大类注解): @Controller:控制器,验证用户请求的数据正确性(安保系统) @Service:服务层,编排和调度具体执行方法的(客服

    2023年04月19日
    浏览(47)
  • Spring使用注解进行对象装配(DI)

    通过五大类注解可以更便捷的将对象存储到 Spring 中,同样也可以使用注解将已经储存的对象取出来,直接赋值到注解所在类的一个属性中,这一个过程也叫做对象的装配或者叫对象的注入,即 DI。 获取 Bean 对象也叫做对象装配,就是把对象取出来放到某个类中,有时候也叫

    2024年02月15日
    浏览(38)
  • 【JavaEE进阶】 Spring使用注解存储对象

    在博主前面所写的《【JavaEE进阶】 Spring 的创建和使⽤》中我们已经可以实现基本的 Spring 读取和存储对象的操作了,但在操作的过程中我们发现读取和存储对象并没有想象中的那么“简单”,所以接下来我们要学习更加简单的操作 Bean 对象的⽅法。 在 Spring 中想要更简单的存

    2024年02月05日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包