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

fix: 🐛 resolve incorrect parsing of constants in @JsonProperty and @JSONField annotation #935

Merged
merged 1 commit into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/main/java/com/ly/doc/handler/IWebSocketRequestHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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;
}
Expand All @@ -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<String> subProtocols = JavaClassUtil.getAnnotationValueStrings(projectBuilder, javaAnnotation,
"subprotocols");
builder.setSubProtocols(subProtocols);

// Handle 'decoders' property
builder.setDecoders(JavaClassUtil.getAnnotationValueClassNames(javaAnnotation, "decoders"));
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/com/ly/doc/helper/BaseHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,18 +176,20 @@ 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);
}
}

// Handle @JsonProperty
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) {
Expand Down
21 changes: 18 additions & 3 deletions src/main/java/com/ly/doc/template/IWebSocketTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
100 changes: 79 additions & 21 deletions src/main/java/com/ly/doc/utils/DocUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,78 @@
*/
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;
import org.apache.commons.codec.digest.DigestUtils;
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;
Expand Down Expand Up @@ -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);

}

/**
Expand Down
46 changes: 38 additions & 8 deletions src/main/java/com/ly/doc/utils/JavaClassUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -1323,11 +1351,13 @@ public static List<String> 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.
* </p>
* @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<String> getAnnotationValueStrings(JavaAnnotation javaAnnotation, String propertyName) {
public static List<String> getAnnotationValueStrings(ProjectDocConfigBuilder projectBuilder,
JavaAnnotation javaAnnotation, String propertyName) {
AnnotationValue propertyValue = javaAnnotation.getProperty(propertyName);
if (propertyValue != null) {
if (propertyValue instanceof AnnotationValueList) {
Expand All @@ -1338,9 +1368,9 @@ public static List<String> 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();
}
Expand Down