最近我这边有一个需求就是需要把Bean中的某一些特殊字段的值进行替换。而这个替换过程是需要依赖一个第三方的dubbo服务的。为了使得这个转换功能更加的通用,我们采用了下面的方式:

client端使用自定义的注解(假设为@Dimension)标记Bean中所有的「特殊字段」

client端把bean转换为json格式,但是这个转换过程的要求是:这些特殊的字段对应的json的key需要符合一定的格式,而这个格式依赖于标记的@Dimension注解

然后client端通过dubbo RPC服务把json扔给server端,server进行一些json解析,替换之后把替换之后的json扔给client端,然后client端把接收到的json再转回为之前的Bean对象的实例。

我们先来看看把bean转为json,一般没有特殊要求的话,我们都是:

/**

* Object可以是POJO,也可以是Collection或数组。

* 如果对象为Null, 返回"null".

* 如果集合为空集合, 返回"[]".

*

* @param object the object to json

* @return toJson result

*/

public String toJson(Object object) {

try {

return mapper.writeValueAsString(object);

} catch (IOException e) {

LOGGER.error("write to json string error:" + object, e);

return null;

}

}

这种是默认的情况,生成的json的key和对应的Bean的filed的name是一模一样的。

而Jackson也给我们提供了注解:@JsonProperty注解来帮助我们重命名生成的json的key。但是他这个重命名并不是很灵活,因为他只能固定的重命名为某一个「确定的」值,而不能容许我们做一些额外的操作。

所以在这种情况下,我打算自定义一个注解,因为业务场景相关,我们的注解定义如下:

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.FIELD)

public @interface Dimension {

String valueType();

}

假设我们的json的key的生成规则如下:

valueType()的值为“id”时,json key追加后缀“_id”

valueType()的值为”code”时,json key追加后缀“_code”

这个时候我们就可以使用Jackson提供给我们强大的JacksonAnnotationIntrospector类了。

import com.google.common.base.Preconditions;

import org.codehaus.jackson.Version;

import org.codehaus.jackson.Versioned;

import org.codehaus.jackson.map.introspect.AnnotatedField;

import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;

import org.codehaus.jackson.util.VersionUtil;

import java.lang.annotation.Annotation;

import static com.google.common.base.Strings.isNullOrEmpty;

/**

* @author rollenholt

*/

public class DimensionFieldSerializer extends JacksonAnnotationIntrospector implements Versioned {

@Override

public Version version() {

return VersionUtil.versionFor(getClass());

}

@Override

public boolean isHandled(Annotation ann) {

Class> cls = ann.annotationType();

if (Dimension.class == cls) {

return true;

}

return super.isHandled(ann);

}

@Override

public String findSerializablePropertyName(AnnotatedField af) {

return getPropertyName(af);

}

@Override

public String findDeserializablePropertyName(AnnotatedField af) {

return getPropertyName(af);

}

private String getPropertyName(AnnotatedField af) {

Dimension annotation = af.getAnnotation(Dimension.class);

if (annotation != null) {

String valueType = annotation.valueType();

Preconditions.checkArgument(!isNullOrEmpty(valueType), "@Dimension注解中的valudType不能为空");

if (valueType.equalsIgnoreCase("id")) {

return af.getName() + "_id";

}

if (valueType.equalsIgnoreCase("code")) {

return af.getName() + "_code";

}

}

return af.getName();

}

}

同时为了触发上面的代码,以及为了验证我们的功能,我们有如下的代码:

/**

* @author rollenholt

*/

public class DimensionAdapterHelper {

private final static ObjectMapper objectMapper = new ObjectMapper();

static {

AnnotationIntrospector dimensionFieldSerializer = new DimensionFieldSerializer();

objectMapper.setAnnotationIntrospector(dimensionFieldSerializer);

}

public static String beanToJson(Object object) {

StringWriter sw = new StringWriter();

try {

objectMapper.writeValue(sw, object);

return sw.toString();

} catch (IOException e) {

throw Throwables.propagate(e);

}

}

public static T jsonToBean(String json, Class clazz) {

try {

return (T) objectMapper.readValue(json, clazz);

} catch (IOException e) {

throw Throwables.propagate(e);

}

}

public static class Type {

private String code;

@Dimension(valueType = "id")

private String description;

@Dimension(valueType = "code")

private String value;

public Type() {

}

public Type(String code, String description, String value) {

super();

this.code = code;

this.description = description;

this.value = value;

}

public String getCode() {

return code;

}

public void setCode(String code) {

this.code = code;

}

public String getDescription() {

return description;

}

public void setDescription(String description) {

this.description = description;

}

public String getValue() {

return value;

}

public void setValue(String value) {

this.value = value;

}

@Override

public String toString() {

return ToStringBuilder.reflectionToString(this);

}

}

public static void main(String[] args) {

Type t = new Type("a", "b", "c");

String json = beanToJson(t);

System.out.println(json);

Type type = jsonToBean(json, Type.class);

System.out.println(type);

}

}

运行之后输出结果为:

{"code":"a","description_id":"b","value_code":"c"}

DimensionAdapterHelper$Type@2cb4c3ab[code=a,description=b,value=c]

