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

danhaywood pushed a commit to branch CAUSEWAY-3676
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/CAUSEWAY-3676 by this push:
     new 2622f28c1a CAUSEWAY-3676: validates invoke
2622f28c1a is described below

commit 2622f28c1afb0e32b7a824e5b3afb6a9961f6f48
Author: danhaywood <[email protected]>
AuthorDate: Wed Jan 24 22:15:36 2024 +0000

    CAUSEWAY-3676: validates invoke
---
 .../viewer/graphql/model/domain/GqlvAction.java    |   11 +-
 .../graphql/model/domain/GqlvActionInvoke.java     |   16 +-
 ...lvActionInvoke.java => GqlvActionValidate.java} |   96 +-
 .../model/domain/GqlvActionValidateHolder.java     |   27 +
 .../graphql/model/domain/GqlvPropertyValidate.java |   15 +-
 .../graphql/viewer/test/domain/DeptHead.java       |    8 +
 .../graphql/viewer/test/domain/StaffMember.java    |    2 +-
 ...n_IntegTest.find_depthead_and_change_name._.gql |    4 +-
 ...est.find_depthead_and_change_name.approved.json |    2 +-
 ...st.find_depthead_and_change_name_invalid._.gql} |    4 +-
 ..._depthead_and_change_name_invalid.approved.json |   24 +
 .../graphql/viewer/test/e2e/Domain_IntegTest.java  |   25 +-
 .../test/e2e/Schema_IntegTest.schema.approved.json | 1272 +++++++++++++++++++-
 .../graphql/test/src/test/resources/schema.gql     |   60 +
 14 files changed, 1428 insertions(+), 138 deletions(-)

diff --git 
a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
index 04e965b3a4..f51077c69d 100644
--- 
a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
+++ 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
@@ -31,13 +31,18 @@ import static 
graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
 import static graphql.schema.GraphQLObjectType.newObject;
 
 @Log4j2
-public class GqlvAction extends GqlvMember<ObjectAction, GqlvActionHolder>
-        implements GqlvActionInvokeHolder, GqlvMemberHiddenHolder, 
GqlvMemberDisabledHolder {
+public class GqlvAction
+        extends GqlvMember<ObjectAction, GqlvActionHolder>
+        implements  GqlvMemberHiddenHolder,
+                    GqlvMemberDisabledHolder,
+                    GqlvActionInvokeHolder,
+                    GqlvActionValidateHolder {
 
     private final GraphQLObjectType.Builder gqlObjectTypeBuilder;
     private final GraphQLObjectType gqlObjectType;
     private final GqlvMemberHidden hidden;
     private final GqlvMemberDisabled disabled;
+    private final GqlvActionValidate validate;
     private final GqlvActionInvoke invoke;
     private final BookmarkService bookmarkService;
 
@@ -54,6 +59,7 @@ public class GqlvAction extends GqlvMember<ObjectAction, 
GqlvActionHolder>
 
         this.hidden = new GqlvMemberHidden(this, codeRegistryBuilder);
         this.disabled = new GqlvMemberDisabled(this, codeRegistryBuilder);
+        this.validate = new GqlvActionValidate(this, codeRegistryBuilder);
         this.invoke = new GqlvActionInvoke(this, codeRegistryBuilder);
 
         this.gqlObjectType = gqlObjectTypeBuilder.build();
@@ -86,6 +92,7 @@ public class GqlvAction extends GqlvMember<ObjectAction, 
GqlvActionHolder>
 
         hidden.addDataFetcher();
         disabled.addDataFetcher();
+        validate.addDataFetcher();
         invoke.addDataFetcher();
     }
 
diff --git 
a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
index f941fefa23..925e825fae 100644
--- 
a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
+++ 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
@@ -21,6 +21,7 @@ package org.apache.causeway.viewer.graphql.model.domain;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import org.apache.causeway.core.metamodel.consent.Consent;
 import org.apache.causeway.core.metamodel.spec.feature.OneToOneActionParameter;
 
 import org.springframework.lang.Nullable;
@@ -173,19 +174,24 @@ public class GqlvActionInvoke {
         val managedObject = ManagedObject.adaptSingular(objectSpecification, 
sourcePojo);
         val actionInteractionHead = 
objectAction.interactionHead(managedObject);
 
-        Map<String, Object> arguments = dataFetchingEnvironment.getArguments();
+        Map<String, Object> argumentPojos = 
dataFetchingEnvironment.getArguments();
         Can<ObjectActionParameter> parameters = objectAction.getParameters();
-        Can<ManagedObject> canOfParams = parameters
+        Can<ManagedObject> argumentManagedObjects = parameters
                 .map(oap -> {
-                    Object argumentValue = arguments.get(oap.getId());
+                    Object argumentValue = argumentPojos.get(oap.getId());
                     return ManagedObject.adaptParameter(oap, argumentValue);
                 });
 
-        // TODO: should validate args first.
+        val consent = objectAction.isArgumentSetValid(actionInteractionHead, 
argumentManagedObjects, InteractionInitiatedBy.USER);
+        if (consent.isVetoed()) {
+            throw new 
IllegalArgumentException(consent.getReasonAsString().orElse("Invalid"));
+        }
+
         val resultManagedObject = objectAction
-                .execute(actionInteractionHead, canOfParams, 
InteractionInitiatedBy.USER);
+                .execute(actionInteractionHead, argumentManagedObjects, 
InteractionInitiatedBy.USER);
 
         return resultManagedObject.getPojo();
+
     }
 
 }
