Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] 自定义注解,Yapi上加入到Header参数上 #1174

Open
Noel443 opened this issue Nov 25, 2024 · 10 comments · May be fixed by #1176
Open

[Feature] 自定义注解,Yapi上加入到Header参数上 #1174

Noel443 opened this issue Nov 25, 2024 · 10 comments · May be fixed by #1176
Labels
status: work-in-progress Currently being worked on type: feature request Feature Enhancement Request

Comments

@Noel443
Copy link

Noel443 commented Nov 25, 2024

我的项目需要通过参数去校验请求头有没有这个header,如果没有则报参数不足异常。而能够满足我的功能的是@RequestHeader("xxx"),这个注解在Yapi是能出现的,而我现在需要在我的java bean的某一字段加上我的自定义注解,使其能在YApi上展示出我的header是必须参数,我翻阅了文档,并没有找到相应的说明,是我没找到还是目前暂时不支持?

使用了@RequestHeader("xxx")
image

目前我的自定义注解
image

@Noel443 Noel443 added the type: feature request Feature Enhancement Request label Nov 25, 2024
@tangcent
Copy link
Owner

试试配一下: method.additional.header

@Noel443
Copy link
Author

Noel443 commented Nov 25, 2024

我尝试使用method.additional.header去写到.easy.api.config配置文件上,我想运行一段groovy代码去动态添加header

method.additional.header[groovy:it.containingClass().name().startsWith("com.xxx.controller")]=
    import java.util.logging.Logger
    import com.xxxx.xxxx.xxxx.HeaderCheck

    def log = Logger.getLogger("HeaderGenerator")
    def headers = []

    try {
        if (method.parameters && method.parameters.size() > 0) {
            def parameter = method.parameters[0]
            def paramValue = parameter.value

            if (paramValue) {
                def fields = paramValue.class.getDeclaredFields()
                fields.each { field ->
                    field.setAccessible(true)
                    def annotation = field.getAnnotation(HeaderCheck)
                    if (annotation) {
                        def fieldValue = field.get(paramValue)
                        if (fieldValue != null) {
                            headers.add([
                                name: annotation.value(),
                                value: fieldValue,
                                required: true
                            ])
                        } else {
                            log.warning("Field value is null for field: ${field.name}")
                        }
                    } else {
                        log.fine("No HeaderCheck annotation found on field: ${field.name}")
                    }
                }
            } else {
                log.warning("Parameter value is null")
            }
        } else {
            log.warning("Method has no parameters or not enough parameters")
        }
    } catch (Exception e) {
        log.severe("Error generating headers: ${e.message}")
        e.printStackTrace()
    }

    return headers

但是我不知道如何让他生效,我的能力不是很够,看日志不知道如何定位问题,看了文档并没有找到相应的答案,
https://easyyapi.com/setting/rules/method_additional_header.html
https://easyyapi.com/setting/local-file-config.html
如果有空可以帮我看看如何解决这个问题吗?十分感谢

@tangcent
Copy link
Owner

试试这样:

method.additional.header[groovy:it.containingClass().name().startsWith("xxxx.xxxx.xxxx.controller")]=groovy:```
  logger.info("it:"+it)
  for (arg in it.args()) {
      logger.info("arg:"+arg)
      logger.info("type:"+arg.type())
      logger.info("fields:"+arg.type().fields())
      for (field in arg.type().fields()) {
          logger.info("field: "+field+", annotated with: xxxx.xxxx.xxxx.Annotation :"+field.hasAnn("xxxx.xxxx.xxxx.Annotation"))
          if (field.hasAnn("xxxx.xxxx.xxxx.Annotation")) {
              logger.info("Annotation found on:"+field)
              return tool.toJson([
                  name: "xxx-xxx-xxx",
                  value: "{{xxx-xxx-xxx}}",
                  desc: "xxxx",
                  required: true,
                  example: ""
              ])
          }
      }
  }
```

@tangcent
Copy link
Owner

or:

method.additional.header[groovy:it.containingClass().name().startsWith("xxxx.xxxx.xxxx.controller")]=groovy:```
  logger.info("it:"+it)
  for (arg in it.args()) {
      logger.info("arg:"+arg)
      logger.info("type:"+arg.type())
      logger.info("fields:"+arg.type().fields())
      for (field in arg.type().fields()) {
          def header = field.ann("xxxx.xxxx.xxxx.Header")
          logger.info("field: "+field+", annotated with: xxxx.xxxx.xxxx.Annotation, required:"+header)
          if (header!=null) {
              logger.info("Annotation found on:"+field)
              return tool.toJson([
                  name: header,
                  value: "{{xxx-xxx-xxx}}",
                  desc: "xxxx",
                  required: true,
                  example: ""
              ])
          }
      }
  }
```

@Noel443
Copy link
Author

Noel443 commented Nov 26, 2024

它成功导出了,但是有一个小的问题,就是假如我的入参类型字段存在一个泛型,是无法获取它的type()的吗?我需要获取入参类型的data字段里面,去获取它是否存在我的HeaderCheck注解