还算是很符合我们的期望的。

至于server端是如何替换json字符串的key的那块,简单的说一下,因为key有一定的格式,所以可以递归遍历json的所有key,就可以拿到有哪些key-value对需要处理了。关于如何在Java中递归便利Json,这个比较简单。如果大家觉的有需要,我后面在写。

参考资料

java 自定义注解 生成json_Jackson 通过自定义注解来控制json key的格式相关推荐

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

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

  2. java 自定义注解 生成json_SpringBoot:自定义注解实现后台接收Json参数

    0.需求 在实际的开发过程中,服务间调用一般使用Json传参的模式,SpringBoot项目无法使用@RequestParam接收Json传参 只有@RequestBody支持Json,但是每次为了一 ...

  3. java 自定义注解 生成json_Java使用@JsonDeserialize注解实现自定义反序列化器

    @JsonDeserialize注解用于在将JSON反序列化为Java对象时声明自定义反序列化器.我们可以通过使用泛型类型Employee继承 StdDeserializer类来实现自定义反序列化器, ...

  4. java 自定义注解 生成json_用自定义注解实现fastjson序列化的扩展

    这篇文章起源于项目中一个特殊的需求.由于目前的开发方式是前后端分离的,基本上是通过接口提供各个服务. 而前两天前端fe在开发中遇到了一些问题:他们在处理字符串类型的时间时会出现精度丢失的情况,所以希望 ...

  5. java自定义编号生成(支持前缀自定义)

    工作中要求合同编号自动生成 格式 NYZL-001,NYZL-002...在我的StringUtils工具类中新增如下方法,该方法可以自定义前缀以及当前排到数字几了(可从数据库中查询最大的编号+1) ...

  6. Java根据表格生成图_java绘制数据表格并导出为图片格式

    /*** @Description : 导出图片 *@param: * *@return: * 2020-04-23*/ public void actionExportReport(HttpServ ...

  7. 详解Dart中如何通过注解生成代码

    简介:详解dart与java注解生成代码异同点 作者:闲鱼技术-龙湫 1.背景 最近在项目中使用到了Dart中的注解代码生成技术,这跟之前Java中APT+JavaPoet生成代码那套技术还是有一些不 ...

  8. 使用Java反射(Reflect)、自定义注解(Customer Annotation)生成简单SQL语句

    使用Java反射(Reflect).自定义注解(Customer Annotation)生成简单SQL语句 这次给大家介绍一下在Java开发过程中 使用自定义注解开发: 主要知识点:          ...

  9. java 外部覆盖内部配置,Spring 与自定义注解、外部配置化的结合使用

    Spring 与自定义注解.外部配置化的结合使用 一.Java注解的简单介绍 注解,也叫Annotation.标注,是 Java 5 带来的新特性. 可使用范围 类.字段.方法.参数.构造函数.包等, ...

最新文章

  1. 如何快速部署国人开源的 Java 博客系统 Tale
  2. 《Hadoop技术详解》一导读
  3. 无法从套接字读取更多的数据 oracle_小伙面试时被追问数据库优化,面试前如何埋点反杀?
  4. Linux高级编程实验(30个)
  5. 飞行棋 c语言,骑士飞行棋【纯c】
  6. 对话框应用程序的DoModal()源代码
  7. 2000-2018年各省研发投入面板数据
  8. 利用BigDecimal类巧妙处理Double类型精度丢失
  9. The 'mode' option has not been set, webpack will fallback to 'production' for th is value
  10. 笔记本软件兼容性测试,Windows 10 技术预览版 国产杀毒软件兼容性测试:大多可以使用...
  11. 在工作中历练思考力,行动力,表达力
  12. 群晖设置公网ipv6方式域名解析访问
  13. 桌面系统(web前端)jQuery制作Web桌面系统界面类似WebQQ桌面布局
  14. 关于全球苹果手机的型号版本介绍
  15. 第 254 场力扣周赛(KMP、贪心、快速幂、二分+多源bfs、并查集 + 时光倒流)
  16. RTSP安防网络摄像头/海康大华硬盘录像机网页无插件直播流媒体服务器EasyNVR证书配置页面按钮无法正常打开和关闭的问题解析
  17. Vue基础学习笔记Day02_vue-cli脚手架_基础API
  18. V370 Intel WiFi Link 1000 BGN驱动如何正确安装
  19. [android图片压缩]一款不错的图片压缩,值得学习!
  20. 视频中的音频如何提取出来?分享简单好用的提取方法

热门文章

  1. matplotlib绘制三维折线图
  2. 解决file.seek()读取文件报错:AttributeError: ‘str‘ object has no attribute ‘seek‘
  3. Intellij IDEA 安装jnetpcap开发环境与 no jnetpcap in java.library.path 的解决方案
  4. django-xadmin出现Models aren't loaded yet错误
  5. 公司java框架让程序员变笨_框架会使程序员变笨吗?
  6. django--cookie与session
  7. siege4安装和使用介绍
  8. html5标签兼容低版本浏览器
  9. listview的item中嵌套多个EditText时的问题
  10. openssl生成私钥公钥的步骤