本文作者:suxingrui
本文链接:https://blog.csdn.net/suxingrui/article/details/103788530
版权声明:本文为原创文章,转载请注明出处。

回顾2019年碰到的问题及解决方式
问题:读取Java源文件中字段的注释当做Swagger的字段描述

问题发现:
正常来说,Swagger通过使用@ApiModelProperty来标注Bean对象的字段的相关信息
然后,我们在一个老服务中引进Swagger,如果需要Swagger UI中显示即存Bean对象的字段的信息的话,
那就需要给这几十上百个Bean对象的每个字段都加上@ApiModelProperty
这是一个艰难的工作。。。

所以,考虑着通过读取源文件中字段的注释的方式来实现:不添加@ApiModelProperty也能显示字段描述的目标

调查分析:
又是一系列的源码跟踪分析,继承Swagger的ModelMapperImpl覆盖mapModels方法,并在里面补存对象的属性即可

读取源码中的注释,可以使用工具类:

     <dependency><groupId>org.jboss.forge.roaster</groupId><artifactId>roaster-api</artifactId><version>2.21.0.Final</version></dependency><dependency><groupId>org.jboss.forge.roaster</groupId><artifactId>roaster-jdt</artifactId><version>2.21.0.Final</version></dependency>

支持读取【/** 描述*/】,不支持【// 描述】