method.additional.header[groovy:it.containingClass().name().startsWith("com.xxx.controller")]=groovy:```
  logger.info("it: "+it)
  for (arg in it.args()) {
      logger.info("arg: "+arg)
      logger.info("type: "+arg.type())
      logger.info("fields: "+arg.type().fields())
      for (field in arg.type().fields()) {
          def header = field.ann("xxxx.xxxx.HeaderCheck")
          logger.info("field: "+field+", annotated with: xxxx.xxxx.HeaderCheck, required:"+header)
          if (header!=null) {
              logger.info("Annotation found on:"+field)
              return tool.toJson([
                  name: header,
                  required: true,
              ])
          }
      }
      def fieldNames = arg.type().fields().collect { it.name }
      logger.info("Field names: "+fieldNames)
      if (fieldNames == ['current', 'size', 'data']) {
          logger.info("Fields only contain current, size, and data")
                  def dataField = arg.type().fields().find { it.name == 'data' }
                  if (dataField) {
                      logger.info("Found data field: " + dataField)
                      def dataType = dataField.type()
                      logger.info("Data field type: " + dataType)
                       if (dataType instanceof java.lang.reflect.ParameterizedType) {
                           def actualTypeArguments = dataType.actualTypeArguments
                           if (actualTypeArguments.length > 0) {
                               def genericType = actualTypeArguments[0]
                               logger.info("Generic type: " + genericType)
                               def genericClass = genericType.rawType as Class
                               logger.info("Generic class: " + genericClass)

                               for (innerField in genericClass.declaredFields) {
                                   def header = innerField.getAnnotation(xxxx.xxxx.HeaderCheck)
                                   logger.info("data field: " + innerField + ", annotated with: xxxx.xxxx.HeaderCheck, required: " + header)
                                   if (header != null) {
                                       logger.info("Annotation found on data field: " + innerField)
                                       return tool.toJson([
                                           name: header.name(),
                                           required: header.required(),
                                       ])
                                   }
                               }
                           } else {
                               logger.warn("Data field is not a generic type")
                           }
                       } else {
                           logger.warn("Field type is not a parameterized type")
                       }
                  } else {
                      logger.warn("Data field not found")
                  }
      }
  }

我的这个日志是[INFO] Data field type: ,说明这个type根本拿不出来,被泛型擦出了,我尝试用gpt帮我修改,但是并不生效,尝试很多办法都不能生效。我应该怎么去处理这个问题呢?十分感谢帮我进行解答 @tangcent
我的类是这样的
image

@tangcent
Copy link
Owner

@Noel443 应该是这里.fields()的泛型没传递下去,等我修复吧 :)

@Noel443
Copy link
Author

Noel443 commented Nov 27, 2024

这里还有一个问题,我发现header只能add一个,于是乎我用数组接住json,后面一并返回,新修改的代码是这样的

method.additional.header[groovy:it.containingClass().name().startsWith("com.xxx.controller")]=groovy:```
  logger.info("所属类 "+ it)
  def headers = []
  for (arg in it.args()) {
      logger.info("入参: "+ arg)
      logger.info("入参类型: "+ arg.type())
      logger.info("入参类型字段: "+ arg.type().fields())
      for (field in arg.type().fields()) {
          def header = field.ann("com.xxx.xxx.xxx.HeaderCheck")
          if (header!=null) {
              logger.info("找到必须header字段: "+ field)
              def json = tool.toJson([
                  name: header,
                  required: true,
              ])
              headers.add(json)
          }
      }
      def fieldNames = arg.type().fields().collect { it.name }
      logger.info("字段名: "+ fieldNames)
      if (fieldNames == ['current', 'size', 'data']) {
          logger.info("参数类型只有 current, size, data 三个字段")
                  def dataField = arg.type().fields().find { it.name == 'data' }
                  if (dataField) {
                      def dataType = dataField.type()
                      logger.info("Data field type: " + dataType)
                      logger.info("泛型获取该插件暂时存在缺陷无法获取,等待作者修复")
                       if (dataType instanceof java.lang.reflect.ParameterizedType) {
                           def actualTypeArguments = dataType.actualTypeArguments
                           if (actualTypeArguments.length > 0) {
                               def genericType = actualTypeArguments[0]
                               logger.info("泛型类型 " + genericType)

                               def genericClass = genericType.rawType as Class
                               logger.info("泛型类: " + genericClass)

                               for (innerField in genericClass.declaredFields) {
                                   def header = innerField.getAnnotation(com.xxx.xxx.xxx.HeaderCheck)
                                   if (header != null) {
                                       logger.info("找到必须header字段: "+ field)
                                       def innerJson = tool.toJson([
                                           name: header.name(),
                                           required: header.required(),
                                       ])
                                       headers.add(innerJson)
                                   }
                               }
                           } else {
                               logger.warn("data字段不是泛型类型")
                           }
                       } else {
                           logger.warn("data字段未找到")
                       }
                  } else {
                      logger.warn("data字段未找到")
                  }
      }
  }
  return headers

但是它的日志出现是:[ERROR] error to parse additional header: [{"name":"header1","required":true}, {"name":"header2","required":true}],这个问题目前有办法处理吗?我自己也尝试找很多办法,但是找不到过多的参考价值,如果有时间,可以帮我看一下吗?十分感谢 @tangcent

@tangcent
Copy link
Owner

这里还有一个问题,我发现header只能add一个,于是乎我用数组接住json,后面一并返回

目前method.additional.header这个规则只接受一个header,但你可以配多条method.additional.header,每条处理某一个header.

dataType instanceof java.lang.reflect.ParameterizedType

这里是没办法用ParameterizedType的,这不是运行时环境,你的class也并没有加载到JVM里,这里的dataType你可以理解为一组数据,记录了你这个类里有什么字段。

@tangcent
Copy link
Owner

尝试处理了类型擦除的问题, 可以试试. easy-yapi-2.7.3.212.0.zip

@tangcent
Copy link
Owner

尝试处理了类型擦除的问题, 可以试试. easy-yapi-2.7.3.212.0.zip
另外如果规则编写有点困难,可以尝试提供一个例子,描述一下你想达成的效果,我给你看看。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: work-in-progress Currently being worked on type: feature request Feature Enhancement Request
Projects
None yet
2 participants