You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bval.apache.org by ta...@apache.org on 2026/04/23 20:54:58 UTC

(bval) branch master updated (ff4e282 -> ae05de3)

This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/bval.git


    from ff4e282  Merge pull request #211 from apache/dependabot/maven/org.apache.maven.plugins-maven-source-plugin-3.4.0
     new bfd9cb2  [perf] improve ConstraintValidator init
     new f97ff39  Update hibernate-validator
     new 3b3bc37  [perf] dont use concurrent if not required
     new cf47e8c  [perf] cache default validator
     new 4d8a301  [perf] Ccheckoint: Cheaper unconstrained-bean path, Less stream work in the bean/property walk
     new ae05de3  [perf] Ccheckoint: Reduce streams

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/bval/jsr/ApacheFactoryContext.java  |  29 ++-
 .../apache/bval/jsr/ApacheValidatorFactory.java    |  30 ++-
 .../java/org/apache/bval/jsr/descriptor/BeanD.java |  12 +-
 .../org/apache/bval/jsr/descriptor/ComposedD.java  |  15 ++
 .../bval/jsr/descriptor/DescriptorManager.java     |  15 +-
 .../java/org/apache/bval/jsr/job/ValidateBean.java |  10 +-
 .../org/apache/bval/jsr/job/ValidationJob.java     | 224 ++++++++++++---------
 bval-perf/pom.xml                                  |   4 +-
 8 files changed, 219 insertions(+), 120 deletions(-)


(bval) 04/06: [perf] cache default validator

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bval.git

commit cf47e8c3ae8641a30027fd4cd201e06206bbf3a1
Author: tandraschko <ta...@apache.org>
AuthorDate: Thu Apr 23 14:03:32 2026 +0200

    [perf] cache default validator
---
 .../apache/bval/jsr/ApacheValidatorFactory.java    | 30 ++++++++++++++++++----
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
index a7b6188..8fa5785 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
@@ -112,6 +112,13 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
     private ParameterNameProvider parameterNameProvider;
     private ClockProvider clockProvider;
 
+    /**
+     * Lazily created default validator for {@link #getValidator()} (factory default settings, no
+     * {@link #usingContext()} customization). Safe to use concurrently; {@link Validator} is thread-safe.
+     * Not copied on {@link #clone()}; the clone gets its own instance on first use.
+     */
+    private volatile Validator defaultValidator;
+
     /**
      * Create a new ApacheValidatorFactory instance.
      */
