@@ -1754,6 +1754,8 @@ protected boolean applyBeanValidatorAnnotations(Schema property, Annotation[] an
17541754 return modified ;
17551755 }
17561756 }
1757+ // expand composed constraint meta-annotations (e.g., @Min/@Max on custom annotations)
1758+ annotations = expandValidationMetaAnnotations (annotations );
17571759 Map <String , Annotation > annos = new HashMap <>();
17581760 if (annotations != null ) {
17591761 for (Annotation anno : annotations ) {
@@ -1946,6 +1948,8 @@ protected boolean checkGroupValidation(Class[] groups, Set<Class> invocationGrou
19461948 }
19471949
19481950 protected boolean applyBeanValidatorAnnotationsNoGroups (Schema property , Annotation [] annotations , Schema parent , boolean applyNotNullAnnotations ) {
1951+ // expand composed constraint meta-annotations (e.g., @Min/@Max on custom annotations)
1952+ annotations = expandValidationMetaAnnotations (annotations );
19491953 Map <String , Annotation > annos = new HashMap <>();
19501954 boolean modified = false ;
19511955 if (annotations != null ) {
@@ -2049,6 +2053,42 @@ protected boolean applyBeanValidatorAnnotationsNoGroups(Schema property, Annotat
20492053 return modified ;
20502054 }
20512055
2056+ /**
2057+ * Expands provided annotations to include bean-validation constraint annotations present as meta-annotations
2058+ * on custom annotations (i.e., composed constraints like a custom @ValidStoreId annotated with @Min/@Max).
2059+ * Only javax.validation.constraints annotations are added to avoid unrelated meta-annotations.
2060+ */
2061+ private Annotation [] expandValidationMetaAnnotations (Annotation [] annotations ) {
2062+ if (annotations == null || annotations .length == 0 ) {
2063+ return annotations ;
2064+ }
2065+ Map <String , Annotation > merged = new LinkedHashMap <>();
2066+ for (Annotation a : annotations ) {
2067+ if (a != null ) {
2068+ merged .put (a .annotationType ().getName (), a );
2069+ }
2070+ }
2071+ try {
2072+ for (Annotation a : annotations ) {
2073+ if (a == null ) continue ;
2074+ Annotation [] metas = a .annotationType ().getAnnotations ();
2075+ if (metas == null ) continue ;
2076+ for (Annotation meta : metas ) {
2077+ if (meta == null ) continue ;
2078+ String name = meta .annotationType ().getName ();
2079+ // include only standard bean validation constraint annotations
2080+ if (name != null && name .startsWith ("javax.validation.constraints" )) {
2081+ merged .putIfAbsent (name , meta );
2082+ }
2083+ }
2084+ }
2085+ } catch (Throwable t ) {
2086+ // be conservative: if anything goes wrong, fall back to original annotations
2087+ return annotations ;
2088+ }
2089+ return merged .values ().toArray (new Annotation [0 ]);
2090+ }
2091+
20522092 private boolean resolveSubtypes (Schema model , BeanDescription bean , ModelConverterContext context , JsonView jsonViewAnnotation ) {
20532093 final List <NamedType > types = _intr ().findSubtypes (bean .getClassInfo ());
20542094 if (types == null ) {
0 commit comments