diff --git 
a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidate.java
similarity index 53%
copy from 
incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
copy to 
incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidate.java
index f941fefa23..ff6bdc15e0 100644
--- 
a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
+++ 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidate.java
@@ -21,7 +21,7 @@ package org.apache.causeway.viewer.graphql.model.domain;
 import java.util.Map;
 import java.util.stream.Collectors;
 
-import org.apache.causeway.core.metamodel.spec.feature.OneToOneActionParameter;
+import org.apache.causeway.core.metamodel.consent.Consent;
 
 import org.springframework.lang.Nullable;
 
@@ -32,6 +32,7 @@ import 
org.apache.causeway.core.metamodel.object.ManagedObject;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
 import org.apache.causeway.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.causeway.core.metamodel.spec.feature.OneToOneActionParameter;
 import org.apache.causeway.viewer.graphql.model.types.TypeMapper;
 
 import lombok.val;
@@ -48,14 +49,14 @@ import graphql.schema.GraphQLType;
 import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
 
 @Log4j2
-public class GqlvActionInvoke {
+public class GqlvActionValidate {
 
-    private final GqlvActionInvokeHolder holder;
+    private final GqlvActionValidateHolder holder;
     private final GraphQLCodeRegistry.Builder codeRegistryBuilder;
     private final GraphQLFieldDefinition field;
 
-    public GqlvActionInvoke(
-            final GqlvActionInvokeHolder holder,
+    public GqlvActionValidate(
+            final GqlvActionValidateHolder holder,
             final GraphQLCodeRegistry.Builder codeRegistryBuilder
     ) {
         this.holder = holder;
@@ -63,15 +64,15 @@ public class GqlvActionInvoke {
         this.field = fieldDefinition(holder);
     }
 
-    private static GraphQLFieldDefinition fieldDefinition(final 
GqlvActionInvokeHolder holder) {
+    private static GraphQLFieldDefinition fieldDefinition(final 
GqlvActionValidateHolder holder) {
 
         val objectAction = holder.getObjectAction();
 
         GraphQLFieldDefinition fieldDefinition = null;
-        GraphQLOutputType type = typeFor(objectAction);
+        GraphQLOutputType type = TypeMapper.scalarTypeFor(String.class);
         if (type != null) {
             val fieldBuilder = newFieldDefinition()
-                    .name(fieldNameForSemanticsOf(objectAction))
+                    .name("validate")
                     .type(type);
             addGqlArguments(objectAction, fieldBuilder);
             fieldDefinition = fieldBuilder.build();
@@ -81,82 +82,21 @@ public class GqlvActionInvoke {
         return fieldDefinition;
     }
 
-    private static String fieldNameForSemanticsOf(ObjectAction objectAction) {
-        switch (objectAction.getSemantics()) {
-            case SAFE_AND_REQUEST_CACHEABLE:
-            case SAFE:
-                return "invoke";
-            case IDEMPOTENT:
-            case IDEMPOTENT_ARE_YOU_SURE:
-                return "invokeIdempotent";
-            case NON_IDEMPOTENT:
-            case NON_IDEMPOTENT_ARE_YOU_SURE:
-            case NOT_SPECIFIED:
-            default:
-                return "invokeNonIdempotent";
-        }
-    }
-
-    @Nullable
-    private static GraphQLOutputType typeFor(final ObjectAction objectAction){
-        ObjectSpecification objectSpecification = objectAction.getReturnType();
-        switch (objectSpecification.getBeanSort()){
-
-            case COLLECTION:
-
-                TypeOfFacet facet = objectAction.getFacet(TypeOfFacet.class);
-                if (facet == null) {
-                    log.warn("Unable to locate TypeOfFacet for {}", 
objectAction.getFeatureIdentifier().getFullIdentityString());
-                    return null;
-                }
-                ObjectSpecification 
objectSpecificationForElementWhenCollection = facet.elementSpec();
-                GraphQLType wrappedType = 
TypeMapper.outputTypeFor(objectSpecificationForElementWhenCollection);
-                if (wrappedType == null) {
-                    log.warn("Unable to create wrapped type of for {} for 
action {}",
-                            
objectSpecificationForElementWhenCollection.getFullIdentifier(),
-                            
objectAction.getFeatureIdentifier().getFullIdentityString());
-                    return null;
-                }
-                return GraphQLList.list(wrappedType);
-
-            case VALUE:
-            case ENTITY:
-            case VIEW_MODEL:
-            default:
-                return TypeMapper.outputTypeFor(objectSpecification);
-
-        }
-    }
-
     static void addGqlArguments(
             final ObjectAction objectAction,
             final GraphQLFieldDefinition.Builder builder) {
 
-        Can<ObjectActionParameter> parameters = objectAction.getParameters();
-
-        if (parameters.isNotEmpty()) {
-            builder.arguments(parameters.stream()
-                    .map(OneToOneActionParameter.class::cast)   // we 
previously filter to ignore any actions that have collection parameters
-                    .map(GqlvActionInvoke::gqlArgumentFor)
-                    .collect(Collectors.toList()));
-        }
-    }
-
-    private static GraphQLArgument gqlArgumentFor(final 
OneToOneActionParameter oneToOneActionParameter) {
-        return GraphQLArgument.newArgument()
-                .name(oneToOneActionParameter.getId())
-                .type(TypeMapper.inputTypeFor(oneToOneActionParameter))
-                .build();
+        GqlvActionInvoke.addGqlArguments(objectAction, builder);
     }
 
     public void addDataFetcher() {
         codeRegistryBuilder.dataFetcher(
                 holder.coordinatesFor(field),
-                this::invoke
+                this::validate
         );
     }
 
-    private Object invoke(final DataFetchingEnvironment 
dataFetchingEnvironment) {
+    private Object validate(final DataFetchingEnvironment 
dataFetchingEnvironment) {
 
         final ObjectAction objectAction = holder.getObjectAction();
 
@@ -173,19 +113,17 @@ public class GqlvActionInvoke {
         val managedObject = ManagedObject.adaptSingular(objectSpecification, 
sourcePojo);
         val actionInteractionHead = 
objectAction.interactionHead(managedObject);
 
-        Map<String, Object> arguments = dataFetchingEnvironment.getArguments();
+        Map<String, Object> argumentPojos = 
dataFetchingEnvironment.getArguments();
         Can<ObjectActionParameter> parameters = objectAction.getParameters();
-        Can<ManagedObject> canOfParams = parameters
+        Can<ManagedObject> argumentManagedObjects = parameters
                 .map(oap -> {
-                    Object argumentValue = arguments.get(oap.getId());
+                    Object argumentValue = argumentPojos.get(oap.getId());
                     return ManagedObject.adaptParameter(oap, argumentValue);
                 });
 
-        // TODO: should validate args first.
-        val resultManagedObject = objectAction
-                .execute(actionInteractionHead, canOfParams, 
InteractionInitiatedBy.USER);
+        Consent consent = 
objectAction.isArgumentSetValid(actionInteractionHead, argumentManagedObjects, 
InteractionInitiatedBy.USER);
 
-        return resultManagedObject.getPojo();
+        return consent.isVetoed() ? 
consent.getReasonAsString().orElse("Invalid") : null;
     }
 
 }
diff --git 
a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidateHolder.java
 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidateHolder.java
new file mode 100644
index 0000000000..0db40ab9e8
--- /dev/null
+++ 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidateHolder.java
@@ -0,0 +1,27 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.model.domain;
+
+import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
+
+public interface GqlvActionValidateHolder extends GqlvHolder {
+
+
+    ObjectAction getObjectAction();
+}
diff --git 
a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java
 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java
index 9416f9a9db..582fa57e89 100644
--- 
a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java
+++ 
b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java
@@ -30,7 +30,6 @@ import 
org.apache.causeway.viewer.graphql.model.types.TypeMapper;
 import lombok.val;
 
 import graphql.schema.DataFetchingEnvironment;
-import graphql.schema.GraphQLArgument;
 import graphql.schema.GraphQLCodeRegistry;
 import graphql.schema.GraphQLFieldDefinition;
 import graphql.schema.GraphQLOutputType;
@@ -57,7 +56,7 @@ public class GqlvPropertyValidate {
     GraphQLFieldDefinition fieldDefinition(final GqlvPropertyValidateHolder 
holder) {
 
         GraphQLFieldDefinition fieldDefinition = null;
-        GraphQLOutputType type = outputTypeFor(holder);
+        GraphQLOutputType type = outputTypeFor();
         if (type != null) {
             val fieldBuilder = newFieldDefinition()
                     .name("validate")
@@ -70,7 +69,7 @@ public class GqlvPropertyValidate {
         return fieldDefinition;
     }
 
-    GraphQLOutputType outputTypeFor(GqlvPropertyValidateHolder holder) {
+    GraphQLOutputType outputTypeFor() {
         return TypeMapper.scalarTypeFor(String.class);
     }
 
@@ -78,17 +77,9 @@ public class GqlvPropertyValidate {
             final OneToOneAssociation oneToOneAssociation,
             final GraphQLFieldDefinition.Builder builder) {
 
-        builder.argument(gqlArgumentFor(oneToOneAssociation));
+        GqlvPropertySet.addGqlArgument(oneToOneAssociation, builder);
     }
 
-    private static GraphQLArgument gqlArgumentFor(final OneToOneAssociation 
oneToOneAssociation) {
-        return GraphQLArgument.newArgument()
-                .name(oneToOneAssociation.getId())
-                .type(TypeMapper.inputTypeFor(oneToOneAssociation))
-                .build();
-    }
-
-
     void addDataFetcher() {
 
         val association = holder.getOneToOneAssociation();
diff --git 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/DeptHead.java
 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/DeptHead.java
index 03f90873b1..d40f1ab1bb 100644
--- 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/DeptHead.java
+++ 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/DeptHead.java
@@ -86,9 +86,17 @@ public class DeptHead implements Comparable<DeptHead> {
         public String default0Act(){
             return getName();
         }
+
+        public String validateAct(String name) {
+            if (name.contains("!")) {
+                return "Name cannot contain '!' character";
+            }
+            return null;
+        }
     }
 
 
+
     @Action(semantics = SemanticsOf.IDEMPOTENT)
     public class changeDepartment {
 
diff --git 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/StaffMember.java
 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/StaffMember.java
index cca203a03f..547ac32a68 100644
--- 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/StaffMember.java
+++ 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/StaffMember.java
@@ -55,7 +55,7 @@ public class StaffMember implements Comparable<StaffMember> {
     private String name;
     public String validateName(String proposedName) {
         if(proposedName.contains("!")) {
-            return("Name cannot contain '!' character");
+            return "Name cannot contain '!' character";
         }
         return null;
     }
diff --git 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name._.gql
 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name._.gql
index 726c65282a..02453720e7 100644
--- 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name._.gql
+++ 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name._.gql
@@ -1,9 +1,9 @@
 {
   university_dept_DeptHeads {
     findHeadByName {
-      invoke(name: "foo") {
+      invoke(name: "Prof. Dicky Horwich") {
         changeName {
-          invokeIdempotent(newName: "bar") {
+          invokeIdempotent(newName: "Prof. Richard Horwich") {
             name {
               get
             }
diff --git 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name.approved.json
 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name.approved.json
index b0d4d8feda..30572563c3 100644
--- 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name.approved.json
+++ 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name.approved.json
@@ -6,7 +6,7 @@
           "changeName" : {
             "invokeIdempotent" : {
               "name" : {
-                "get" : "bar"
+                "get" : "Prof. Richard Horwich"
               }
             }
           }
diff --git 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name._.gql
 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name_invalid._.gql
similarity index 61%
copy from 
incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name._.gql
copy to 
incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name_invalid._.gql
index 726c65282a..4635de96a6 100644
--- 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name._.gql
+++ 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name_invalid._.gql
@@ -1,9 +1,9 @@
 {
   university_dept_DeptHeads {
     findHeadByName {
-      invoke(name: "foo") {
+      invoke(name: "Prof. Dicky Horwich") {
         changeName {
-          invokeIdempotent(newName: "bar") {
+          invokeIdempotent(newName: "Prof. Dicky Horwich!") {
             name {
               get
             }
diff --git 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name_invalid.approved.json
 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name_invalid.approved.json
new file mode 100644
index 0000000000..c253290018
--- /dev/null
+++ 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.find_depthead_and_change_name_invalid.approved.json
@@ -0,0 +1,24 @@
+{
+  "errors" : [ {
+    "message" : "Exception while fetching data 
(/university_dept_DeptHeads/findHeadByName/invoke/changeName/invokeIdempotent) 
: Name cannot contain '!' character",
+    "locations" : [ {
+      "line" : 6,
+      "column" : 11
+    } ],
+    "path" : [ "university_dept_DeptHeads", "findHeadByName", "invoke", 
"changeName", "invokeIdempotent" ],
+    "extensions" : {
+      "classification" : "DataFetchingException"
+    }
+  } ],
+  "data" : {
+    "university_dept_DeptHeads" : {
+      "findHeadByName" : {
+        "invoke" : {
+          "changeName" : {
+            "invokeIdempotent" : null
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.java
 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.java
index 67b9c97774..d454b5b375 100644
--- 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.java
+++ 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Domain_IntegTest.java
@@ -249,19 +249,20 @@ public class Domain_IntegTest extends 
CausewayViewerGraphqlTestModuleIntegTestAb
 
     @Test
     @UseReporter(DiffReporter.class)
-    void find_depthead_and_change_name() throws Exception {
+    void find_depthead_and_change_name_invalid() throws Exception {
 
-        // given
-        transactionService.callTransactional(
-                Propagation.REQUIRED,
-                () -> deptHeadRepository.create("foo", null)
-        ).valueAsNonNullElseFail();
+        String response = submit();
 
-        // when lookup 'foo' and change it to 'bar'
-        String response = transactionService.callTransactional(
-                Propagation.REQUIRED,
-                this::submit
-        ).valueAsNonNullElseFail();
+        // then payload
+        Approvals.verify(response, jsonOptions());
+    }
+
+    @Test
+    @UseReporter(DiffReporter.class)
+    void find_depthead_and_change_name() throws Exception {
+
+        // when lookup 'Prof. Dicky Horwich' and change it to 'Prof. Richard 
Horwich'
+        String response = submit();
 
         // then payload
         Approvals.verify(response, jsonOptions());
@@ -269,7 +270,7 @@ public class Domain_IntegTest extends 
CausewayViewerGraphqlTestModuleIntegTestAb
         // and also in the database
         DeptHead deptHeadAfter = transactionService.callTransactional(
                 Propagation.REQUIRED,
-                () -> deptHeadRepository.findByName("bar")
+                () -> deptHeadRepository.findByName("Prof. Richard Horwich")
         ).valueAsNullableElseFail();
 
         assertThat(deptHeadAfter).isNotNull();
diff --git 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Schema_IntegTest.schema.approved.json
 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Schema_IntegTest.schema.approved.json
index 2bd68359dc..88863d63a9 100644
--- 
a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Schema_IntegTest.schema.approved.json
+++ 
b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Schema_IntegTest.schema.approved.json
@@ -2713,6 +2713,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -4500,6 +4511,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invoke",
           "description" : null,
@@ -4991,6 +5013,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -5482,6 +5515,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -6300,6 +6344,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invoke",
           "description" : null,
@@ -12419,6 +12474,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invoke",
           "description" : null,
@@ -13669,6 +13735,43 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "leftConsumer",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_Consumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          }, {
+            "name" : "rightConsumer",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_Consumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -13798,6 +13901,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -13840,6 +13954,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "leftMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_Function__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -13895,6 +14033,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "rightMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_Function__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -13950,6 +14112,43 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "leftMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_Function__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          }, {
+            "name" : "rightMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_Function__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -14018,6 +14217,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -14157,6 +14367,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "chainingFunction",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -14368,7 +14602,7 @@
           "isDeprecated" : false,
           "deprecationReason" : null
         }, {
-          "name" : "invokeNonIdempotent",
+          "name" : "validate",
           "description" : null,
           "args" : [ {
             "name" : "failureConsumer",
@@ -14385,27 +14619,51 @@
             "defaultValue" : null
           } ],
           "type" : {
-            "kind" : "OBJECT",
-            "name" : "org_apache_causeway_commons_functional_Railway",
+            "kind" : "SCALAR",
+            "name" : "String",
             "ofType" : null
           },
           "isDeprecated" : false,
           "deprecationReason" : null
-        } ],
-        "inputFields" : null,
-        "interfaces" : [ ],
-        "enumValues" : null,
-        "possibleTypes" : null
-      }, {
-        "kind" : "OBJECT",
-        "name" : 
"org_apache_causeway_commons_functional_Railway__ifSuccess__gqlv_action",
-        "description" : null,
-        "fields" : [ {
-          "name" : "hidden",
+        }, {
+          "name" : "invokeNonIdempotent",
           "description" : null,
-          "args" : [ ],
-          "type" : {
-            "kind" : "SCALAR",
+          "args" : [ {
+            "name" : "failureConsumer",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "OBJECT",
+            "name" : "org_apache_causeway_commons_functional_Railway",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
+        } ],
+        "inputFields" : null,
+        "interfaces" : [ ],
+        "enumValues" : null,
+        "possibleTypes" : null
+      }, {
+        "kind" : "OBJECT",
+        "name" : 
"org_apache_causeway_commons_functional_Railway__ifSuccess__gqlv_action",
+        "description" : null,
+        "fields" : [ {
+          "name" : "hidden",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
             "name" : "Boolean",
             "ofType" : null
           },
@@ -14422,6 +14680,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "successConsumer",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -14477,6 +14759,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "failureMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -14532,6 +14838,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "successMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -14723,6 +15053,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "arg0",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_Consumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -14839,6 +15193,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "exceptionWrapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_BiFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -14947,6 +15325,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "arg0",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_Function__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -15002,6 +15404,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "arg0",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_Function__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -15118,6 +15544,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "exceptionWrapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_function_BiFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -15248,6 +15698,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -15351,6 +15812,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -15394,7 +15866,7 @@
           "isDeprecated" : false,
           "deprecationReason" : null
         }, {
-          "name" : "invokeNonIdempotent",
+          "name" : "validate",
           "description" : null,
           "args" : [ ],
           "type" : {
@@ -15404,10 +15876,21 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
-        } ],
-        "inputFields" : null,
-        "interfaces" : [ ],
-        "enumValues" : null,
+        }, {
+          "name" : "invokeNonIdempotent",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
+        } ],
+        "inputFields" : null,
+        "interfaces" : [ ],
+        "enumValues" : null,
         "possibleTypes" : null
       }, {
         "kind" : "OBJECT",
@@ -15435,6 +15918,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -15477,6 +15971,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -15792,6 +16297,43 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "failureConsumer",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          }, {
+            "name" : "successConsumer",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -15954,6 +16496,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "successMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16009,6 +16575,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "successMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16064,6 +16654,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "successMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16180,6 +16794,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16222,6 +16847,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16264,6 +16900,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "exceptionConsumer",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16319,6 +16979,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "valueConsumer",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16374,6 +17058,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "valueConsumer",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16429,6 +17137,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16471,6 +17190,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "recoveryMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16526,6 +17269,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "failureMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16581,6 +17348,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "successMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16636,6 +17427,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "successMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16691,6 +17506,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "successMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16746,6 +17585,43 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "failureMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          }, {
+            "name" : "successMapper",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16814,6 +17690,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "fallback",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_concurrent_Callable__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -16963,6 +17863,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "callable",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_concurrent_Callable__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -17018,6 +17942,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "runnable",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : 
"org_apache_causeway_commons_functional_ThrowingRunnable__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -17073,6 +18021,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "next",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "java_util_concurrent_Callable__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -17764,6 +18736,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -18128,6 +19111,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -18170,6 +19164,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -18601,6 +19606,39 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "name",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "SCALAR",
+                "name" : "String",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          }, {
+            "name" : "deptHead",
+            "description" : null,
+            "type" : {
+              "kind" : "INPUT_OBJECT",
+              "name" : "university_dept_DeptHead__gqlv_input",
+              "ofType" : null
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -18665,6 +19703,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invoke",
           "description" : null,
@@ -18711,6 +19760,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "name",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "SCALAR",
+                "name" : "String",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invoke",
           "description" : null,
@@ -18830,6 +19903,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "department",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "university_dept_Department__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeIdempotent",
           "description" : null,
@@ -18885,6 +19982,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "newName",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "SCALAR",
+                "name" : "String",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeIdempotent",
           "description" : null,
@@ -19207,6 +20328,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invoke",
           "description" : null,
@@ -19253,6 +20385,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "name",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "SCALAR",
+                "name" : "String",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invoke",
           "description" : null,
@@ -19640,6 +20796,43 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "name",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "SCALAR",
+                "name" : "String",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          }, {
+            "name" : "department",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "INPUT_OBJECT",
+                "name" : "university_dept_Department__gqlv_input",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invokeNonIdempotent",
           "description" : null,
@@ -19708,6 +20901,17 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invoke",
           "description" : null,
@@ -19754,6 +20958,30 @@
           },
           "isDeprecated" : false,
           "deprecationReason" : null
+        }, {
+          "name" : "validate",
+          "description" : null,
+          "args" : [ {
+            "name" : "name",
+            "description" : null,
+            "type" : {
+              "kind" : "NON_NULL",
+              "name" : null,
+              "ofType" : {
+                "kind" : "SCALAR",
+                "name" : "String",
+                "ofType" : null
+              }
+            },
+            "defaultValue" : null
+          } ],
+          "type" : {
+            "kind" : "SCALAR",
+            "name" : "String",
+            "ofType" : null
+          },
+          "isDeprecated" : false,
+          "deprecationReason" : null
         }, {
           "name" : "invoke",
           "description" : null,
diff --git a/incubator/viewers/graphql/test/src/test/resources/schema.gql 
b/incubator/viewers/graphql/test/src/test/resources/schema.gql
index b5c9311d12..a4cefa945e 100644
--- a/incubator/viewers/graphql/test/src/test/resources/schema.gql
+++ b/incubator/viewers/graphql/test/src/test/resources/schema.gql
@@ -205,6 +205,7 @@ type 
causeway_applib_PropertyNode__streamChildNodes__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: java_util_stream_Stream
+  validate: String
 }
 
 type causeway_applib_RoleMemento {
@@ -380,6 +381,7 @@ type causeway_applib_UserMenu__me__gqlv_action {
   disabled: String
   hidden: Boolean
   invoke: causeway_applib_UserMemento
+  validate: String
 }
 
 type causeway_applib_node_ActionNode {
@@ -429,6 +431,7 @@ type 
causeway_applib_node_ActionNode__streamChildNodes__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: java_util_stream_Stream
+  validate: String
 }
 
 type causeway_applib_node_CollectionNode {
@@ -478,6 +481,7 @@ type 
causeway_applib_node_CollectionNode__streamChildNodes__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: java_util_stream_Stream
+  validate: String
 }
 
 type causeway_applib_node_FacetAttrNode {
@@ -562,6 +566,7 @@ type 
causeway_conf_ConfigurationMenu__configuration__gqlv_action {
   disabled: String
   hidden: Boolean
   invoke: causeway_conf_ConfigurationViewmodel
+  validate: String
 }
 
 type causeway_conf_ConfigurationProperty {
@@ -1135,6 +1140,7 @@ type causeway_security_LogoutMenu__logout__gqlv_action {
   disabled: String
   hidden: Boolean
   invoke: String
+  validate: String
 }
 
 type causeway_testing_fixtures_FixtureResult {
@@ -1267,6 +1273,7 @@ type 
org_apache_causeway_commons_functional_Either__accept__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(leftConsumer: java_util_function_Consumer__gqlv_input!, 
rightConsumer: java_util_function_Consumer__gqlv_input!): String
+  validate(leftConsumer: java_util_function_Consumer__gqlv_input!, 
rightConsumer: java_util_function_Consumer__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Either__gqlv_meta {
@@ -1278,30 +1285,35 @@ type 
org_apache_causeway_commons_functional_Either__left__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: String
+  validate: String
 }
 
 type org_apache_causeway_commons_functional_Either__mapLeft__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(leftMapper: java_util_function_Function__gqlv_input!): 
org_apache_causeway_commons_functional_Either
+  validate(leftMapper: java_util_function_Function__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Either__mapRight__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(rightMapper: java_util_function_Function__gqlv_input!): 
org_apache_causeway_commons_functional_Either
+  validate(rightMapper: java_util_function_Function__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Either__map__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(leftMapper: java_util_function_Function__gqlv_input!, 
rightMapper: java_util_function_Function__gqlv_input!): 
org_apache_causeway_commons_functional_Either
+  validate(leftMapper: java_util_function_Function__gqlv_input!, rightMapper: 
java_util_function_Function__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Either__right__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: String
+  validate: String
 }
 
 type org_apache_causeway_commons_functional_Railway {
@@ -1319,6 +1331,7 @@ type 
org_apache_causeway_commons_functional_Railway__chain__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(chainingFunction: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Railway
+  validate(chainingFunction: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Railway__failure__gqlv_property {
@@ -1338,24 +1351,28 @@ type 
org_apache_causeway_commons_functional_Railway__ifFailure__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(failureConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): 
org_apache_causeway_commons_functional_Railway
+  validate(failureConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Railway__ifSuccess__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(successConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): 
org_apache_causeway_commons_functional_Railway
+  validate(successConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Railway__mapFailure__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(failureMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Railway
+  validate(failureMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Railway__mapSuccess__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Railway
+  validate(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Railway__success__gqlv_property {
@@ -1376,6 +1393,7 @@ type 
org_apache_causeway_commons_functional_ThrowingConsumer__andThen__gqlv_acti
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(arg0: java_util_function_Consumer__gqlv_input!): 
java_util_function_Consumer
+  validate(arg0: java_util_function_Consumer__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_meta {
@@ -1387,6 +1405,7 @@ type 
org_apache_causeway_commons_functional_ThrowingConsumer__throwing__gqlv_act
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(exceptionWrapper: 
java_util_function_BiFunction__gqlv_input!): 
org_apache_causeway_commons_functional_ThrowingConsumer
+  validate(exceptionWrapper: java_util_function_BiFunction__gqlv_input!): 
String
 }
 
 type org_apache_causeway_commons_functional_ThrowingFunction {
@@ -1400,12 +1419,14 @@ type 
org_apache_causeway_commons_functional_ThrowingFunction__andThen__gqlv_acti
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(arg0: java_util_function_Function__gqlv_input!): 
java_util_function_Function
+  validate(arg0: java_util_function_Function__gqlv_input!): String
 }
 
 type 
org_apache_causeway_commons_functional_ThrowingFunction__compose__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(arg0: java_util_function_Function__gqlv_input!): 
java_util_function_Function
+  validate(arg0: java_util_function_Function__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_ThrowingFunction__gqlv_meta {
@@ -1417,6 +1438,7 @@ type 
org_apache_causeway_commons_functional_ThrowingFunction__throwing__gqlv_act
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(exceptionWrapper: 
java_util_function_BiFunction__gqlv_input!): 
org_apache_causeway_commons_functional_ThrowingFunction
+  validate(exceptionWrapper: java_util_function_BiFunction__gqlv_input!): 
String
 }
 
 type org_apache_causeway_commons_functional_ThrowingRunnable {
@@ -1432,6 +1454,7 @@ type 
org_apache_causeway_commons_functional_ThrowingRunnable__callUncatched__gql
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: String
+  validate: String
 }
 
 type org_apache_causeway_commons_functional_ThrowingRunnable__gqlv_meta {
@@ -1443,24 +1466,28 @@ type 
org_apache_causeway_commons_functional_ThrowingRunnable__runUncatched__gqlv
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: String
+  validate: String
 }
 
 type org_apache_causeway_commons_functional_ThrowingRunnable__run__gqlv_action 
{
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: String
+  validate: String
 }
 
 type 
org_apache_causeway_commons_functional_ThrowingRunnable__toCallable__gqlv_action
 {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: java_util_concurrent_Callable
+  validate: String
 }
 
 type 
org_apache_causeway_commons_functional_ThrowingRunnable__toRunnable__gqlv_action
 {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: java_lang_Runnable
+  validate: String
 }
 
 type org_apache_causeway_commons_functional_Try {
@@ -1494,6 +1521,7 @@ type 
org_apache_causeway_commons_functional_Try__accept__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(failureConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!, 
successConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(failureConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!, 
successConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__failure__gqlv_property {
@@ -1508,18 +1536,21 @@ type 
org_apache_causeway_commons_functional_Try__flatMapSuccessAsNullable__gqlv_
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type 
org_apache_causeway_commons_functional_Try__flatMapSuccessWhenPresent__gqlv_action
 {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__flatMapSuccess__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__gqlv_meta {
@@ -1531,78 +1562,91 @@ type 
org_apache_causeway_commons_functional_Try__ifAbsentFail__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: org_apache_causeway_commons_functional_Try
+  validate: String
 }
 
 type org_apache_causeway_commons_functional_Try__ifFailureFail__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: org_apache_causeway_commons_functional_Try
+  validate: String
 }
 
 type org_apache_causeway_commons_functional_Try__ifFailure__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(exceptionConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(exceptionConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): String
 }
 
 type 
org_apache_causeway_commons_functional_Try__ifSuccessAsNullable__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(valueConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(valueConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__ifSuccess__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(valueConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(valueConsumer: 
org_apache_causeway_commons_functional_ThrowingConsumer__gqlv_input!): String
 }
 
 type 
org_apache_causeway_commons_functional_Try__mapEmptyToFailure__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: org_apache_causeway_commons_functional_Try
+  validate: String
 }
 
 type 
org_apache_causeway_commons_functional_Try__mapFailureToSuccess__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(recoveryMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(recoveryMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__mapFailure__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(failureMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(failureMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type 
org_apache_causeway_commons_functional_Try__mapSuccessAsNullable__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type 
org_apache_causeway_commons_functional_Try__mapSuccessWhenPresent__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__mapSuccess__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__mapToEither__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(failureMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!, 
successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): 
org_apache_causeway_commons_functional_Either
+  validate(failureMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!, 
successMapper: 
org_apache_causeway_commons_functional_ThrowingFunction__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__orCall__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(fallback: java_util_concurrent_Callable__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(fallback: java_util_concurrent_Callable__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__success__gqlv_property {
@@ -1617,18 +1661,21 @@ type 
org_apache_causeway_commons_functional_Try__thenCall__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(callable: java_util_concurrent_Callable__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(callable: java_util_concurrent_Callable__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__thenRun__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(runnable: 
org_apache_causeway_commons_functional_ThrowingRunnable__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(runnable: 
org_apache_causeway_commons_functional_ThrowingRunnable__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__then__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(next: java_util_concurrent_Callable__gqlv_input!): 
org_apache_causeway_commons_functional_Try
+  validate(next: java_util_concurrent_Callable__gqlv_input!): String
 }
 
 type org_apache_causeway_commons_functional_Try__value__gqlv_property {
@@ -1699,6 +1746,7 @@ type 
org_apache_causeway_core_metamodel_inspect_model_MemberNode__streamChildNod
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: java_util_stream_Stream
+  validate: String
 }
 
 type org_apache_causeway_testing_fixtures_applib_fixturescripts_FixtureScript {
@@ -1737,12 +1785,14 @@ type 
university_admin_AdminMenu__adminAction__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: String
+  validate: String
 }
 
 type university_admin_AdminMenu__otherAdminAction__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent: String
+  validate: String
 }
 
 type university_dept_Department {
@@ -1790,18 +1840,21 @@ type 
university_dept_Departments__createDepartment__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(deptHead: university_dept_DeptHead__gqlv_input, name: 
String!): university_dept_Department
+  validate(deptHead: university_dept_DeptHead__gqlv_input, name: String!): 
String
 }
 
 type university_dept_Departments__findAllDepartments__gqlv_action {
   disabled: String
   hidden: Boolean
   invoke: [university_dept_Department]
+  validate: String
 }
 
 type university_dept_Departments__findByName__gqlv_action {
   disabled: String
   hidden: Boolean
   invoke(name: String!): university_dept_Department
+  validate(name: String!): String
 }
 
 type university_dept_DeptHead {
@@ -1816,12 +1869,14 @@ type 
university_dept_DeptHead__changeDepartment__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeIdempotent(department: university_dept_Department__gqlv_input!): 
university_dept_DeptHead
+  validate(department: university_dept_Department__gqlv_input!): String
 }
 
 type university_dept_DeptHead__changeName__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeIdempotent(newName: String!): university_dept_DeptHead
+  validate(newName: String!): String
 }
 
 type university_dept_DeptHead__department__gqlv_property {
@@ -1855,12 +1910,14 @@ type 
university_dept_DeptHeads__findAllHeads__gqlv_action {
   disabled: String
   hidden: Boolean
   invoke: [university_dept_DeptHead]
+  validate: String
 }
 
 type university_dept_DeptHeads__findHeadByName__gqlv_action {
   disabled: String
   hidden: Boolean
   invoke(name: String!): university_dept_DeptHead
+  validate(name: String!): String
 }
 
 type university_dept_Staff {
@@ -1901,18 +1958,21 @@ type 
university_dept_Staff__createStaffMember__gqlv_action {
   disabled: String
   hidden: Boolean
   invokeNonIdempotent(department: university_dept_Department__gqlv_input!, 
name: String!): university_dept_StaffMember
+  validate(department: university_dept_Department__gqlv_input!, name: 
String!): String
 }
 
 type university_dept_Staff__findAllStaffMembers__gqlv_action {
   disabled: String
   hidden: Boolean
   invoke: [university_dept_StaffMember]
+  validate: String
 }
 
 type university_dept_Staff__findByName__gqlv_action {
   disabled: String
   hidden: Boolean
   invoke(name: String!): university_dept_StaffMember
+  validate(name: String!): String
 }
 
 input causeway_applib_DomainObjectList__gqlv_input {


Reply via email to