@@ -152,13 +159,24 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
     }
 
     /**
-     * Shortcut method to create a new Validator instance with factory's settings
-     *
-     * @return the new validator instance
+     * Return a {@link Validator} for this factory's default settings (as if from {@link #usingContext()} with no
+     * customization). The same instance may be returned on every call, which is allowed by the specification and
+     * avoids allocating a new {@link ApacheFactoryContext} and {@link Validator} each time. Use
+     * {@code usingContext()....getValidator()} when a distinct {@link Validator} with customized context is required.
      */
     @Override
     public Validator getValidator() {
-        return usingContext().getValidator();
+        Validator v = defaultValidator;
+        if (v == null) {
+            synchronized (this) {
+                v = defaultValidator;
+                if (v == null) {
+                    v = new ApacheFactoryContext(this).getValidator();
+                    defaultValidator = v;
+                }
+            }
+        }
+        return v;
     }
 
     /**
@@ -177,7 +195,9 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
     @Override
     public synchronized ApacheValidatorFactory clone() {
         try {
-            return (ApacheValidatorFactory) super.clone();
+            final ApacheValidatorFactory copy = (ApacheValidatorFactory) super.clone();
+            copy.defaultValidator = null;
+            return copy;
         } catch (CloneNotSupportedException e) {
             throw new InternalError(); // VM bug.
         }


(bval) 03/06: [perf] dont use concurrent if not required

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bval.git

commit 3b3bc37ea0ed9eb7c459826038168b681740148a
Author: tandraschko <ta...@apache.org>
AuthorDate: Thu Apr 23 13:18:14 2026 +0200

    [perf] dont use concurrent if not required
---
 .../org/apache/bval/jsr/job/ValidationJob.java     | 146 ++++++++++-----------
 1 file changed, 73 insertions(+), 73 deletions(-)

diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
index d5d6588..6dc8e6c 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
@@ -22,15 +22,14 @@ import java.lang.reflect.Array;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.TreeMap;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -105,7 +104,7 @@ public abstract class ValidationJob<T> {
             Validate.notNull(sink, "sink");
 
             GroupStrategy.redefining(groups, Collections.singletonMap(Group.DEFAULT, descriptor.getGroupStrategy()))
-                .applyTo(noViolations(gs -> validateDescriptorConstraints(gs, sink)));
+                    .applyTo(noViolations(gs -> validateDescriptorConstraints(gs, sink)));
 
             recurse(groups, sink);
         }
@@ -118,20 +117,20 @@ public abstract class ValidationJob<T> {
 
         void validateDescriptorConstraints(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
             constraintsFor(descriptor, groups)
-                .forEach(c -> unwrap(c.getValueUnwrapping()).forEach(f -> f.validate(c, sink)));
+                    .forEach(c -> unwrap(c.getValueUnwrapping()).forEach(f -> f.validate(c, sink)));
         }
 
         private Stream<Frame<D>> unwrap(ValidateUnwrappedValue valueUnwrapping) {
             if (valueUnwrapping != ValidateUnwrappedValue.SKIP && context.getValue() != null) {
                 final Optional<ValueExtractors.UnwrappingInfo> valueExtractorAndAssociatedContainerElementKey =
-                    validatorContext.getValueExtractors().findUnwrappingInfo(context.getValue().getClass(),
-                        valueUnwrapping);
+                        validatorContext.getValueExtractors().findUnwrappingInfo(context.getValue().getClass(),
+                                valueUnwrapping);
 
                 if (valueExtractorAndAssociatedContainerElementKey.isPresent()) {
                     return ExtractValues
-                        .extract(context, valueExtractorAndAssociatedContainerElementKey.get().containerElementKey,
-                            valueExtractorAndAssociatedContainerElementKey.get().valueExtractor)
-                        .stream().map(child -> new UnwrappedElementConstraintValidationPseudoFrame<>(this, child));
+                            .extract(context, valueExtractorAndAssociatedContainerElementKey.get().containerElementKey,
+                                    valueExtractorAndAssociatedContainerElementKey.get().valueExtractor)
+                            .stream().map(child -> new UnwrappedElementConstraintValidationPseudoFrame<>(this, child));
                 }
             }
             return Stream.of(this);
@@ -139,16 +138,17 @@ public abstract class ValidationJob<T> {
 
         @SuppressWarnings({ "rawtypes", "unchecked" })
         private boolean validate(ConstraintD<?> constraint, Consumer<ConstraintViolation<T>> sink) {
-            final ConcurrentMap<Path, Set<Object>> pathMap = completedValidations.computeIfAbsent(constraint,
-                k -> new ConcurrentSkipListMap<>(PathImpl.PATH_COMPARATOR));
+            // Use the same path ordering/equality as before (ConcurrentSkipListMap): comparator-based, not Path#equals.
+            final Map<Path, Set<Object>> pathMap = completedValidations.computeIfAbsent(constraint,
+                    k -> new TreeMap<>(PathImpl.PATH_COMPARATOR));
             final Set<Object> objectSet =
-                pathMap.computeIfAbsent(context.getPath(), p -> Collections.newSetFromMap(new IdentityHashMap<>()));
+                    pathMap.computeIfAbsent(context.getPath(), p -> Collections.newSetFromMap(new IdentityHashMap<>()));
             if (!objectSet.add(context.getValue())) {
                 return true;
             }
             final ConstraintValidator constraintValidator = getConstraintValidator(constraint);
             final ConstraintValidatorContextImpl<T> constraintValidatorContext =
-                new ConstraintValidatorContextImpl<>(this, constraint);
+                    new ConstraintValidatorContextImpl<>(this, constraint);
 
             final boolean valid;
             if (constraintValidator == null) {
@@ -156,7 +156,6 @@ public abstract class ValidationJob<T> {
                 valid = true;
             } else {
                 try {
-                    constraintValidator.initialize(constraint.getAnnotation());
                     valid = constraintValidator.isValid(context.getValue(), constraintValidatorContext);
                 } catch (ValidationException e) {
                     throw e;
@@ -189,7 +188,7 @@ public abstract class ValidationJob<T> {
 
             // collect validation results to set of Boolean, ensuring all are evaluated:
             final Set<Boolean> validationResults = constraint.getComposingConstraints().stream().map(ConstraintD.class::cast)
-                .map(c -> validate(c, effectiveSink)).collect(Collectors.toSet());
+                    .map(c -> validate(c, effectiveSink)).collect(Collectors.toSet());
 
             return Collections.singleton(Boolean.TRUE).equals(validationResults);
         }
@@ -231,8 +230,8 @@ public abstract class ValidationJob<T> {
             final Class<?> elementClass = descriptor.getElementClass();
 
             final Optional<Class<?>> extractedType =
-                validatorContext.getValueExtractors().findUnwrappingInfo(elementClass, constraint.getValueUnwrapping())
-                    .map(info -> ValueExtractors.getExtractedType(info.valueExtractor, elementClass));
+                    validatorContext.getValueExtractors().findUnwrappingInfo(elementClass, constraint.getValueUnwrapping())
+                            .map(info -> ValueExtractors.getExtractedType(info.valueExtractor, elementClass));
 
             return extractedType.orElse(elementClass);
         }
@@ -247,7 +246,7 @@ public abstract class ValidationJob<T> {
 
         BeanFrame(Frame<?> parent, GraphContext context) {
             super(parent, getBeanDescriptor(context.getValue()),
-                context.child(context.getPath().addBean(), context.getValue()));
+                    context.child(context.getPath().addBean(), context.getValue()));
             this.realContext = context;
         }
 
@@ -257,7 +256,7 @@ public abstract class ValidationJob<T> {
             final Lazy<Set<Frame<?>>> propertyFrames = new Lazy<>(this::propertyFrames);
 
             final GroupStrategy localGroupStrategy = GroupStrategy.redefining(groups,
-                Collections.singletonMap(Group.DEFAULT, descriptor.getGroupStrategy()));
+                    Collections.singletonMap(Group.DEFAULT, descriptor.getGroupStrategy()));
 
             localGroupStrategy.applyTo(noViolations(gs -> {
                 validateDescriptorConstraints(gs, sink);
@@ -284,7 +283,7 @@ public abstract class ValidationJob<T> {
 
         private Set<Frame<?>> propertyFrames() {
             final Stream<PropertyD<?>> properties = descriptor.getConstrainedProperties().stream()
-                .flatMap(d -> ComposedD.unwrap(d, PropertyD.class)).map(d -> (PropertyD<?>) d);
+                    .flatMap(d -> ComposedD.unwrap(d, PropertyD.class)).map(d -> (PropertyD<?>) d);
 
             final TraversableResolver traversableResolver = validatorContext.getTraversableResolver();
 
@@ -293,7 +292,7 @@ public abstract class ValidationJob<T> {
                 p.addProperty(d.getPropertyName());
                 try {
                     return traversableResolver.isReachable(context.getValue(), p.removeLeafNode(), getRootBeanClass(),
-                        p, d.getElementType());
+                            p, d.getElementType());
                 } catch (ValidationException ve) {
                     throw ve;
                 } catch (Exception e) {
@@ -301,7 +300,7 @@ public abstract class ValidationJob<T> {
                 }
             });
             return reachableProperties.flatMap(d -> d.read(realContext).filter(context -> !context.isRecursive())
-                .map(child -> propertyFrame(d, child))).collect(Collectors.toSet());
+                    .map(child -> propertyFrame(d, child))).collect(Collectors.toSet());
         }
     }
 
@@ -320,17 +319,17 @@ public abstract class ValidationJob<T> {
             super.validateDescriptorConstraints(groups, sink);
             if (context.getValue() != null) {
                 descriptor.getConstrainedContainerElementTypes().stream()
-                    .flatMap(d -> ComposedD.unwrap(d, ContainerElementTypeD.class)).forEach(d -> {
-                        if (constraintsFor(d, groups).findFirst().isPresent()
-                            || !d.getConstrainedContainerElementTypes().isEmpty()) {
-                            final ValueExtractor<?> declaredTypeValueExtractor =
-                                context.getValidatorContext().getValueExtractors().find(d.getKey());
-                            ExtractValues.extract(context, d.getKey(), declaredTypeValueExtractor).stream()
-                                .filter(e -> !e.isRecursive())
-                                .map(e -> new ContainerElementConstraintsFrame(this, d, e))
-                                .forEach(f -> f.validateDescriptorConstraints(groups, sink));
-                        }
-                    });
+                        .flatMap(d -> ComposedD.unwrap(d, ContainerElementTypeD.class)).forEach(d -> {
+                            if (constraintsFor(d, groups).findFirst().isPresent()
+                                    || !d.getConstrainedContainerElementTypes().isEmpty()) {
+                                final ValueExtractor<?> declaredTypeValueExtractor =
+                                        context.getValidatorContext().getValueExtractors().find(d.getKey());
+                                ExtractValues.extract(context, d.getKey(), declaredTypeValueExtractor).stream()
+                                        .filter(e -> !e.isRecursive())
+                                        .map(e -> new ContainerElementConstraintsFrame(this, d, e))
+                                        .forEach(f -> f.validateDescriptorConstraints(groups, sink));
+                            }
+                        });
             }
         }
 
@@ -340,22 +339,22 @@ public abstract class ValidationJob<T> {
                 return;
             }
             final Map<Group, GroupStrategy> conversions =
-                descriptor.getGroupConversions().stream().collect(Collectors.toMap(gc -> Group.of(gc.getFrom()),
-                    gc -> validatorContext.getGroupsComputer().computeGroups(gc.getTo()).asStrategy()));
+                    descriptor.getGroupConversions().stream().collect(Collectors.toMap(gc -> Group.of(gc.getFrom()),
+                            gc -> validatorContext.getGroupsComputer().computeGroups(gc.getTo()).asStrategy()));
 
             GroupStrategy.redefining(groups, conversions).applyTo(noViolations(gs -> cascade(gs, sink)));
         }
 
         private void cascade(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
             descriptor.getConstrainedContainerElementTypes().stream()
-                .filter(d -> d.isCascaded() || !d.getConstrainedContainerElementTypes().isEmpty())
-                .flatMap(d -> ComposedD.unwrap(d, ContainerElementTypeD.class)).forEach(d -> {
-                    final ValueExtractor<?> runtimeTypeValueExtractor =
-                        context.getValidatorContext().getValueExtractors().find(context.runtimeKey(d.getKey()));
-                    ExtractValues.extract(context, d.getKey(), runtimeTypeValueExtractor).stream()
-                        .filter(e -> !e.isRecursive()).map(e -> new ContainerElementCascadeFrame(this, d, e))
-                        .forEach(f -> f.recurse(groups, sink));
-                });
+                    .filter(d -> d.isCascaded() || !d.getConstrainedContainerElementTypes().isEmpty())
+                    .flatMap(d -> ComposedD.unwrap(d, ContainerElementTypeD.class)).forEach(d -> {
+                        final ValueExtractor<?> runtimeTypeValueExtractor =
+                                context.getValidatorContext().getValueExtractors().find(context.runtimeKey(d.getKey()));
+                        ExtractValues.extract(context, d.getKey(), runtimeTypeValueExtractor).stream()
+                                .filter(e -> !e.isRecursive()).map(e -> new ContainerElementCascadeFrame(this, d, e))
+                                .forEach(f -> f.recurse(groups, sink));
+                    });
             if (!descriptor.isCascaded()) {
                 return;
             }
@@ -363,14 +362,14 @@ public abstract class ValidationJob<T> {
                 final TraversableResolver traversableResolver = validatorContext.getTraversableResolver();
 
                 final Object traversableObject =
-                    Optional.ofNullable(context.getParent()).map(GraphContext::getValue).orElse(null);
+                        Optional.ofNullable(context.getParent()).map(GraphContext::getValue).orElse(null);
 
                 final PathImpl pathToTraversableObject = context.getPath();
                 final NodeImpl traversableProperty = pathToTraversableObject.removeLeafNode();
 
                 try {
                     if (!traversableResolver.isCascadable(traversableObject, traversableProperty, getRootBeanClass(),
-                        pathToTraversableObject, ((PropertyD<?>) descriptor).getElementType())) {
+                            pathToTraversableObject, ((PropertyD<?>) descriptor).getElementType())) {
                         return;
                     }
                 } catch (ValidationException ve) {
@@ -380,7 +379,7 @@ public abstract class ValidationJob<T> {
                 }
             }
             multiplex().filter(context -> context.getValue() != null && !context.isRecursive())
-                .map(context -> new BeanFrame<>(this, context)).forEach(b -> b.process(groups, sink));
+                    .map(context -> new BeanFrame<>(this, context)).forEach(b -> b.process(groups, sink));
         }
 
         protected GraphContext getMultiplexContext() {
@@ -397,28 +396,28 @@ public abstract class ValidationJob<T> {
                 // inconsistent: use Object[] here but specific type for Iterable? RI compatibility
                 final Class<?> arrayType = value instanceof Object[] ? Object[].class : value.getClass();
                 return IntStream.range(0, Array.getLength(value)).mapToObj(
-                    i -> multiplexContext.child(NodeImpl.atIndex(i).inContainer(arrayType, null), Array.get(value, i)));
+                        i -> multiplexContext.child(NodeImpl.atIndex(i).inContainer(arrayType, null), Array.get(value, i)));
             }
             if (Map.class.isInstance(value)) {
                 return ((Map<?, ?>) value).entrySet().stream()
-                    .map(e -> multiplexContext.child(
-                        setContainerInformation(NodeImpl.atKey(e.getKey()), MAP_VALUE, descriptor.getElementClass()),
-                        e.getValue()));
+                        .map(e -> multiplexContext.child(
+                                setContainerInformation(NodeImpl.atKey(e.getKey()), MAP_VALUE, descriptor.getElementClass()),
+                                e.getValue()));
             }
             if (List.class.isInstance(value)) {
                 final List<?> l = (List<?>) value;
                 return IntStream.range(0, l.size())
-                    .mapToObj(i -> multiplexContext.child(
-                        setContainerInformation(NodeImpl.atIndex(i), ITERABLE_ELEMENT, descriptor.getElementClass()),
-                        l.get(i)));
+                        .mapToObj(i -> multiplexContext.child(
+                                setContainerInformation(NodeImpl.atIndex(i), ITERABLE_ELEMENT, descriptor.getElementClass()),
+                                l.get(i)));
             }
             if (Iterable.class.isInstance(value)) {
                 final Stream.Builder<Object> b = Stream.builder();
                 ((Iterable<?>) value).forEach(b);
                 return b.build()
-                    .map(o -> multiplexContext.child(
-                        setContainerInformation(NodeImpl.atIndex(null), ITERABLE_ELEMENT, descriptor.getElementClass()),
-                        o));
+                        .map(o -> multiplexContext.child(
+                                setContainerInformation(NodeImpl.atIndex(null), ITERABLE_ELEMENT, descriptor.getElementClass()),
+                                o));
             }
             return Stream.of(multiplexContext);
         }
@@ -426,14 +425,14 @@ public abstract class ValidationJob<T> {
         // RI apparently wants to use e.g. Set for Iterable containers, so use declared type + assigned type
         // variable if present. not sure I agree, FWIW
         private NodeImpl setContainerInformation(NodeImpl node, TypeVariable<?> originalTypeVariable,
-            Class<?> containerType) {
+                                                 Class<?> containerType) {
             final TypeVariable<?> tv;
             if (containerType.equals(originalTypeVariable.getGenericDeclaration())) {
                 tv = originalTypeVariable;
             } else {
                 final Type assignedType =
-                    TypeUtils.getTypeArguments(containerType, (Class<?>) originalTypeVariable.getGenericDeclaration())
-                        .get(originalTypeVariable);
+                        TypeUtils.getTypeArguments(containerType, (Class<?>) originalTypeVariable.getGenericDeclaration())
+                                .get(originalTypeVariable);
 
                 tv = assignedType instanceof TypeVariable<?> ? (TypeVariable<?>) assignedType : null;
             }
@@ -450,7 +449,7 @@ public abstract class ValidationJob<T> {
     private class ContainerElementConstraintsFrame extends SproutFrame<ContainerElementTypeD> {
 
         ContainerElementConstraintsFrame(ValidationJob<T>.Frame<?> parent, ContainerElementTypeD descriptor,
-            GraphContext context) {
+                                         GraphContext context) {
             super(parent, descriptor, context);
         }
 
@@ -462,7 +461,7 @@ public abstract class ValidationJob<T> {
     private class ContainerElementCascadeFrame extends SproutFrame<ContainerElementTypeD> {
 
         ContainerElementCascadeFrame(ValidationJob<T>.Frame<?> parent, ContainerElementTypeD descriptor,
-            GraphContext context) {
+                                     GraphContext context) {
             super(parent, descriptor, context);
         }
 
@@ -494,7 +493,7 @@ public abstract class ValidationJob<T> {
             } else {
                 final ContainerElementKey key = descriptor.getKey();
                 newLeaf = new NodeImpl.PropertyNodeImpl((String) null).inContainer(key.getContainerClass(),
-                    key.getTypeArgumentIndex());
+                        key.getTypeArgumentIndex());
             }
             path.addNode(newLeaf);
 
@@ -504,7 +503,7 @@ public abstract class ValidationJob<T> {
 
     private class UnwrappedElementConstraintValidationPseudoFrame<D extends ElementD<?, ?>> extends Frame<D> {
         final Lazy<IllegalStateException> exc = new Lazy<>(() -> Exceptions.create(IllegalStateException::new,
-            "%s is not meant to participate in validation lifecycle", getClass()));
+                "%s is not meant to participate in validation lifecycle", getClass()));
 
         UnwrappedElementConstraintValidationPseudoFrame(ValidationJob<T>.Frame<D> parent, GraphContext context) {
             super(parent, parent.descriptor, context);
@@ -531,11 +530,11 @@ public abstract class ValidationJob<T> {
 
     private static Stream<ConstraintD<?>> constraintsFor(ElementD<?, ?> descriptor, GroupStrategy groups) {
         return descriptor.getConstraintDescriptors().stream().<ConstraintD<?>> map(ConstraintD.class::cast)
-            .filter(c -> {
-                final Set<Class<?>> constraintGroups = c.getGroups();
-                return groups.getGroups().stream().map(Group::getGroup).anyMatch(g -> constraintGroups.contains(g)
-                    || constraintGroups.contains(Default.class) && c.getDeclaringClass().equals(g));
-            });
+                .filter(c -> {
+                    final Set<Class<?>> constraintGroups = c.getGroups();
+                    return groups.getGroups().stream().map(Group::getGroup).anyMatch(g -> constraintGroups.contains(g)
+                            || constraintGroups.contains(Default.class) && c.getDeclaringClass().equals(g));
+                });
     }
 
     protected final ApacheFactoryContext validatorContext;
@@ -543,7 +542,8 @@ public abstract class ValidationJob<T> {
 
     private final Lazy<Set<ConstraintViolation<T>>> results = new Lazy<>(LinkedHashSet::new);
 
-    private ConcurrentMap<ConstraintD<?>, ConcurrentMap<Path, Set<Object>>> completedValidations;
+    /** Filled only during single-threaded {@link #getResults()} for one validation. */
+    private Map<ConstraintD<?>, Map<Path, Set<Object>>> completedValidations;
 
     ValidationJob(ApacheFactoryContext validatorContext, Class<?>[] groups) {
         super();
@@ -561,7 +561,7 @@ public abstract class ValidationJob<T> {
 
             final Consumer<ConstraintViolation<T>> sink = results.consumer(Set::add);
 
-            completedValidations = new ConcurrentHashMap<>();
+            completedValidations = new HashMap<>();
             try {
                 baseFrame.process(groups.asStrategy(), sink);
             } finally {
@@ -587,7 +587,7 @@ public abstract class ValidationJob<T> {
     }
 
     final ConstraintViolationImpl<T> createViolation(String messageTemplate, ConstraintValidatorContextImpl<T> context,
-        PathImpl propertyPath) {
+                                                     PathImpl propertyPath) {
         if (!propertyPath.isRootPath()) {
             final NodeImpl leafNode = propertyPath.getLeafNode();
             if (leafNode.getName() == null && !(leafNode.getKind() == ElementKind.BEAN || leafNode.isInIterable())) {
@@ -598,7 +598,7 @@ public abstract class ValidationJob<T> {
     }
 
     abstract ConstraintViolationImpl<T> createViolation(String messageTemplate, String message,
-        ConstraintValidatorContextImpl<T> context, PathImpl propertyPath);
+                                                        ConstraintValidatorContextImpl<T> context, PathImpl propertyPath);
 
     protected abstract Frame<?> computeBaseFrame();
 


(bval) 06/06: [perf] Ccheckoint: Reduce streams

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bval.git

commit ae05de39972513cf8ec2e29bc6e80c7c35bb6cfe
Author: tandraschko <ta...@apache.org>
AuthorDate: Thu Apr 23 22:07:31 2026 +0200

    [perf] Ccheckoint: Reduce streams
---
 .../src/main/java/org/apache/bval/jsr/descriptor/BeanD.java  | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java
index d85ddff..91c24d2 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java
@@ -23,7 +23,6 @@ import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
 
 import jakarta.validation.metadata.BeanDescriptor;
@@ -44,6 +43,8 @@ public class BeanD<T> extends ElementD<Class<T>, MetadataReader.ForBean<T>> impl
     private final Class<T> beanClass;
     private final Map<String, PropertyDescriptor> propertiesMap;
     private final Set<PropertyDescriptor> properties;
+    /** Constrained properties only, by name — hot path for {@link #getConstraintsForProperty(String)}. */
+    private final Map<String, PropertyDescriptor> constraintsForPropertyByName;
     private final Map<Signature, ConstructorD<T>> constructors;
     private final Map<Signature, MethodD> methods;
     private final GroupStrategy groupStrategy;
@@ -59,6 +60,11 @@ public class BeanD<T> extends ElementD<Class<T>, MetadataReader.ForBean<T>> impl
         propertiesMap = reader.getProperties(this);
         properties =
             propertiesMap.values().stream().filter(DescriptorManager::isConstrained).collect(ToUnmodifiable.set());
+        final Map<String, PropertyDescriptor> cfpn = new HashMap<>();
+        for (PropertyDescriptor p : properties) {
+            cfpn.put(p.getPropertyName(), p);
+        }
+        constraintsForPropertyByName = Map.copyOf(cfpn);
         constructors = reader.getConstructors(this);
         methods = reader.getMethods(this);
         
@@ -78,7 +84,9 @@ public class BeanD<T> extends ElementD<Class<T>, MetadataReader.ForBean<T>> impl
 
     @Override
     public PropertyDescriptor getConstraintsForProperty(String propertyName) {
-        return Optional.ofNullable(getProperty(propertyName)).filter(properties::contains).orElse(null);
+        Exceptions.raiseIf(StringUtils.isBlank(propertyName), IllegalArgumentException::new,
+            "propertyName was null/empty/blank");
+        return constraintsForPropertyByName.get(propertyName);
     }
 
     @Override


(bval) 01/06: [perf] improve ConstraintValidator init

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bval.git

commit bfd9cb2440019f424a83bd93296f48f66fde671f
Author: tandraschko <ta...@apache.org>
AuthorDate: Thu Apr 23 13:00:20 2026 +0200

    [perf] improve ConstraintValidator init
---
 .../org/apache/bval/jsr/ApacheFactoryContext.java  | 29 ++++++++++++++--------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
index 6dde017..cfea9ff 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
@@ -27,6 +27,7 @@ import jakarta.validation.ConstraintValidatorFactory;
 import jakarta.validation.MessageInterpolator;
 import jakarta.validation.ParameterNameProvider;
 import jakarta.validation.TraversableResolver;
+import jakarta.validation.ValidationException;
 import jakarta.validation.Validator;
 import jakarta.validation.ValidatorContext;
 import jakarta.validation.valueextraction.ValueExtractor;
@@ -191,17 +192,25 @@ public class ApacheFactoryContext implements ValidatorContext {
         return factory;
     }
 
+    /**
+     * Create (if missing) and cache a {@link ConstraintValidator} for this constraint, and call
+     * {@link ConstraintValidator#initialize} once. Per BV usage, a cached instance is reused; initialize is not
+     * repeated on every {@code isValid} invocation.
+     */
     public ConstraintValidator getOrComputeConstraintValidator(final ConstraintD<?> constraint, final Supplier<ConstraintValidator> computer) {
         final ConcurrentMap<ConstraintD<?>, ConstraintValidator<?, ?>> constraintsCache = factory.getConstraintsCache().getValidators();
-        final ConstraintValidator<?, ?> validator = constraintsCache.get(constraint); // constraints are cached so we can query per instance
-        if (validator != null) {
-            return validator;
-        }
-        ConstraintValidator<?, ?> instance = computer.get();
-        final ConstraintValidator<?, ?> existing = constraintsCache.putIfAbsent(constraint, instance);
-        if (existing != null) {
-            instance = existing;
-        }
-        return instance;
+        return constraintsCache.computeIfAbsent(constraint, c -> {
+            final ConstraintValidator instance = computer.get();
+            if (instance != null) {
+                try {
+                    instance.initialize(c.getAnnotation());
+                } catch (ValidationException e) {
+                    throw e;
+                } catch (Exception e) {
+                    throw new ValidationException(e);
+                }
+            }
+            return instance;
+        });
     }
 }


(bval) 05/06: [perf] Ccheckoint: Cheaper unconstrained-bean path, Less stream work in the bean/property walk

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bval.git

commit 4d8a301146c8b09f359c658d4f2b3448ecb6158a
Author: tandraschko <ta...@apache.org>
AuthorDate: Thu Apr 23 21:46:00 2026 +0200

    [perf] Ccheckoint: Cheaper unconstrained-bean path, Less stream work in the bean/property walk
---
 .../org/apache/bval/jsr/descriptor/ComposedD.java  |  15 ++
 .../bval/jsr/descriptor/DescriptorManager.java     |  15 +-
 .../java/org/apache/bval/jsr/job/ValidateBean.java |  10 +-
 .../org/apache/bval/jsr/job/ValidationJob.java     | 156 ++++++++++++---------
 4 files changed, 129 insertions(+), 67 deletions(-)

diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
index 2ddb44d..1923b75 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java
@@ -22,6 +22,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.Consumer;
 import java.util.stream.Stream;
 
 import jakarta.validation.metadata.CascadableDescriptor;
@@ -89,6 +90,20 @@ public abstract class ComposedD<D extends ElementD<?, ?>> implements ElementDesc
         return s.map(delegateType::cast);
     }
 
+    /**
+     * Like {@link #unwrap} but visits each leaf delegate without building a stream (hot path).
+     */
+    public static <T extends ElementD<?, ?>> void forEachUnwrapped(ElementDescriptor descriptor, Class<T> delegateType,
+        Consumer<T> action) {
+        if (descriptor instanceof ComposedD<?>) {
+            for (final Object o : ((ComposedD<?>) descriptor).delegates) {
+                forEachUnwrapped((ElementDescriptor) o, delegateType, action);
+            }
+        } else {
+            action.accept(delegateType.cast(descriptor));
+        }
+    }
+
     protected final List<D> delegates;
 
     ComposedD(List<D> delegates) {
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
index a2cc0aa..2d3081e 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
@@ -59,6 +59,8 @@ public class DescriptorManager {
 
     private final ApacheValidatorFactory validatorFactory;
     private final ConcurrentMap<Class<?>, BeanD<?>> beanDescriptors = new ConcurrentHashMap<>();
+    /** Same meaning as {@link BeanDescriptor#isBeanConstrained()} — avoids loading metadata on repeat {@code hasWork} checks. */
+    private final ConcurrentMap<Class<?>, Boolean> beanConstrainedByType = new ConcurrentHashMap<>();
     // synchronization unnecessary
     private final ReflectionBuilder reflectionBuilder;
 
@@ -68,21 +70,32 @@ public class DescriptorManager {
         this.reflectionBuilder = new ReflectionBuilder(validatorFactory);
     }
 
+    /**
+     * @return cached result of {@link BeanDescriptor#isBeanConstrained()} for this class, or {@code null} if unknown
+     */
+    public Boolean getCachedBeanConstrained(Class<?> beanClass) {
+        return beanConstrainedByType.get(beanClass);
+    }
+
     public <T> BeanDescriptor getBeanDescriptor(Class<T> beanClass) {
         Validate.notNull(beanClass, IllegalArgumentException::new, "beanClass");
 
         // cannot use computeIfAbsent due to recursion being the usual case:
         final BeanD<?> existing = beanDescriptors.get(beanClass);
         if (existing != null) {
+            beanConstrainedByType.put(beanClass, existing.isBeanConstrained());
             return existing;
         }
         final BeanD<?> value = new BeanD<>(new MetadataReader(validatorFactory, beanClass).forBean(builder(beanClass)));
         final BeanD<?> previous = beanDescriptors.putIfAbsent(beanClass, value);
-        return previous == null ? value : previous;
+        final BeanD<?> result = previous == null ? value : previous;
+        beanConstrainedByType.put(beanClass, result.isBeanConstrained());
+        return result;
     }
 
     public void clear() {
         beanDescriptors.clear();
+        beanConstrainedByType.clear();
     }
 
     private <T> MetadataBuilder.ForBean<T> builder(Class<T> beanClass) {
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java
index d9899db..ee22b18 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java
@@ -23,6 +23,7 @@ import org.apache.bval.jsr.ConstraintViolationImpl;
 import org.apache.bval.jsr.GraphContext;
 import org.apache.bval.jsr.descriptor.BeanD;
 import org.apache.bval.jsr.descriptor.ConstraintD;
+import org.apache.bval.jsr.descriptor.DescriptorManager;
 import org.apache.bval.jsr.util.PathImpl;
 import org.apache.bval.jsr.util.Proxies;
 import org.apache.bval.util.Validate;
@@ -47,9 +48,12 @@ public final class ValidateBean<T> extends ValidationJob<T> {
             unwrappedClass = Proxies.classFor(beanClass);
             classCache.putIfAbsent(beanClass, unwrappedClass);
         }
-        return validatorContext.getFactory().getDescriptorManager()
-                .getBeanDescriptor(unwrappedClass)
-                .isBeanConstrained();
+        final DescriptorManager dm = validatorContext.getFactory().getDescriptorManager();
+        final Boolean cached = dm.getCachedBeanConstrained(unwrappedClass);
+        if (cached != null) {
+            return cached;
+        }
+        return dm.getBeanDescriptor(unwrappedClass).isBeanConstrained();
     }
 
     @Override
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
index 6dc8e6c..670297f 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
@@ -23,7 +23,9 @@ import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.IdentityHashMap;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -33,7 +35,6 @@ import java.util.TreeMap;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
-import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
 import jakarta.validation.ConstraintValidator;
@@ -48,6 +49,8 @@ import jakarta.validation.constraintvalidation.ValidationTarget;
 import jakarta.validation.groups.Default;
 import jakarta.validation.metadata.CascadableDescriptor;
 import jakarta.validation.metadata.ContainerDescriptor;
+import jakarta.validation.metadata.ContainerElementTypeDescriptor;
+import jakarta.validation.metadata.GroupConversionDescriptor;
 import jakarta.validation.metadata.PropertyDescriptor;
 import jakarta.validation.metadata.ValidateUnwrappedValue;
 import jakarta.validation.valueextraction.ValueExtractor;
@@ -282,25 +285,31 @@ public abstract class ValidationJob<T> {
         }
 
         private Set<Frame<?>> propertyFrames() {
-            final Stream<PropertyD<?>> properties = descriptor.getConstrainedProperties().stream()
-                    .flatMap(d -> ComposedD.unwrap(d, PropertyD.class)).map(d -> (PropertyD<?>) d);
-
             final TraversableResolver traversableResolver = validatorContext.getTraversableResolver();
-
-            final Stream<PropertyD<?>> reachableProperties = properties.filter(d -> {
-                final PathImpl p = realContext.getPath();
-                p.addProperty(d.getPropertyName());
-                try {
-                    return traversableResolver.isReachable(context.getValue(), p.removeLeafNode(), getRootBeanClass(),
-                            p, d.getElementType());
-                } catch (ValidationException ve) {
-                    throw ve;
-                } catch (Exception e) {
-                    throw new ValidationException(e);
-                }
-            });
-            return reachableProperties.flatMap(d -> d.read(realContext).filter(context -> !context.isRecursive())
-                    .map(child -> propertyFrame(d, child))).collect(Collectors.toSet());
+            final Set<Frame<?>> frames = new HashSet<>();
+            for (final PropertyDescriptor pd : descriptor.getConstrainedProperties()) {
+                ComposedD.forEachUnwrapped(pd, PropertyD.class, d -> {
+                    final PathImpl p = realContext.getPath();
+                    p.addProperty(d.getPropertyName());
+                    try {
+                        if (!traversableResolver.isReachable(context.getValue(), p.removeLeafNode(), getRootBeanClass(),
+                                p, d.getElementType())) {
+                            return;
+                        }
+                    } catch (ValidationException ve) {
+                        throw ve;
+                    } catch (Exception e) {
+                        throw new ValidationException(e);
+                    }
+                    for (final Iterator<GraphContext> it = d.read(realContext).iterator(); it.hasNext();) {
+                        final GraphContext child = it.next();
+                        if (!child.isRecursive()) {
+                            frames.add(propertyFrame(d, child));
+                        }
+                    }
+                });
+            }
+            return frames;
         }
     }
 
@@ -318,18 +327,22 @@ public abstract class ValidationJob<T> {
         void validateDescriptorConstraints(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
             super.validateDescriptorConstraints(groups, sink);
             if (context.getValue() != null) {
-                descriptor.getConstrainedContainerElementTypes().stream()
-                        .flatMap(d -> ComposedD.unwrap(d, ContainerElementTypeD.class)).forEach(d -> {
-                            if (constraintsFor(d, groups).findFirst().isPresent()
-                                    || !d.getConstrainedContainerElementTypes().isEmpty()) {
-                                final ValueExtractor<?> declaredTypeValueExtractor =
-                                        context.getValidatorContext().getValueExtractors().find(d.getKey());
-                                ExtractValues.extract(context, d.getKey(), declaredTypeValueExtractor).stream()
-                                        .filter(e -> !e.isRecursive())
-                                        .map(e -> new ContainerElementConstraintsFrame(this, d, e))
-                                        .forEach(f -> f.validateDescriptorConstraints(groups, sink));
+                for (final ContainerElementTypeDescriptor ctd : descriptor.getConstrainedContainerElementTypes()) {
+                    ComposedD.forEachUnwrapped(ctd, ContainerElementTypeD.class, d -> {
+                        if (!constraintsFor(d, groups).findFirst().isPresent()
+                                && d.getConstrainedContainerElementTypes().isEmpty()) {
+                            return;
+                        }
+                        final ValueExtractor<?> declaredTypeValueExtractor =
+                                context.getValidatorContext().getValueExtractors().find(d.getKey());
+                        for (final GraphContext e : ExtractValues.extract(context, d.getKey(), declaredTypeValueExtractor)) {
+                            if (!e.isRecursive()) {
+                                new ContainerElementConstraintsFrame(this, d, e)
+                                        .validateDescriptorConstraints(groups, sink);
                             }
-                        });
+                        }
+                    });
+                }
             }
         }
 
@@ -338,23 +351,30 @@ public abstract class ValidationJob<T> {
             if (context.getValue() == null || !DescriptorManager.isCascaded(descriptor)) {
                 return;
             }
-            final Map<Group, GroupStrategy> conversions =
-                    descriptor.getGroupConversions().stream().collect(Collectors.toMap(gc -> Group.of(gc.getFrom()),
-                            gc -> validatorContext.getGroupsComputer().computeGroups(gc.getTo()).asStrategy()));
+            final Map<Group, GroupStrategy> conversions = new HashMap<>();
+            for (final GroupConversionDescriptor gc : descriptor.getGroupConversions()) {
+                conversions.put(Group.of(gc.getFrom()),
+                        validatorContext.getGroupsComputer().computeGroups(gc.getTo()).asStrategy());
+            }
 
             GroupStrategy.redefining(groups, conversions).applyTo(noViolations(gs -> cascade(gs, sink)));
         }
 
         private void cascade(GroupStrategy groups, Consumer<ConstraintViolation<T>> sink) {
-            descriptor.getConstrainedContainerElementTypes().stream()
-                    .filter(d -> d.isCascaded() || !d.getConstrainedContainerElementTypes().isEmpty())
-                    .flatMap(d -> ComposedD.unwrap(d, ContainerElementTypeD.class)).forEach(d -> {
-                        final ValueExtractor<?> runtimeTypeValueExtractor =
-                                context.getValidatorContext().getValueExtractors().find(context.runtimeKey(d.getKey()));
-                        ExtractValues.extract(context, d.getKey(), runtimeTypeValueExtractor).stream()
-                                .filter(e -> !e.isRecursive()).map(e -> new ContainerElementCascadeFrame(this, d, e))
-                                .forEach(f -> f.recurse(groups, sink));
-                    });
+            for (final ContainerElementTypeDescriptor ctd : descriptor.getConstrainedContainerElementTypes()) {
+                ComposedD.forEachUnwrapped(ctd, ContainerElementTypeD.class, d -> {
+                    if (!d.isCascaded() && d.getConstrainedContainerElementTypes().isEmpty()) {
+                        return;
+                    }
+                    final ValueExtractor<?> runtimeTypeValueExtractor =
+                            context.getValidatorContext().getValueExtractors().find(context.runtimeKey(d.getKey()));
+                    for (final GraphContext e : ExtractValues.extract(context, d.getKey(), runtimeTypeValueExtractor)) {
+                        if (!e.isRecursive()) {
+                            new ContainerElementCascadeFrame(this, d, e).recurse(groups, sink);
+                        }
+                    }
+                });
+            }
             if (!descriptor.isCascaded()) {
                 return;
             }
@@ -378,48 +398,58 @@ public abstract class ValidationJob<T> {
                     throw new ValidationException(e);
                 }
             }
-            multiplex().filter(context -> context.getValue() != null && !context.isRecursive())
-                    .map(context -> new BeanFrame<>(this, context)).forEach(b -> b.process(groups, sink));
+            multiplexEach(cx -> {
+                if (cx.getValue() != null && !cx.isRecursive()) {
+                    new BeanFrame<>(this, cx).process(groups, sink);
+                }
+            });
         }
 
         protected GraphContext getMultiplexContext() {
             return context;
         }
 
-        private Stream<GraphContext> multiplex() {
+        private void multiplexEach(Consumer<GraphContext> consumer) {
             final GraphContext multiplexContext = getMultiplexContext();
             final Object value = multiplexContext.getValue();
             if (value == null) {
-                return Stream.empty();
+                return;
             }
             if (value.getClass().isArray()) {
                 // inconsistent: use Object[] here but specific type for Iterable? RI compatibility
                 final Class<?> arrayType = value instanceof Object[] ? Object[].class : value.getClass();
-                return IntStream.range(0, Array.getLength(value)).mapToObj(
-                        i -> multiplexContext.child(NodeImpl.atIndex(i).inContainer(arrayType, null), Array.get(value, i)));
+                for (int i = 0, n = Array.getLength(value); i < n; i++) {
+                    consumer.accept(
+                            multiplexContext.child(NodeImpl.atIndex(i).inContainer(arrayType, null), Array.get(value, i)));
+                }
+                return;
             }
             if (Map.class.isInstance(value)) {
-                return ((Map<?, ?>) value).entrySet().stream()
-                        .map(e -> multiplexContext.child(
-                                setContainerInformation(NodeImpl.atKey(e.getKey()), MAP_VALUE, descriptor.getElementClass()),
-                                e.getValue()));
+                for (final Map.Entry<?, ?> e : ((Map<?, ?>) value).entrySet()) {
+                    consumer.accept(multiplexContext.child(
+                            setContainerInformation(NodeImpl.atKey(e.getKey()), MAP_VALUE, descriptor.getElementClass()),
+                            e.getValue()));
+                }
+                return;
             }
             if (List.class.isInstance(value)) {
                 final List<?> l = (List<?>) value;
-                return IntStream.range(0, l.size())
-                        .mapToObj(i -> multiplexContext.child(
-                                setContainerInformation(NodeImpl.atIndex(i), ITERABLE_ELEMENT, descriptor.getElementClass()),
-                                l.get(i)));
+                for (int i = 0, n = l.size(); i < n; i++) {
+                    consumer.accept(multiplexContext.child(
+                            setContainerInformation(NodeImpl.atIndex(i), ITERABLE_ELEMENT, descriptor.getElementClass()),
+                            l.get(i)));
+                }
+                return;
             }
             if (Iterable.class.isInstance(value)) {
-                final Stream.Builder<Object> b = Stream.builder();
-                ((Iterable<?>) value).forEach(b);
-                return b.build()
-                        .map(o -> multiplexContext.child(
-                                setContainerInformation(NodeImpl.atIndex(null), ITERABLE_ELEMENT, descriptor.getElementClass()),
-                                o));
+                for (final Object o : (Iterable<?>) value) {
+                    consumer.accept(multiplexContext.child(
+                            setContainerInformation(NodeImpl.atIndex(null), ITERABLE_ELEMENT, descriptor.getElementClass()),
+                            o));
+                }
+                return;
             }
-            return Stream.of(multiplexContext);
+            consumer.accept(multiplexContext);
         }
 
         // RI apparently wants to use e.g. Set for Iterable containers, so use declared type + assigned type


(bval) 02/06: Update hibernate-validator

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bval.git

commit f97ff39bd6ff93908a0a5d26151e9f8dd9e824cb
Author: tandraschko <ta...@apache.org>
AuthorDate: Thu Apr 23 13:01:31 2026 +0200

    Update hibernate-validator
---
 bval-perf/pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bval-perf/pom.xml b/bval-perf/pom.xml
index 5f246ba..dc27763 100644
--- a/bval-perf/pom.xml
+++ b/bval-perf/pom.xml
@@ -67,9 +67,9 @@
     </dependency>
 
     <dependency>
-      <groupId>org.hibernate</groupId>
+      <groupId>org.hibernate.validator</groupId>
       <artifactId>hibernate-validator</artifactId>
-      <version>8.0.2.Final</version>
+      <version>9.1.0.Final</version>
       <scope>test</scope>
     </dependency>