3535
3636import java .lang .reflect .Field ;
3737import java .lang .reflect .Modifier ;
38+ import java .util .LinkedHashMap ;
3839import java .util .List ;
3940import java .util .Map ;
4041import java .util .Objects ;
42+ import java .util .StringJoiner ;
43+ import java .util .regex .Matcher ;
44+ import java .util .regex .Pattern ;
4145
4246/**
4347 * JavaFieldUtil
@@ -53,6 +57,11 @@ private JavaFieldUtil() {
5357 throw new IllegalStateException ("Utility class" );
5458 }
5559
60+ /**
61+ * Pattern to match placeholders in messages
62+ */
63+ private static final Pattern PLACEHOLDER_PATTERN = Pattern .compile ("\\ {(.+?)\\ }" );
64+
5665 /**
5766 * public static final
5867 */
@@ -141,47 +150,79 @@ public static String getParamMaxLength(ClassLoader classLoader, List<JavaAnnotat
141150 }
142151
143152 /**
144- * getJsr303Comment
145- * @param showValidation Show JSR validation information
146- * @param classLoader ClassLoader
147- * @param annotations annotations
148- * @return Jsr comments
153+ * Get JSR 303 validation comments.
154+ * @param showValidation Whether to show JSR validation information
155+ * @param classLoader The ClassLoader used to resolve annotation values
156+ * @param annotations List of Java annotations to process
157+ * @return A string containing JSR validation comments
149158 */
150159 public static String getJsrComment (boolean showValidation , ClassLoader classLoader ,
151160 List <JavaAnnotation > annotations ) {
152161 if (!showValidation ) {
153162 return DocGlobalConstants .EMPTY ;
154163 }
155- StringBuilder sb = new StringBuilder ( );
164+ StringJoiner validationJoiner = new StringJoiner ( "; " );
156165 for (JavaAnnotation annotation : annotations ) {
157- Map <String , AnnotationValue > values = annotation .getPropertyMap ();
158- String name = annotation .getType ().getValue ();
159- if (JSRAnnotationConstants .NOT_BLANK .equals (name ) || JSRAnnotationConstants .NOT_EMPTY .equals (name )
160- || JSRAnnotationConstants .NOT_NULL .equals (name ) || JSRAnnotationConstants .NULL .equals (name )
161- || JSRAnnotationConstants .VALIDATED .equals (name )) {
166+ String annotationName = annotation .getType ().getValue ();
167+ // Skip excluded annotations
168+ if (DocValidatorAnnotationEnum .EXCLUDED_ANNOTATIONS .contains (annotationName )) {
162169 continue ;
163170 }
164- if (DocValidatorAnnotationEnum .listValidatorAnnotations ().contains (name )) {
165- sb .append (name ).append ("(" );
166- int j = 0 ;
167- for (Map .Entry <String , AnnotationValue > m : values .entrySet ()) {
168- j ++;
169- String value = DocUtil .resolveAnnotationValue (classLoader , m .getValue ());
170- sb .append (m .getKey ()).append ("=" ).append (StringUtil .removeDoubleQuotes (value ));
171- if (j < values .size ()) {
172- sb .append (", " );
173- }
174- }
175- sb .append ("); " );
171+
172+ // Skip non-validator annotations
173+ if (!DocValidatorAnnotationEnum .VALIDATOR_ANNOTATIONS .contains (annotationName )) {
174+ continue ;
176175 }
176+
177+ StringJoiner paramJoiner = getParamJoiner (classLoader , annotation );
178+
179+ validationJoiner .add (annotationName + "(" + paramJoiner + ")" );
180+
177181 }
178- if (sb .length () < 1 ) {
179- return DocGlobalConstants .EMPTY ;
182+ return validationJoiner .length () == 0 ? DocGlobalConstants .EMPTY : "\n Validation[" + validationJoiner + "]" ;
183+ }
184+
185+ /**
186+ * Get the string joiner for the given annotation.
187+ * @param classLoader The ClassLoader used to resolve annotation values
188+ * @param annotation The Java annotation to process
189+ * @return A string joiner containing the resolved annotation properties
190+ */
191+ private static StringJoiner getParamJoiner (ClassLoader classLoader , JavaAnnotation annotation ) {
192+ Map <String , AnnotationValue > properties = annotation .getPropertyMap ();
193+ Map <String , String > resolvedValues = new LinkedHashMap <>();
194+ properties .forEach ((key , value ) -> resolvedValues .put (key ,
195+ StringUtil .removeDoubleQuotes (DocUtil .resolveAnnotationValue (classLoader , value ))));
196+
197+ resolvedValues .computeIfPresent ("message" , (k , v ) -> replacePlaceholders (v , resolvedValues ));
198+
199+ StringJoiner paramJoiner = new StringJoiner (", " );
200+ resolvedValues .forEach ((key , val ) -> paramJoiner .add (key + "=" + val ));
201+ return paramJoiner ;
202+ }
203+
204+ /**
205+ * Replace placeholders in the message with corresponding annotation property values.
206+ * @param message The original message content
207+ * @param resolvedValues A map of resolved annotation property values
208+ * @return The message with placeholders replaced
209+ */
210+ private static String replacePlaceholders (String message , Map <String , String > resolvedValues ) {
211+ // Early exit if the message is null, empty, or does not contain any placeholders
212+ if (message == null || !message .contains ("{" ) || !message .contains ("}" )) {
213+ return message ;
180214 }
181- if (sb .toString ().contains (";" )) {
182- sb .deleteCharAt (sb .lastIndexOf (";" ));
215+
216+ Matcher matcher = PLACEHOLDER_PATTERN .matcher (message );
217+ StringBuffer sb = new StringBuffer ();
218+ while (matcher .find ()) {
219+ String key = matcher .group (1 );
220+ String replacement = resolvedValues .getOrDefault (key , matcher .group ());
221+ matcher .appendReplacement (sb , Matcher .quoteReplacement (replacement ));
183222 }
184- return "\n Validation[" + sb + "]" ;
223+ matcher .appendTail (sb );
224+ return sb .toString ();
225+
185226 }
186227
187228 /**
0 commit comments