From cd81eafbd0f1bcad09259cedb75244bf46ea45de Mon Sep 17 00:00:00 2001
From: linwumingshi
Date: Tue, 29 Oct 2024 18:04:57 +0800
Subject: [PATCH] fix: :bug: resolve incorrect parsing of constants in
`@JsonProperty` and `@JSONField` annotations
- Fixed an issue where constants from a constant class in `@JsonProperty` and `@JSONField` annotations were not correctly parsed in generated documentation
- Fixed an issue where constants from a constant class in `@ServerEndpoint` subprotocols value
[issues 934](https://github.com/TongchengOpenSource/smart-doc/issues/934)
---
.../doc/handler/IWebSocketRequestHandler.java | 10 +-
.../java/com/ly/doc/helper/BaseHelper.java | 12 ++-
.../ly/doc/template/IWebSocketTemplate.java | 21 +++-
src/main/java/com/ly/doc/utils/DocUtil.java | 100 ++++++++++++++----
.../java/com/ly/doc/utils/JavaClassUtil.java | 46 ++++++--
5 files changed, 150 insertions(+), 39 deletions(-)
diff --git a/src/main/java/com/ly/doc/handler/IWebSocketRequestHandler.java b/src/main/java/com/ly/doc/handler/IWebSocketRequestHandler.java
index 21105f36..1bd304ad 100644
--- a/src/main/java/com/ly/doc/handler/IWebSocketRequestHandler.java
+++ b/src/main/java/com/ly/doc/handler/IWebSocketRequestHandler.java
@@ -20,6 +20,7 @@
*/
package com.ly.doc.handler;
+import com.ly.doc.builder.ProjectDocConfigBuilder;
import com.ly.doc.constants.DocAnnotationConstants;
import com.ly.doc.constants.DocTags;
import com.ly.doc.model.request.ServerEndpoint;
@@ -28,6 +29,7 @@
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -40,11 +42,13 @@ public interface IWebSocketRequestHandler {
/**
* handle class annotation `@ServerEndpoint`
+ * @param projectBuilder the project configuration builder
* @param javaAnnotation javaAnnotation @ServerEndpoint
* @param cls JavaClass
* @return ServerEndpoint
*/
- default ServerEndpoint handleServerEndpoint(JavaClass cls, JavaAnnotation javaAnnotation) {
+ default ServerEndpoint handleServerEndpoint(ProjectDocConfigBuilder projectBuilder, JavaClass cls,
+ JavaAnnotation javaAnnotation) {
if (Objects.nonNull(cls.getTagByName(DocTags.IGNORE))) {
return null;
}
@@ -56,7 +60,9 @@ default ServerEndpoint handleServerEndpoint(JavaClass cls, JavaAnnotation javaAn
.ifPresent(builder::setUrl);
// get subProtocols of annotation
- builder.setSubProtocols(JavaClassUtil.getAnnotationValueStrings(javaAnnotation, "subprotocols"));
+ List subProtocols = JavaClassUtil.getAnnotationValueStrings(projectBuilder, javaAnnotation,
+ "subprotocols");
+ builder.setSubProtocols(subProtocols);
// Handle 'decoders' property
builder.setDecoders(JavaClassUtil.getAnnotationValueClassNames(javaAnnotation, "decoders"));
diff --git a/src/main/java/com/ly/doc/helper/BaseHelper.java b/src/main/java/com/ly/doc/helper/BaseHelper.java
index 591af02a..bc8a7d49 100644
--- a/src/main/java/com/ly/doc/helper/BaseHelper.java
+++ b/src/main/java/com/ly/doc/helper/BaseHelper.java
@@ -176,8 +176,10 @@ protected static FieldJsonAnnotationInfo getFieldJsonAnnotationInfo(ProjectDocCo
// Handle @JSONField
if (DocAnnotationConstants.SHORT_JSON_FIELD.equals(annotationName)) {
if (null != annotation.getProperty(DocAnnotationConstants.NAME_PROP)) {
- fieldJsonAnnotationInfo.setFieldName(StringUtil
- .removeQuotes(annotation.getProperty(DocAnnotationConstants.NAME_PROP).toString()));
+ AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.NAME_PROP);
+ String fieldName = DocUtil.resolveAnnotationValue(projectBuilder.getApiConfig().getClassLoader(),
+ annotationValue);
+ fieldJsonAnnotationInfo.setFieldName(fieldName);
}
}
@@ -185,9 +187,9 @@ protected static FieldJsonAnnotationInfo getFieldJsonAnnotationInfo(ProjectDocCo
else if (DocAnnotationConstants.SHORT_JSON_PROPERTY.equals(annotationName)
|| DocAnnotationConstants.GSON_ALIAS_NAME.equals(annotationName)) {
AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.VALUE_PROP);
- if (null != annotationValue) {
- fieldJsonAnnotationInfo.setFieldName(StringUtil.removeQuotes(annotationValue.toString()));
- }
+ String fieldName = DocUtil.resolveAnnotationValue(projectBuilder.getApiConfig().getClassLoader(),
+ annotationValue);
+ fieldJsonAnnotationInfo.setFieldName(fieldName);
}
// Handle JSR303 required
if (JavaClassValidateUtil.isJSR303Required(annotationName) && !isResp) {
diff --git a/src/main/java/com/ly/doc/template/IWebSocketTemplate.java b/src/main/java/com/ly/doc/template/IWebSocketTemplate.java
index a2b04100..f953acbd 100644
--- a/src/main/java/com/ly/doc/template/IWebSocketTemplate.java
+++ b/src/main/java/com/ly/doc/template/IWebSocketTemplate.java
@@ -39,10 +39,25 @@
import com.ly.doc.utils.JavaClassUtil;
import com.power.common.util.StringUtil;
import com.power.common.util.ValidateUtil;
-import com.thoughtworks.qdox.model.*;
+import com.thoughtworks.qdox.model.JavaAnnotation;
+import com.thoughtworks.qdox.model.JavaClass;
+import com.thoughtworks.qdox.model.JavaMethod;
+import com.thoughtworks.qdox.model.JavaParameter;
+import com.thoughtworks.qdox.model.JavaType;
import com.thoughtworks.qdox.model.impl.DefaultJavaParameterizedType;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -157,7 +172,7 @@ default WebSocketDoc buildEntryPointWebSocketDoc(final JavaClass javaClass, Proj
webSocketRequestHandler = Objects.isNull(webSocketRequestHandler) ? DefaultWebSocketRequestHandler.getInstance()
: webSocketRequestHandler;
- ServerEndpoint serverEndpoint = webSocketRequestHandler.handleServerEndpoint(javaClass,
+ ServerEndpoint serverEndpoint = webSocketRequestHandler.handleServerEndpoint(projectBuilder, javaClass,
serverEndpointAnnotation);
WebSocketDoc webSocketDoc = new WebSocketDoc();
diff --git a/src/main/java/com/ly/doc/utils/DocUtil.java b/src/main/java/com/ly/doc/utils/DocUtil.java
index 58216a13..362f0492 100644
--- a/src/main/java/com/ly/doc/utils/DocUtil.java
+++ b/src/main/java/com/ly/doc/utils/DocUtil.java
@@ -20,16 +20,42 @@
*/
package com.ly.doc.utils;
-import com.ly.doc.constants.*;
+import com.ly.doc.constants.DocAnnotationConstants;
+import com.ly.doc.constants.DocGlobalConstants;
+import com.ly.doc.constants.DocTags;
+import com.ly.doc.constants.JAXRSAnnotations;
+import com.ly.doc.constants.JakartaJaxrsAnnotations;
+import com.ly.doc.constants.JavaTypeConstants;
+import com.ly.doc.constants.MediaType;
import com.ly.doc.extension.dict.DictionaryValuesResolver;
-import com.ly.doc.model.*;
+import com.ly.doc.model.ApiConfig;
+import com.ly.doc.model.ApiDataDictionary;
+import com.ly.doc.model.ApiDocDict;
+import com.ly.doc.model.ApiErrorCode;
+import com.ly.doc.model.ApiErrorCodeDictionary;
+import com.ly.doc.model.ApiReqParam;
+import com.ly.doc.model.DataDict;
+import com.ly.doc.model.DocJavaField;
+import com.ly.doc.model.FormData;
+import com.ly.doc.model.SystemPlaceholders;
import com.ly.doc.model.request.RequestMapping;
import com.mifmif.common.regex.Generex;
-import com.power.common.util.*;
+import com.power.common.util.CollectionUtil;
+import com.power.common.util.DateTimeUtil;
+import com.power.common.util.EnumUtil;
+import com.power.common.util.IDCardUtil;
+import com.power.common.util.RandomUtil;
+import com.power.common.util.StringUtil;
import com.thoughtworks.qdox.JavaProjectBuilder;
-import com.thoughtworks.qdox.model.*;
+import com.thoughtworks.qdox.model.DocletTag;
+import com.thoughtworks.qdox.model.JavaAnnotation;
+import com.thoughtworks.qdox.model.JavaClass;
+import com.thoughtworks.qdox.model.JavaField;
+import com.thoughtworks.qdox.model.JavaMember;
+import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.expression.Add;
import com.thoughtworks.qdox.model.expression.AnnotationValue;
+import com.thoughtworks.qdox.model.expression.Constant;
import com.thoughtworks.qdox.model.expression.Expression;
import com.thoughtworks.qdox.model.expression.FieldRef;
import net.datafaker.Faker;
@@ -37,9 +63,35 @@
import org.apache.commons.lang3.StringUtils;
import java.text.DecimalFormat;
-import java.time.*;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.Stack;
+import java.util.TimeZone;
+import java.util.UUID;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -969,30 +1021,36 @@ public static String getPathUrl(ClassLoader classLoader, JavaAnnotation annotati
* @return annotation value
*/
public static String resolveAnnotationValue(ClassLoader classLoader, AnnotationValue annotationValue) {
+ // if it is a constant, return its value directly
+ if (annotationValue instanceof Constant) {
+ return ((Constant) annotationValue).getValue().toString();
+ }
+ // if it is an add operation, return the result directly
if (annotationValue instanceof Add) {
Add add = (Add) annotationValue;
String leftValue = resolveAnnotationValue(classLoader, add.getLeft());
String rightValue = resolveAnnotationValue(classLoader, add.getRight());
return StringUtil.removeQuotes(leftValue + rightValue);
}
- else {
- if (annotationValue instanceof FieldRef) {
- FieldRef fieldRef = (FieldRef) annotationValue;
- JavaField javaField = fieldRef.getField();
- if (javaField != null) {
- String fieldValue = JavaFieldUtil.getConstantsFieldValue(classLoader, javaField.getDeclaringClass(),
- javaField.getName());
- if (StringUtil.isNotEmpty(fieldValue)) {
- return StringUtil.removeQuotes(fieldValue);
- }
- return StringUtil.removeQuotes(javaField.getInitializationExpression());
+ // if it is a field reference, return its value directly
+ if (annotationValue instanceof FieldRef) {
+ FieldRef fieldRef = (FieldRef) annotationValue;
+ JavaField javaField = fieldRef.getField();
+ if (javaField != null) {
+ String fieldValue = JavaFieldUtil.getConstantsFieldValue(classLoader, javaField.getDeclaringClass(),
+ javaField.getName());
+ if (StringUtil.isNotEmpty(fieldValue)) {
+ return StringUtil.removeQuotes(fieldValue);
}
+ return StringUtil.removeQuotes(javaField.getInitializationExpression());
}
- return Optional.ofNullable(annotationValue)
- .map(Expression::getParameterValue)
- .map(Object::toString)
- .orElse(StringUtil.EMPTY);
}
+ // default return
+ return Optional.ofNullable(annotationValue)
+ .map(Expression::getParameterValue)
+ .map(Object::toString)
+ .orElse(StringUtil.EMPTY);
+
}
/**
diff --git a/src/main/java/com/ly/doc/utils/JavaClassUtil.java b/src/main/java/com/ly/doc/utils/JavaClassUtil.java
index ff311fa9..01b5e524 100644
--- a/src/main/java/com/ly/doc/utils/JavaClassUtil.java
+++ b/src/main/java/com/ly/doc/utils/JavaClassUtil.java
@@ -23,7 +23,13 @@
package com.ly.doc.utils;
import com.ly.doc.builder.ProjectDocConfigBuilder;
-import com.ly.doc.constants.*;
+import com.ly.doc.constants.DefaultClassConstants;
+import com.ly.doc.constants.DocAnnotationConstants;
+import com.ly.doc.constants.DocGlobalConstants;
+import com.ly.doc.constants.DocTags;
+import com.ly.doc.constants.DocValidatorAnnotationEnum;
+import com.ly.doc.constants.JSRAnnotationConstants;
+import com.ly.doc.constants.JavaTypeConstants;
import com.ly.doc.model.ApiConfig;
import com.ly.doc.model.ApiDataDictionary;
import com.ly.doc.model.DocJavaField;
@@ -34,7 +40,15 @@
import com.power.common.util.EnumUtil;
import com.power.common.util.StringUtil;
import com.thoughtworks.qdox.JavaProjectBuilder;
-import com.thoughtworks.qdox.model.*;
+import com.thoughtworks.qdox.model.DocletTag;
+import com.thoughtworks.qdox.model.JavaAnnotation;
+import com.thoughtworks.qdox.model.JavaClass;
+import com.thoughtworks.qdox.model.JavaField;
+import com.thoughtworks.qdox.model.JavaGenericDeclaration;
+import com.thoughtworks.qdox.model.JavaMethod;
+import com.thoughtworks.qdox.model.JavaParameterizedType;
+import com.thoughtworks.qdox.model.JavaType;
+import com.thoughtworks.qdox.model.JavaTypeVariable;
import com.thoughtworks.qdox.model.expression.AnnotationValue;
import com.thoughtworks.qdox.model.expression.AnnotationValueList;
import com.thoughtworks.qdox.model.expression.Constant;
@@ -43,8 +57,22 @@
import com.thoughtworks.qdox.model.impl.DefaultJavaParameterizedType;
import org.apache.commons.lang3.StringUtils;
-import java.lang.reflect.*;
-import java.util.*;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -1323,11 +1351,13 @@ public static List getAnnotationValueClassNames(JavaAnnotation javaAnnot
* annotation. It handles both single string values and lists of string values. If the
* property is not found or has no valid string values, an empty list is returned.
*
+ * @param projectBuilder the project configuration builder
* @param javaAnnotation the annotation containing the property
* @param propertyName the name of the property to retrieve
* @return a list of string values or an empty list if not present
*/
- public static List getAnnotationValueStrings(JavaAnnotation javaAnnotation, String propertyName) {
+ public static List getAnnotationValueStrings(ProjectDocConfigBuilder projectBuilder,
+ JavaAnnotation javaAnnotation, String propertyName) {
AnnotationValue propertyValue = javaAnnotation.getProperty(propertyName);
if (propertyValue != null) {
if (propertyValue instanceof AnnotationValueList) {
@@ -1338,9 +1368,9 @@ public static List getAnnotationValueStrings(JavaAnnotation javaAnnotati
.filter(StringUtil::isNotEmpty)
.collect(Collectors.toList());
}
- if (propertyValue instanceof Constant) {
- return Collections.singletonList(((Constant) propertyValue).getValue().toString());
- }
+ String value = DocUtil.resolveAnnotationValue(projectBuilder.getApiConfig().getClassLoader(),
+ propertyValue);
+ return Collections.singletonList(value);
}
return Collections.emptyList();
}