Skip to content
This repository was archived by the owner on Dec 4, 2025. It is now read-only.
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
28 changes: 21 additions & 7 deletions src/main/java/com/ly/doc/constants/DocValidatorAnnotationEnum.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2024 smart-doc
* Copyright (C) 2018-2025 smart-doc
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
Expand All @@ -20,8 +20,8 @@
*/
package com.ly.doc.constants;

import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;

/**
* spring validator annotations
Expand Down Expand Up @@ -164,12 +164,26 @@ public enum DocValidatorAnnotationEnum {
this.value = value;
}

public static List<String> listValidatorAnnotations() {
List<String> annotations = new ArrayList<>();
/**
* validator annotations
*/
public static final Set<String> VALIDATOR_ANNOTATIONS = new HashSet<>();

/**
* excluded annotations
*/
public static final Set<String> EXCLUDED_ANNOTATIONS = new HashSet<>();

static {
for (DocValidatorAnnotationEnum annotation : DocValidatorAnnotationEnum.values()) {
annotations.add(annotation.value);
VALIDATOR_ANNOTATIONS.add(annotation.value);
}
return annotations;

EXCLUDED_ANNOTATIONS.add(NOT_BLANK.value);
EXCLUDED_ANNOTATIONS.add(NOT_EMPTY.value);
EXCLUDED_ANNOTATIONS.add(NOT_NULL.value);
EXCLUDED_ANNOTATIONS.add(NULL.value);
EXCLUDED_ANNOTATIONS.add(VALIDATED.value);
}

}
29 changes: 23 additions & 6 deletions src/main/java/com/ly/doc/utils/JavaClassUtil.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* smart-doc
*
* Copyright (C) 2018-2024 smart-doc
* Copyright (C) 2018-2025 smart-doc
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
Expand Down Expand Up @@ -872,9 +872,8 @@ public static Set<String> getParamGroupJavaClass(List<JavaAnnotation> annotation
return new HashSet<>(0);
}
Set<String> javaClassList = new HashSet<>();
List<String> validates = DocValidatorAnnotationEnum.listValidatorAnnotations();
for (JavaAnnotation javaAnnotation : annotations) {
List<AnnotationValue> annotationValueList = getValidatedAnnotationValues(validates, javaAnnotation);
List<AnnotationValue> annotationValueList = getValidatedAnnotationValues(javaAnnotation);
addGroupClass(annotationValueList, javaClassList, builder);
// When using @Validated and group class is empty, add the Default group
// class;
Expand All @@ -899,8 +898,7 @@ public static Set<String> getParamGroupJavaClass(JavaAnnotation javaAnnotation)
return new HashSet<>(0);
}
Set<String> javaClassList = new HashSet<>();
List<String> validates = DocValidatorAnnotationEnum.listValidatorAnnotations();
List<AnnotationValue> annotationValueList = getValidatedAnnotationValues(validates, javaAnnotation);
List<AnnotationValue> annotationValueList = getValidatedAnnotationValues(javaAnnotation);
addGroupClass(annotationValueList, javaClassList);
String simpleAnnotationName = javaAnnotation.getType().getValue();
// add default group
Expand Down Expand Up @@ -1047,7 +1045,7 @@ private static void recursionGetAllValidInterface(JavaClass classByName, Set<Str
* annotation values. If the property name cannot be determined or the annotation does
* not contain valid validation information, an empty list is returned.
*/
private static List<AnnotationValue> getValidatedAnnotationValues(List<String> validates,
private static List<AnnotationValue> getValidatedAnnotationValues(Set<String> validates,
JavaAnnotation javaAnnotation) {
String simpleName = javaAnnotation.getType().getValue();

Expand All @@ -1068,6 +1066,25 @@ else if (validates.contains(simpleName)) {
return Collections.emptyList();
}

/**
* Retrieves a list of validated annotation values.
* <p>
* This method processes and extracts validation-related information from a given
* annotation object, based on the list of validation annotation names provided. It
* first determines the annotation type, then identifies the property name to extract
* based on the annotation type, and finally retrieves the corresponding annotation
* values according to that property name.
* </p>
* @param javaAnnotation A JavaAnnotation object representing the annotation being
* processed.
* @return Returns a list of AnnotationValue objects containing valid validation
* annotation values. If the property name cannot be determined or the annotation does
* not contain valid validation information, an empty list is returned.
*/
private static List<AnnotationValue> getValidatedAnnotationValues(JavaAnnotation javaAnnotation) {
return getValidatedAnnotationValues(DocValidatorAnnotationEnum.VALIDATOR_ANNOTATIONS, javaAnnotation);
}

/**
* Generic parameter map.
* @param genericMap generic map
Expand Down
97 changes: 69 additions & 28 deletions src/main/java/com/ly/doc/utils/JavaFieldUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* JavaFieldUtil
Expand All @@ -53,6 +57,11 @@ private JavaFieldUtil() {
throw new IllegalStateException("Utility class");
}

/**
* Pattern to match placeholders in messages
*/
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{(.+?)\\}");

/**
* public static final
*/
Expand Down Expand Up @@ -141,47 +150,79 @@ public static String getParamMaxLength(ClassLoader classLoader, List<JavaAnnotat
}

/**
* getJsr303Comment
* @param showValidation Show JSR validation information
* @param classLoader ClassLoader
* @param annotations annotations
* @return Jsr comments
* Get JSR 303 validation comments.
* @param showValidation Whether to show JSR validation information
* @param classLoader The ClassLoader used to resolve annotation values
* @param annotations List of Java annotations to process
* @return A string containing JSR validation comments
*/
public static String getJsrComment(boolean showValidation, ClassLoader classLoader,
List<JavaAnnotation> annotations) {
if (!showValidation) {
return DocGlobalConstants.EMPTY;
}
StringBuilder sb = new StringBuilder();
StringJoiner validationJoiner = new StringJoiner("; ");
for (JavaAnnotation annotation : annotations) {
Map<String, AnnotationValue> values = annotation.getPropertyMap();
String name = annotation.getType().getValue();
if (JSRAnnotationConstants.NOT_BLANK.equals(name) || JSRAnnotationConstants.NOT_EMPTY.equals(name)
|| JSRAnnotationConstants.NOT_NULL.equals(name) || JSRAnnotationConstants.NULL.equals(name)
|| JSRAnnotationConstants.VALIDATED.equals(name)) {
String annotationName = annotation.getType().getValue();
// Skip excluded annotations
if (DocValidatorAnnotationEnum.EXCLUDED_ANNOTATIONS.contains(annotationName)) {
continue;
}
if (DocValidatorAnnotationEnum.listValidatorAnnotations().contains(name)) {
sb.append(name).append("(");
int j = 0;
for (Map.Entry<String, AnnotationValue> m : values.entrySet()) {
j++;
String value = DocUtil.resolveAnnotationValue(classLoader, m.getValue());
sb.append(m.getKey()).append("=").append(StringUtil.removeDoubleQuotes(value));
if (j < values.size()) {
sb.append(", ");
}
}
sb.append("); ");

// Skip non-validator annotations
if (!DocValidatorAnnotationEnum.VALIDATOR_ANNOTATIONS.contains(annotationName)) {
continue;
}

StringJoiner paramJoiner = getParamJoiner(classLoader, annotation);

validationJoiner.add(annotationName + "(" + paramJoiner + ")");

}
if (sb.length() < 1) {
return DocGlobalConstants.EMPTY;
return validationJoiner.length() == 0 ? DocGlobalConstants.EMPTY : "\nValidation[" + validationJoiner + "]";
}

/**
* Get the string joiner for the given annotation.
* @param classLoader The ClassLoader used to resolve annotation values
* @param annotation The Java annotation to process
* @return A string joiner containing the resolved annotation properties
*/
private static StringJoiner getParamJoiner(ClassLoader classLoader, JavaAnnotation annotation) {
Map<String, AnnotationValue> properties = annotation.getPropertyMap();
Map<String, String> resolvedValues = new LinkedHashMap<>();
properties.forEach((key, value) -> resolvedValues.put(key,
StringUtil.removeDoubleQuotes(DocUtil.resolveAnnotationValue(classLoader, value))));

resolvedValues.computeIfPresent("message", (k, v) -> replacePlaceholders(v, resolvedValues));

StringJoiner paramJoiner = new StringJoiner(", ");
resolvedValues.forEach((key, val) -> paramJoiner.add(key + "=" + val));
return paramJoiner;
}

/**
* Replace placeholders in the message with corresponding annotation property values.
* @param message The original message content
* @param resolvedValues A map of resolved annotation property values
* @return The message with placeholders replaced
*/
private static String replacePlaceholders(String message, Map<String, String> resolvedValues) {
// Early exit if the message is null, empty, or does not contain any placeholders
if (message == null || !message.contains("{") || !message.contains("}")) {
return message;
}
if (sb.toString().contains(";")) {
sb.deleteCharAt(sb.lastIndexOf(";"));

Matcher matcher = PLACEHOLDER_PATTERN.matcher(message);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String key = matcher.group(1);
String replacement = resolvedValues.getOrDefault(key, matcher.group());
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
}
return "\nValidation[" + sb + "]";
matcher.appendTail(sb);
return sb.toString();

}

/**
Expand Down