improve handling of non-constrained executables
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
index c80937f..d4f9668 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
@@ -162,6 +162,11 @@
         return new ParametersFrame(describe(), new GraphContext(validatorContext, cp, parameterValues));
     }
 
+    @Override
+    protected boolean hasWork() {
+        return describe() != null;
+    }
+
     protected abstract ExecutableDescriptor describe();
 
     protected abstract List<String> getParameterNames(ParameterNameProvider parameterNameProvider);
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
index ca1deba..d477b72 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
@@ -131,6 +131,11 @@
             context.getConstraintDescriptor().unwrap(ConstraintD.class).getDeclaredOn(), returnValue, null);
     }
 
+    @Override
+    protected boolean hasWork() {
+        return describe() != null;
+    }
+
     protected abstract ExecutableD<?, ?, ?> describe();
 
     protected abstract T getRootBean();
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 b8f22c1..61dcd39 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
@@ -489,26 +489,31 @@
         if (results.optional().isPresent()) {
             return results.get();
         }
-        final Frame<?> baseFrame = computeBaseFrame();
-        Validate.validState(baseFrame != null, "%s computed null baseFrame", getClass().getName());
+        if (hasWork()) {
+            final Frame<?> baseFrame = computeBaseFrame();
+            Validate.validState(baseFrame != null, "%s computed null baseFrame", getClass().getName());
 
-        final Consumer<ConstraintViolation<T>> sink = results.consumer(Set::add);
+            final Consumer<ConstraintViolation<T>> sink = results.consumer(Set::add);
 
-        validatedPathsByConstraint = new ConcurrentHashMap<>();
+            validatedPathsByConstraint = new ConcurrentHashMap<>();
 
-        try {
-            groups.getGroups().stream().map(Group::getGroup).forEach(g -> baseFrame.process(g, sink));
+            try {
+                groups.getGroups().stream().map(Group::getGroup).forEach(g -> baseFrame.process(g, sink));
 
-            sequences: for (List<Group> seq : groups.getSequences()) {
-                final boolean proceed = each(seq.stream().map(Group::getGroup), baseFrame::process, sink);
-                if (!proceed) {
-                    break sequences;
+                sequences: for (List<Group> seq : groups.getSequences()) {
+                    final boolean proceed = each(seq.stream().map(Group::getGroup), baseFrame::process, sink);
+                    if (!proceed) {
+                        break sequences;
+                    }
                 }
+            } finally {
+                validatedPathsByConstraint = null;
             }
-        } finally {
-            validatedPathsByConstraint = null;
+            if (results.optional().isPresent()) {
+                return Collections.unmodifiableSet(results.get());
+            }
         }
-        return results.optional().map(Collections::unmodifiableSet).orElse(Collections.emptySet());
+        return results.reset(Collections::emptySet).get();
     }
 
     private boolean each(Stream<Class<?>> groupSequence, BiConsumer<Class<?>, Consumer<ConstraintViolation<T>>> closure,
@@ -543,6 +548,10 @@
 
     protected abstract Class<T> getRootBeanClass();
 
+    protected boolean hasWork() {
+        return true;
+    }
+
     private final String interpolate(String messageTemplate, MessageInterpolator.Context context) {
         try {
             return validatorContext.getMessageInterpolator().interpolate(messageTemplate, context);