解决方法:
1、实现一个内部的字段描述类:FieldDesc

 private static class FieldDesc {String name; // 字段String type; // 类型String desc; // 描述private FieldDesc(String name, String type, String desc) {this.name = name;this.type = type;this.desc = desc;}}

2、实现根据类对象读取对应源码的字段描述的方法
PS1:因为使用的是spring-boot-maven-plugin打包的,所以这里获取类对应jar包名的方式不一定适用所有同学
PS2:同时,刚好Jenkins与测试机器在同一台机器,所以这里获取源码的方式就是简单的配置路径即可(笑)
不然,可以考虑打测试包的同时把源码打包,或者编译打包之后同时推送源码包到测试环境的指定目录下

 private static final Pattern FIND_JAR_PATTERN = Pattern.compile("/WEB-INF/lib/(\\S+)\\.jar!");private static final Pattern FIND_NAME_PATTERN = Pattern.compile("(\\S+)-[\\d]+\\.");@Value("${swagger.api.workspace:}")private String apiWorkspace;@Value("#{'${swagger.lib.workspaces:}'.split(',')}")private String[] libWorkspaces;private Map<String, FieldDesc> getFieldDescMap(Class<?> clz) {Map<String, FieldDesc> fieldDescMap = Maps.newLinkedHashMap();try {URL url = clz.getResource("/" + clz.getName().replace('.', '/') + ".class");String classPath = url.getFile();// 获取开发环境,本地的源码String sourcePath = classPath.replaceAll("target/classes", "src/main/java");sourcePath = sourcePath.substring(0, sourcePath.length() - ".class".length()) + ".java";File sourceFile = new File(sourcePath);String source;if (!sourceFile.exists()) {// 打包之后的,对象即可能在classes下面也可能在lib包里,获取类对应的jar包名称if (classPath.contains("/WEB-INF/classes!/")) {sourcePath = apiWorkspace;} else if (classPath.contains("/WEB-INF/lib/")) {Matcher matcher = FIND_JAR_PATTERN.matcher(classPath);if (matcher.find()) {sourcePath = matcher.group(1);matcher = FIND_NAME_PATTERN.matcher(sourcePath);if (matcher.find()) {sourcePath = matcher.group(1);}}}sourcePath = sourcePath + "/src/main/java/" + clz.getName().replace('.', '/') + ".java";for (String w : libWorkspaces) {sourceFile = new File(w + sourcePath);if (sourceFile.exists()) {log.debug("sourcePath:{}", sourcePath);break;}}}if (sourceFile.exists()) {source = Files.asCharSource(sourceFile, Charset.forName("UTF-8")).read();// 读取源码JavaType<?> javaType = Roaster.parse(source); // 解析源码if (javaType != null && javaType.isClass()) {JavaClassSource javaClassSource = (JavaClassSource) javaType;List<FieldSource<JavaClassSource>> fields = javaClassSource.getFields();if (fields != null) {for (FieldSource<JavaClassSource> field : fields) {String type = field.getType().getName().toLowerCase();fieldDescMap.put(field.getName(),new FieldDesc(field.getName(), type, field.getJavaDoc().getText()));}}}}} catch (IOException e) {log.info("【SWAGGER】读取源文件异常:{}", e.getMessage());}Class<?> superClass = clz.getSuperclass();if (superClass != null && superClass != Object.class) {fieldDescMap.putAll(getFieldDescMap(superClass));}return fieldDescMap;}

3、使用从源码中获取到的类字段的描述,补充到Swagger中

/*** 覆写swagger的ModelMapper,实现:读取文件源码字段的注释当做swagger的字段描述** @author suxingrui* @time Jun 29, 2019 11:28:41 AM*/
@Slf4j
@Primary
@Configuration
public class ModelMapperImplEx extends ModelMapperImpl {@Overridepublic Map<String, Model> mapModels(Map<String, springfox.documentation.schema.Model> from) {Map<String, Model> map = super.mapModels(from);if (map != null) {Set<String> modelKeys = from.keySet();// 遍历所有的Modelfor (String key : modelKeys) {Model tm = map.get(key);// Model的属性Map<String, Property> properties = tm.getProperties();if (properties == null) {continue;}ResolvedType resolvedType = from.get(key).getType();List<RawField> memberFields = resolvedType.getMemberFields();Map<String, FieldDesc> fieldDescMap = getFieldDescMap(resolvedType.getErasedType());// 新的属性Map<String, Property> newProperties = Maps.newLinkedHashMap();for (RawField rawField : memberFields) {String name = rawField.getName();Property property = properties.remove(name);if (property == null) {continue;}if (property instanceof StringProperty) {StringProperty sp = (StringProperty) property;// 枚举使用int,这边的规范,可以按实际删除if (sp.getEnum() != null && sp.getEnum().size() > 0) {property = new IntegerProperty();property.setName(name);property.setDescription(sp.getDescription());}}newProperties.put(name, property);if (StringUtils.isNoneBlank(property.getDescription())) {continue;}// 没有描述时,使用从源码获取的FieldDesc fieldDesc = fieldDescMap.remove(name);if (fieldDesc != null) {property.setDescription(fieldDesc.desc);}}for (FieldDesc fieldDesc : fieldDescMap.values()) {Property property;if ("integer".equals(fieldDesc.type) || "int".equals(fieldDesc.type)) {property = new IntegerProperty();} else if ("boolean".equals(fieldDesc.type)) {property = new BooleanProperty();} else if (fieldDesc.type.endsWith("enum")) {property = new IntegerProperty();} else {property = new StringProperty();}property.setName(fieldDesc.name);property.setDescription(fieldDesc.desc);newProperties.put(fieldDesc.name, property);}try {// 新的属性列表替换旧的Field propertiesField = FieldUtils.getDeclaredField(tm.getClass(), "properties", true);if (propertiesField != null) {propertiesField.set(tm, newProperties);}} catch (Exception e) {log.info("【SWAGGER】设置properties异常:{}", e.getMessage());}}}return map;}...
}

读取Java源文件中字段的注释当做Swagger的字段描述相关推荐

  1. Python编程 统计Java源文件代码行数,注释行数,空白行数

    每次学习新的语言,就想重新实现一遍做过的课设=,= 这里实现的是"综合性实验 Java源代码分析程序"的第三部分 第二部分见:[Python编程]统计目录下Java源文件的关键字出 ...

  2. 在一个java源文件中只能定义_10在Java的一个源文件中可以定义多个类。

    [单选题]一组常量和抽象方法的集合可以定义成一个 ( ) [判断题]3.当定义一个类时没定义构造方法,则系统自动产生一个构方法. [填空题]JAVA源程序中,跨越多行的注释只需在开始和结尾处用____ ...

  3. 一个java源文件允许_一个Java源文件中最多只能有一个class定义

    一个Java源文件中最多只能有一个class定义 答:× 确诊甲状腺功能紊乱的常规指标是 答:FT3和FT4 I will not let my children in that way. 答:be ...

  4. 一个java源文件中可以声明多少个class与编译后会生成多少个字节码文件

    在一个java源文件中可以声明多个class. 但是,只能最多有一个类声明为public的. 而且要求声明为public的类的类名必须与源文件名相同. 编译的过程 编译以后,会生成一个或多个字节码文件 ...

  5. 删除 java代码中所有的注释

    删除 java代码中所有的注释.java public class CleanCommons {private static Pattern pattern = Pattern.compile(&qu ...

  6. 一个.java源文件中可以有多个类吗?(内部类除外)有什么条件?

    java教程中有一句话叫做"在同一个源程序中只能有一个public类"---- 应该理解为只有一个public类的名字与文件名一致. 一个.java源文件中可以有多个类吗?(内部类 ...

  7. 【错误记录】IntelliJ IDEA 中 Java 代码中的中文注释报错 ( Menu / File / Settings / Editor / File Encodings 中修改工程编码 )

    文章目录 一.报错信息 二.解决方案 一.报错信息 在 IntelliJ IDEA 中 , 出现中文注释报错 ; Y:\002_WorkSpace\003_IDEA\Groovy_Demo\src\m ...

  8. vb 读取mysql所有表名_VB 读取ACCESS数据库中所有表名和指定表字段名.doc

    VB 读取ACCESS数据库中所有表名和指定表字段名 托束显疫面绰么蚂扛沁米衅居鸳辗熊踌薄舱杂们帖婉珍抓津担庐撕枪呻头胀亨短宛溅锭语氏遣搀赠摩紧茧综逾颂备呛庞枷脓移厚醛仕恬浸值胶碟亦短咳腥钥捎魄朗氟商 ...

  9. asciidoc html java_如何使用AsciiDoclet从.java文件中的javadoc注释生成asciidoc文件

    我是asciidoc的新手.我想在 java文件中从注释的 javadoc(asciidoc格式)生成HTML文档. 例如java文件 /** * = Asciidoclet * * Sample c ...

最新文章

  1. cssbefore图片大小_两小时学会CSS-before after 伪元素
  2. (C++)CSP 201712-2 游戏
  3. sort()函数、C++
  4. socket用起始码分割_常用条码Code128码及EAN13码的介绍
  5. 蚂蚁员工持股平台管理权变更 马云持股降至34%
  6. python接口自动化测试一:http协议
  7. firebug js版
  8. web报表工具FineReport常见的数据集报错错误代码和解释
  9. CentOS6.2下安装中文输入法
  10. Java 开源 CMS :magnolia
  11. 如何将CAD格式转成可以编辑的矢量图
  12. 毕设总结(理工本科)
  13. 常用RGB颜色查询对照表及感情色
  14. Kibana:使用 drilldown 从一个仪表板切换到另外一个仪表板
  15. linux 拼音输出繁体_解决rime仓颉拼音反查为繁体的问题
  16. W3Cschool从零开始学C语言笔记(1-2)位、字节及排列组合
  17. Win10正式版Guest来宾账户开启使用方法
  18. vue3 出现 Component inside <Transition> renders non-element root node that cannot be animated.
  19. 手机屏分几种?什么叫水滴屏、刘海屏、瀑布屏、全面屏?
  20. 【数值分析不挂科】第六章 | 线性方程组直接法 迭代法

热门文章

  1. 前端工程化-我们需要做什么
  2. matlab 压缩感知矩阵_【精读】基于MATLAB的钢筋下料优化算法
  3. C++ 字元陣列(C-style)、字元指標、String類別 使用方式整理
  4. 什么是Scheme?原来还可以这样应用!
  5. android studio 或者 idea 前进 后退 箭头图标添加到 工具栏
  6. Ruby-Devise采用多种形式登录
  7. Receptive Field Block Net for Accurate and Fast Object Detection(RFB)
  8. Android之微信界面设计
  9. LightGBM综述
  10. 互联网奥秘_Excel数据表的奥秘