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

commit 7808d881e84b0c42cf2336346db8741a76736864
Author: danhaywood <[email protected]>
AuthorDate: Mon Feb 12 17:32:23 2024 +0000

    CAUSEWAY-3676: introduces GqlvAbstract and GqlvAbstractCustom
---
 .../{GqlvPropertyGet.java => GqlvAbstract.java}    | 34 ++++----
 .../graphql/model/domain/GqlvAbstractCustom.java   | 97 ++++++++++++++++++++++
 .../viewer/graphql/model/domain/GqlvAction.java    | 29 +------
 .../graphql/model/domain/GqlvActionInvoke.java     | 22 +++--
 .../graphql/model/domain/GqlvActionParam.java      | 13 +--
 .../model/domain/GqlvActionParamAutoComplete.java  |  5 +-
 .../model/domain/GqlvActionParamChoices.java       |  5 +-
 .../model/domain/GqlvActionParamDefault.java       |  5 +-
 .../model/domain/GqlvActionParamDisabled.java      |  5 +-
 .../model/domain/GqlvActionParamHidden.java        |  5 +-
 .../model/domain/GqlvActionParamValidate.java      | 11 +--
 .../graphql/model/domain/GqlvActionParams.java     | 44 ++--------
 .../graphql/model/domain/GqlvActionValidity.java   | 12 ++-
 .../graphql/model/domain/GqlvAssociation.java      |  7 +-
 .../graphql/model/domain/GqlvAssociationGet.java   | 14 ++--
 .../graphql/model/domain/GqlvCollection.java       | 29 +------
 .../graphql/model/domain/GqlvDomainObject.java     | 38 ++-------
 .../graphql/model/domain/GqlvDomainService.java    | 13 +--
 .../viewer/graphql/model/domain/GqlvMember.java    | 18 ++--
 .../graphql/model/domain/GqlvMemberDisabled.java   | 14 ++--
 .../graphql/model/domain/GqlvMemberHidden.java     | 12 ++-
 .../viewer/graphql/model/domain/GqlvMeta.java      | 35 +++-----
 .../model/domain/GqlvMutationForAction.java        | 17 ++--
 .../model/domain/GqlvMutationForProperty.java      | 23 +++--
 .../viewer/graphql/model/domain/GqlvProperty.java  | 28 +------
 .../model/domain/GqlvPropertyAutoComplete.java     | 19 ++---
 .../graphql/model/domain/GqlvPropertyChoices.java  | 20 ++---
 .../graphql/model/domain/GqlvPropertyGet.java      |  2 +-
 .../graphql/model/domain/GqlvPropertySet.java      | 13 ++-
 .../graphql/model/domain/GqlvPropertyValidate.java | 10 +--
 .../viewer/graphql/model/domain/GqlvScenario.java  | 35 ++------
 .../graphql/model/domain/GqlvScenarioGiven.java    | 32 ++-----
 .../graphql/model/domain/GqlvScenarioName.java     | 19 +++--
 .../graphql/model/toplevel/GqlvTopLevelQuery.java  |  4 +-
 34 files changed, 280 insertions(+), 409 deletions(-)

diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyGet.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAbstract.java
similarity index 58%
copy from 
viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyGet.java
copy to 
viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAbstract.java
index 0fd8531258..d45584019e 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyGet.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAbstract.java
@@ -18,30 +18,32 @@
  */
 package org.apache.causeway.viewer.graphql.model.domain;
 
+import graphql.schema.FieldCoordinates;
+import graphql.schema.GraphQLFieldDefinition;
+import graphql.schema.GraphQLObjectType;
 import graphql.schema.GraphQLOutputType;
 
-import org.apache.causeway.core.metamodel.spec.feature.OneToOneAssociation;
+import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
+
 import org.apache.causeway.viewer.graphql.model.context.Context;
 
-import lombok.val;
+import lombok.AccessLevel;
+import lombok.Getter;
 
-public class GqlvPropertyGet  extends GqlvAssociationGet<OneToOneAssociation> {
+public abstract class GqlvAbstract {
 
-    public GqlvPropertyGet(
-            final Holder holder,
-            final Context context) {
-        super(holder, context);
-    }
+    protected final Context context;
 
-    @Override
-    GraphQLOutputType 
outputTypeFor(GqlvAssociationGet.Holder<OneToOneAssociation> holder) {
-        val oneToOneAssociation = holder.getObjectAssociation();
-        return context.typeMapper.outputTypeFor(oneToOneAssociation);
-    }
+    @Getter
+    private GraphQLFieldDefinition field;
 
-    public interface Holder extends 
GqlvAssociationGet.Holder<OneToOneAssociation> {
+    protected GqlvAbstract(final Context context) {
+        this.context = context;
+    }
 
-        @Override
-        OneToOneAssociation getObjectAssociation();
+    protected final GraphQLFieldDefinition setField(GraphQLFieldDefinition 
field) {
+        this.field = field;
+        return field;
     }
+
 }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAbstractCustom.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAbstractCustom.java
new file mode 100644
index 0000000000..eef7fb1b9a
--- /dev/null
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAbstractCustom.java
@@ -0,0 +1,97 @@
+/*
+ *  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 graphql.schema.FieldCoordinates;
+import graphql.schema.GraphQLFieldDefinition;
+import graphql.schema.GraphQLObjectType;
+
+import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
+import static graphql.schema.GraphQLObjectType.newObject;
+
+import org.apache.causeway.viewer.graphql.model.context.Context;
+
+import graphql.schema.GraphQLOutputType;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.val;
+
+public abstract class GqlvAbstractCustom extends GqlvAbstract implements 
GqlvHolder {
+
+    protected final GraphQLObjectType.Builder gqlObjectTypeBuilder;
+
+    @Getter(AccessLevel.PROTECTED)
+    private GraphQLObjectType gqlObjectType;
+
+    @Getter
+    protected GraphQLFieldDefinition field;
+
+    protected GqlvAbstractCustom(
+            final GraphQLObjectType.Builder gqlObjectTypeBuilder,
+            final Context context) {
+        super(context);
+
+        this.gqlObjectTypeBuilder = gqlObjectTypeBuilder;
+    }
+
+    protected final GraphQLFieldDefinition field(GraphQLFieldDefinition field) 
{
+        if (this.gqlObjectType != null) {
+            throw new IllegalStateException("GqlObjectType has already been 
created");
+        }
+
+        if (field != null) {
+            gqlObjectTypeBuilder.field(field);
+        }
+        return field;
+    }
+
+    protected final GraphQLFieldDefinition addField(GraphQLFieldDefinition 
childField) {
+        if (this.gqlObjectType != null) {
+            throw new IllegalStateException("GqlObjectType has already been 
created");
+        }
+
+        if (childField != null) {
+            gqlObjectTypeBuilder.field(childField);
+        }
+        return childField;
+    }
+
+    protected GraphQLFieldDefinition buildObjectTypeAndSetFieldName(String 
fieldName) {
+        val graphQLObjectType = buildObjectType();
+
+        return setField(newFieldDefinition()
+                .name(fieldName)
+                .type(graphQLObjectType)
+                .build());
+    }
+
+    protected final GraphQLObjectType buildObjectType() {
+        this.gqlObjectType = gqlObjectTypeBuilder.build();
+        
context.graphQLTypeRegistry.addTypeIfNotAlreadyPresent(this.gqlObjectType);
+        return this.gqlObjectType;
+
+    }
+
+
+    public final FieldCoordinates coordinatesFor(final GraphQLFieldDefinition 
field) {
+        return FieldCoordinates.coordinates(gqlObjectType, field);
+    }
+
+}
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
index cf6f34c507..bf897074f7 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
@@ -27,7 +27,6 @@ import graphql.schema.DataFetchingEnvironment;
 import graphql.schema.FieldCoordinates;
 import graphql.schema.GraphQLArgument;
 import graphql.schema.GraphQLFieldDefinition;
-import graphql.schema.GraphQLObjectType;
 
 import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
 import static graphql.schema.GraphQLObjectType.newObject;
@@ -59,9 +58,6 @@ public class GqlvAction
                    GqlvActionValidity.Holder,
                    GqlvActionParams.Holder {
 
-    private final GraphQLObjectType.Builder gqlObjectTypeBuilder;
-    private final GraphQLObjectType gqlObjectType;
-
     private final GqlvMemberHidden<ObjectAction> hidden;
     private final GqlvMemberDisabled<ObjectAction> disabled;
     private final GqlvActionValidity validate;
@@ -78,14 +74,14 @@ public class GqlvAction
             final Holder holder,
             final ObjectAction objectAction,
             final Context context) {
-        super(holder, objectAction, context);
-
-        this.gqlObjectTypeBuilder = 
newObject().name(TypeNames.actionTypeNameFor(holder.getObjectSpecification(), 
objectAction));
+        super(holder, objectAction, 
newObject().name(TypeNames.actionTypeNameFor(holder.getObjectSpecification(), 
objectAction)), context);
 
         this.hidden = new GqlvMemberHidden<>(this, context);
         addField(hidden.getField());
+
         this.disabled = new GqlvMemberDisabled<>(this, context);
         addField(disabled.getField());
+
         this.validate = new GqlvActionValidity(this, context);
         addField(validate.getField());
 
@@ -107,12 +103,7 @@ public class GqlvAction
             this.params = null;
         }
 
-        this.gqlObjectType = gqlObjectTypeBuilder.build();
-
-        this.field = newFieldDefinition()
-                .name(objectAction.getId())
-                .type(gqlObjectTypeBuilder)
-                .build();
+        buildObjectTypeAndSetFieldName(objectAction.getId());
     }
 
     public Can<ManagedObject> argumentManagedObjectsFor(
@@ -258,13 +249,6 @@ public class GqlvAction
         return getObjectMember();
     }
 
-    private GraphQLFieldDefinition addField(GraphQLFieldDefinition field) {
-        if (field != null) {
-            gqlObjectTypeBuilder.field(field);
-        }
-        return field;
-    }
-
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
                 holder.coordinatesFor(getField()),
@@ -282,11 +266,6 @@ public class GqlvAction
     }
 
 
-    @Override
-    public FieldCoordinates coordinatesFor(GraphQLFieldDefinition 
fieldDefinition) {
-        return FieldCoordinates.coordinates(gqlObjectType, fieldDefinition);
-    }
-
     public interface Holder extends GqlvMember.Holder {
     }
 }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
index 0b004088dc..183ef0bf6c 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvoke.java
@@ -44,34 +44,32 @@ import 
org.apache.causeway.viewer.graphql.model.fetcher.BookmarkedPojo;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectActionProvider;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationProvider;
 
-import lombok.Getter;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class GqlvActionInvoke {
+public class GqlvActionInvoke extends GqlvAbstract {
 
     private final Holder holder;
-    private final Context context;
-    @Getter private final GraphQLFieldDefinition field;
 
     public GqlvActionInvoke(
             final Holder holder,
             final Context context) {
+        super(context);
+
         this.holder = holder;
-        this.context = context;
 
         val objectAction = holder.getObjectAction();
 
-        GraphQLOutputType type = typeFor(objectAction);
-        if (type != null) {
+        val graphQLOutputType = typeFor(objectAction);
+        if (graphQLOutputType != null) {
             val fieldBuilder = newFieldDefinition()
                     .name(fieldNameForSemanticsOf(objectAction))
-                    .type(type);
+                    .type(graphQLOutputType);
             holder.addGqlArguments(objectAction, fieldBuilder, 
TypeMapper.InputContext.INVOKE, objectAction.getParameterCount());
-            this.field = fieldBuilder.build();
+            setField(fieldBuilder.build());
         } else {
-            this.field = null;
+            setField(null);
         }
     }
 
@@ -93,7 +91,7 @@ public class GqlvActionInvoke {
 
     @Nullable
     private GraphQLOutputType typeFor(final ObjectAction objectAction){
-        ObjectSpecification objectSpecification = objectAction.getReturnType();
+        val objectSpecification = objectAction.getReturnType();
         switch (objectSpecification.getBeanSort()){
 
             case COLLECTION:
@@ -124,7 +122,7 @@ public class GqlvActionInvoke {
 
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
-                holder.coordinatesFor(field),
+                holder.coordinatesFor(getField()),
                 this::invoke
         );
     }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParam.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParam.java
index d1c1dd27ab..066f373ade 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParam.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParam.java
@@ -44,6 +44,7 @@ import lombok.extern.log4j.Log4j2;
 
 @Log4j2
 public class GqlvActionParam
+        extends GqlvAbstractCustom
         implements GqlvActionParamHidden.Holder,
                    GqlvActionParamDisabled.Holder,
                    GqlvActionParamChoices.Holder,
@@ -53,10 +54,8 @@ public class GqlvActionParam
 
     @Getter private final Holder holder;
     @Getter private final ObjectActionParameter objectActionParameter;
-    private final Context context;
     @Getter private final int paramNum;
 
-    private final GraphQLObjectType.Builder gqlObjectTypeBuilder;
     private final GraphQLObjectType gqlObjectType;
 
     private final GqlvActionParamHidden hidden;
@@ -82,11 +81,10 @@ public class GqlvActionParam
             final ObjectActionParameter objectActionParameter,
             final Context context,
             final int paramNum) {
+        
super(newObject().name(TypeNames.actionParamTypeNameFor(holder.getObjectSpecification(),
 objectActionParameter)), context);
         this.holder = holder;
         this.objectActionParameter = objectActionParameter;
-        this.context = context;
         this.paramNum = paramNum;
-        this.gqlObjectTypeBuilder = 
newObject().name(TypeNames.actionParamTypeNameFor(holder.getObjectSpecification(),
 objectActionParameter));
 
         this.hidden = new GqlvActionParamHidden(this, context);
         addField(hidden.getField());
@@ -143,13 +141,6 @@ public class GqlvActionParam
         return holder.getObjectAction();
     }
 
-    private GraphQLFieldDefinition addField(GraphQLFieldDefinition field) {
-        if (field != null) {
-            gqlObjectTypeBuilder.field(field);
-        }
-        return field;
-    }
-
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
                 holder.coordinatesFor(field),
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamAutoComplete.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamAutoComplete.java
index f9adb7bbbd..01fb258175 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamAutoComplete.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamAutoComplete.java
@@ -50,12 +50,11 @@ package org.apache.causeway.viewer.graphql.model.domain;
  import lombok.extern.log4j.Log4j2;
 
  @Log4j2
- public class GqlvActionParamAutoComplete {
+ public class GqlvActionParamAutoComplete extends GqlvAbstract {
 
      private static final String SEARCH_PARAM_NAME = "search";
 
      private final Holder holder;
-     private final Context context;
 
      /**
       * Populated iff there is an autocomplete for this parameter.
@@ -65,8 +64,8 @@ package org.apache.causeway.viewer.graphql.model.domain;
      public GqlvActionParamAutoComplete(
              final Holder holder,
              final Context context) {
+         super(context);
          this.holder = holder;
-         this.context = context;
 
          val objectActionParameter = holder.getObjectActionParameter();
          if (objectActionParameter.hasAutoComplete()) {
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamChoices.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamChoices.java
index 68066bcc3f..5431091a4b 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamChoices.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamChoices.java
@@ -48,10 +48,9 @@ package org.apache.causeway.viewer.graphql.model.domain;
  import lombok.extern.log4j.Log4j2;
 
  @Log4j2
- public class GqlvActionParamChoices {
+ public class GqlvActionParamChoices extends GqlvAbstract {
 
      private final Holder holder;
-     private final Context context;
 
      /**
       * Populated iff there are choices for this parameter.
@@ -61,8 +60,8 @@ package org.apache.causeway.viewer.graphql.model.domain;
      public GqlvActionParamChoices(
              final Holder holder,
              final Context context) {
+         super(context);
          this.holder = holder;
-         this.context = context;
 
          val objectActionParameter = holder.getObjectActionParameter();
          if (objectActionParameter.hasChoices()) {
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDefault.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDefault.java
index 4d76b79dd2..4f70a3d0c8 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDefault.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDefault.java
@@ -44,10 +44,9 @@ package org.apache.causeway.viewer.graphql.model.domain;
  import lombok.extern.log4j.Log4j2;
 
  @Log4j2
- public class GqlvActionParamDefault {
+ public class GqlvActionParamDefault extends GqlvAbstract {
 
      private final Holder holder;
-     private final Context context;
 
      /**
       * Populated iff there are choices for this parameter.
@@ -57,8 +56,8 @@ package org.apache.causeway.viewer.graphql.model.domain;
      public GqlvActionParamDefault(
              final Holder holder,
              final Context context) {
+         super(context);
          this.holder = holder;
-         this.context = context;
 
          val objectActionParameter = holder.getObjectActionParameter();
 
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDisabled.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDisabled.java
index e3662dfd1d..fbf40b3bdf 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDisabled.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDisabled.java
@@ -41,18 +41,17 @@ import lombok.extern.log4j.Log4j2;
 
 
 @Log4j2
-public class GqlvActionParamDisabled {
+public class GqlvActionParamDisabled extends GqlvAbstract {
 
     private final Holder holder;
-    private final Context context;
 
     @Getter private final GraphQLFieldDefinition field;
 
     public GqlvActionParamDisabled(
             final Holder holder,
             final Context context) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
         val fieldBuilder = newFieldDefinition()
                 .name("disabled")
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamHidden.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamHidden.java
index 7ef7359fa5..ede4dac1cb 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamHidden.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamHidden.java
@@ -40,18 +40,17 @@ package org.apache.causeway.viewer.graphql.model.domain;
  import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class GqlvActionParamHidden {
+public class GqlvActionParamHidden extends GqlvAbstract {
 
     private final Holder holder;
-    private final Context context;
 
     @Getter private final GraphQLFieldDefinition field;
 
     public GqlvActionParamHidden(
             final Holder holder,
             final Context context) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
         GraphQLFieldDefinition.Builder fieldBuilder = newFieldDefinition()
                 .name("hidden")
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamValidate.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamValidate.java
index 04aa28c81c..3aab19e087 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamValidate.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamValidate.java
@@ -40,30 +40,27 @@ import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class GqlvActionParamValidate {
+public class GqlvActionParamValidate extends GqlvAbstract {
 
     private final Holder holder;
-    private final Context context;
-
-    @Getter private final GraphQLFieldDefinition field;
 
     public GqlvActionParamValidate(
             final Holder holder,
             final Context context) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
         val fieldBuilder = newFieldDefinition()
                 .name("validity")
                 .type(context.typeMapper.scalarTypeFor(String.class));
         holder.addGqlArgument(holder.getObjectAction(), fieldBuilder, 
TypeMapper.InputContext.DISABLE, holder.getParamNum());
-        this.field = fieldBuilder.build();
+        setField(fieldBuilder.build());
     }
 
 
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
-                holder.coordinatesFor(field),
+                holder.coordinatesFor(getField()),
                 this::disabled
         );
     }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParams.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParams.java
index 7f864793c4..71938eacec 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParams.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParams.java
@@ -23,11 +23,8 @@ import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import graphql.schema.DataFetchingEnvironment;
-import graphql.schema.FieldCoordinates;
 import graphql.schema.GraphQLFieldDefinition;
-import graphql.schema.GraphQLObjectType;
 
-import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
 import static graphql.schema.GraphQLObjectType.newObject;
 
 import org.apache.causeway.applib.services.bookmark.BookmarkService;
@@ -36,52 +33,39 @@ 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.viewer.graphql.model.types.TypeMapper;
 import org.apache.causeway.viewer.graphql.model.context.Context;
 import org.apache.causeway.viewer.graphql.model.fetcher.BookmarkedPojoFetcher;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectActionProvider;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationProvider;
+import org.apache.causeway.viewer.graphql.model.types.TypeMapper;
 
 import lombok.Getter;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class GqlvActionParams implements GqlvActionParam.Holder {
+public class GqlvActionParams
+        extends GqlvAbstractCustom
+        implements GqlvActionParam.Holder {
 
     @Getter private final Holder holder;
-    private final Context context;
-
-    private final GraphQLObjectType.Builder gqlObjectTypeBuilder;
-    private final GraphQLObjectType gqlObjectType;
-
-    /**
-     * Populated iff {@link #hasParams()}
-     */
-    @Getter private final GraphQLFieldDefinition field;
 
     private final Map<String, GqlvActionParam> params = new LinkedHashMap<>();
 
     public GqlvActionParams(
             final Holder holder,
             final Context context) {
+        
super(newObject().name(TypeNames.actionParamsTypeNameFor(holder.getObjectSpecification(),
 holder.getObjectAction())), context);
         this.holder = holder;
-        this.context = context;
-        this.gqlObjectTypeBuilder = 
newObject().name(TypeNames.actionParamsTypeNameFor(holder.getObjectSpecification(),
 holder.getObjectAction()));
 
         val idx = new AtomicInteger(0);
         holder.getObjectAction().getParameters().forEach(objectActionParameter 
-> {
             addParam(objectActionParameter, idx.getAndIncrement());
         });
 
-        this.gqlObjectType = gqlObjectTypeBuilder.build();
-
-        this.field = hasParams() ?
-                newFieldDefinition()
-                    .name("params")
-                    .type(gqlObjectTypeBuilder)
-                    .build()
-                : null;
+        if (hasParams()) {
+            buildObjectTypeAndSetFieldName("params");
+        }
     }
 
     @Override
@@ -110,13 +94,6 @@ public class GqlvActionParams implements 
GqlvActionParam.Holder {
     }
 
 
-    private GraphQLFieldDefinition addField(GraphQLFieldDefinition field) {
-        if (field != null) {
-            gqlObjectTypeBuilder.field(field);
-        }
-        return field;
-    }
-
     void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
                 holder.coordinatesFor(field),
@@ -126,11 +103,6 @@ public class GqlvActionParams implements 
GqlvActionParam.Holder {
     }
 
 
-    @Override
-    public FieldCoordinates coordinatesFor(GraphQLFieldDefinition 
fieldDefinition) {
-        return FieldCoordinates.coordinates(gqlObjectType, fieldDefinition);
-    }
-
     @Override
     public void addGqlArguments(
             ObjectAction objectAction, GraphQLFieldDefinition.Builder 
fieldBuilder, TypeMapper.InputContext inputContext, int paramNum) {
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidity.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidity.java
index bb03187654..945aecdbc9 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidity.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionValidity.java
@@ -43,18 +43,16 @@ import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class GqlvActionValidity {
+public class GqlvActionValidity extends GqlvAbstract {
 
     private final Holder holder;
-    private final Context context;
-    @Getter private final GraphQLFieldDefinition field;
 
     public GqlvActionValidity(
             final Holder holder,
             final Context context
     ) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
         val objectAction = holder.getObjectAction();
 
@@ -65,15 +63,15 @@ public class GqlvActionValidity {
                     .type(type);
 
             holder.addGqlArguments(objectAction, fieldBuilder, 
TypeMapper.InputContext.VALIDATE, objectAction.getParameterCount());
-            this.field = fieldBuilder.build();
+            setField(fieldBuilder.build());
         } else {
-            this.field = null;
+            setField(null);
         }
     }
 
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
-                holder.coordinatesFor(field),
+                holder.coordinatesFor(getField()),
                 this::validate
         );
     }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAssociation.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAssociation.java
index 5d84037e74..fc85648db7 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAssociation.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAssociation.java
@@ -19,6 +19,7 @@
 package org.apache.causeway.viewer.graphql.model.domain;
 
 import graphql.schema.GraphQLFieldDefinition;
+import graphql.schema.GraphQLObjectType;
 
 import org.apache.causeway.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.causeway.viewer.graphql.model.context.Context;
@@ -28,16 +29,18 @@ public abstract class GqlvAssociation<T extends 
ObjectAssociation, H extends Gql
     public GqlvAssociation(
             final H holder,
             final T objectAssociation,
+            final GraphQLObjectType.Builder gqlObjectTypeBuilder,
             final Context context) {
-        this(holder, objectAssociation, null, context);
+        this(holder, objectAssociation, gqlObjectTypeBuilder, null, context);
     }
 
     public GqlvAssociation(
             final H holder,
             final T objectAssociation,
+            final GraphQLObjectType.Builder gqlObjectTypeBuilder,
             final GraphQLFieldDefinition fieldDefinition,
             final Context context) {
-        super(holder, objectAssociation, fieldDefinition, context);
+        super(holder, objectAssociation, gqlObjectTypeBuilder, 
fieldDefinition, context);
     }
 
     public boolean hasFieldDefinition() {
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAssociationGet.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAssociationGet.java
index 743e6ad346..35ccd1814a 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAssociationGet.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAssociationGet.java
@@ -19,7 +19,6 @@
 package org.apache.causeway.viewer.graphql.model.domain;
 
 import graphql.schema.DataFetchingEnvironment;
-import graphql.schema.GraphQLFieldDefinition;
 import graphql.schema.GraphQLOutputType;
 
 import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
@@ -31,29 +30,26 @@ import 
org.apache.causeway.viewer.graphql.model.fetcher.BookmarkedPojo;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectAssociationProvider;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationProvider;
 
-import lombok.Getter;
 import lombok.val;
 
-public abstract class GqlvAssociationGet<T extends ObjectAssociation> {
+public abstract class GqlvAssociationGet<T extends ObjectAssociation> extends 
GqlvAbstract {
 
     final Holder<T> holder;
-    final Context context;
-    @Getter final GraphQLFieldDefinition field;
 
     public GqlvAssociationGet(
             final Holder<T> holder,
             final Context context) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
         GraphQLOutputType type = outputTypeFor(holder);
         if (type != null) {
             val fieldBuilder = newFieldDefinition()
                     .name("get")
                     .type(type);
-            this.field = fieldBuilder.build();
+            setField(fieldBuilder.build());
         } else {
-            this.field = null;
+            setField(null);
         }
     }
 
@@ -72,7 +68,7 @@ public abstract class GqlvAssociationGet<T extends 
ObjectAssociation> {
             case ENTITY:
 
                 context.codeRegistryBuilder.dataFetcher(
-                        holder.coordinatesFor(field),
+                        holder.coordinatesFor(getField()),
                         this::get);
 
                 break;
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvCollection.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvCollection.java
index ca5ece1651..5d8c1e8096 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvCollection.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvCollection.java
@@ -36,19 +36,15 @@ public class GqlvCollection
                    GqlvMemberHidden.Holder<OneToManyAssociation>,
                    GqlvMemberDisabled.Holder<OneToManyAssociation> {
 
-    private final GraphQLObjectType.Builder gqlObjectTypeBuilder;
-    private final GraphQLObjectType gqlObjectType;
     private final GqlvMemberHidden<OneToManyAssociation> hidden;
     private final GqlvMemberDisabled<OneToManyAssociation> disabled;
     private final GqlvCollectionGet get;
 
     public GqlvCollection(
-            final Holder domainObject,
+            final Holder holder,
             final OneToManyAssociation oneToManyAssociation,
             final Context context) {
-        super(domainObject, oneToManyAssociation, context);
-
-        this.gqlObjectTypeBuilder = 
newObject().name(TypeNames.collectionTypeNameFor(holder.getObjectSpecification(),
 oneToManyAssociation));
+        super(holder, oneToManyAssociation, 
newObject().name(TypeNames.collectionTypeNameFor(holder.getObjectSpecification(),
 oneToManyAssociation)), context);
 
         this.hidden = new GqlvMemberHidden<>(this, context);
         addField(hidden.getField());
@@ -57,14 +53,7 @@ public class GqlvCollection
         this.get = new GqlvCollectionGet(this, context);
         addField(get.getField());
 
-        this.gqlObjectType = gqlObjectTypeBuilder.build();
-
-        setField(
-            newFieldDefinition()
-                .name(oneToManyAssociation.getId())
-                .type(gqlObjectTypeBuilder)
-                .build()
-        );
+        buildObjectTypeAndSetFieldName(oneToManyAssociation.getId());
     }
 
     @Override
@@ -76,13 +65,6 @@ public class GqlvCollection
         return getObjectAssociation();
     }
 
-    private GraphQLFieldDefinition addField(GraphQLFieldDefinition field) {
-        if (field != null) {
-            gqlObjectTypeBuilder.field(field);
-        }
-        return field;
-    }
-
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
                 holder.coordinatesFor(getField()),
@@ -93,11 +75,6 @@ public class GqlvCollection
         get.addDataFetcher();
     }
 
-    @Override
-    public FieldCoordinates coordinatesFor(GraphQLFieldDefinition 
fieldDefinition) {
-        return FieldCoordinates.coordinates(gqlObjectType, fieldDefinition);
-    }
-
     public interface Holder extends GqlvAssociation.Holder {
 
     }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
index 3079192058..6aa6c8e2c6 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
@@ -52,47 +52,33 @@ import lombok.val;
  * Exposes a domain object (view model or entity) via the GQL viewer.
  */
 public class GqlvDomainObject
+        extends GqlvAbstractCustom
         implements GqlvAction.Holder, GqlvProperty.Holder, 
GqlvCollection.Holder, GqlvMeta.Holder {
 
     @Getter private final ObjectSpecification objectSpecification;
 
     private final Holder holder;
-    private final Context context;
 
     @Getter
     private final GraphQLFieldDefinition lookupField;
 
     private final GqlvMeta meta;
 
-    private final GraphQLObjectType.Builder gqlObjectTypeBuilder;
-
     private final SortedMap<String, GqlvProperty> properties = new TreeMap<>();
     private final SortedMap<String, GqlvCollection> collections = new 
TreeMap<>();
     private final Map<String, GqlvAction> actions = new TreeMap<>();
 
-    private GraphQLObjectType objectType;
 
     @Getter private final GraphQLInputObjectType gqlInputObjectType;
 
-    private static Map<ObjectSpecification, GqlvDomainObject> 
objectByObjectSpec = new LinkedHashMap<>();
-
-    public static GqlvDomainObject of(
-            final ObjectSpecification objectSpec,
-            final GqlvDomainObject.Holder holder,
-            final Context context) {
-        return objectByObjectSpec.computeIfAbsent(objectSpec, x -> new 
GqlvDomainObject(holder, x, context));
-    }
-
-    private GqlvDomainObject(
+    public GqlvDomainObject(
             final GqlvDomainObject.Holder holder,
             final ObjectSpecification objectSpecification,
             final Context context) {
-        this.holder = holder;
+        
super(newObject().name(TypeNames.objectTypeNameFor(objectSpecification)), 
context);
 
+        this.holder = holder;
         this.objectSpecification = objectSpecification;
-        this.context = context;
-
-        this.gqlObjectTypeBuilder = 
newObject().name(TypeNames.objectTypeNameFor(objectSpecification));
 
         this.meta = new GqlvMeta(this, context);
         addField(meta.getField());
@@ -109,7 +95,7 @@ public class GqlvDomainObject
 
         addMembers();
 
-        objectType = gqlObjectTypeBuilder.build();
+        val objectType = buildObjectType();
 
         context.graphQLTypeRegistry.addTypeIfNotAlreadyPresent(objectType);
         
context.graphQLTypeRegistry.addTypeIfNotAlreadyPresent(gqlInputObjectType);
@@ -171,14 +157,6 @@ public class GqlvDomainObject
     }
 
 
-    private GraphQLFieldDefinition addField(GraphQLFieldDefinition field) {
-        if (field != null) {
-            gqlObjectTypeBuilder.field(field);
-        }
-        return field;
-    }
-
-
     public void addDataFetchers() {
 
         this.context.codeRegistryBuilder.dataFetcher(
@@ -196,12 +174,6 @@ public class GqlvDomainObject
     }
 
 
-    @Override
-    public FieldCoordinates coordinatesFor(final GraphQLFieldDefinition 
fieldDefinition) {
-        return FieldCoordinates.coordinates(objectType, fieldDefinition);
-    }
-
-
     @Override
     public String toString() {
         return objectSpecification.getLogicalTypeName();
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainService.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainService.java
index f29919d5e8..3ac6027136 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainService.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainService.java
@@ -65,17 +65,7 @@ public class GqlvDomainService implements GqlvAction.Holder {
      */
     private GraphQLObjectType gqlObjectType;
 
-    private static Map<ObjectSpecification, GqlvDomainService> 
serviceByObjectSpec = new LinkedHashMap<>();
-
-    public static GqlvDomainService of(
-            final ObjectSpecification objectSpec,
-            final Holder holder,
-            final Object servicePojo,
-            final Context context) {
-        return serviceByObjectSpec.computeIfAbsent(objectSpec, x -> new 
GqlvDomainService(holder, x, servicePojo, context));
-    }
-
-    private GqlvDomainService(
+    public GqlvDomainService(
             final GqlvDomainService.Holder holder,
             final ObjectSpecification objectSpecification,
             final Object servicePojo,
@@ -88,7 +78,6 @@ public class GqlvDomainService implements GqlvAction.Holder {
         this.gqlObjectTypeBuilder = 
newObject().name(TypeNames.objectTypeNameFor(objectSpecification));
 
         addActions();
-
         if (hasActions()) {
             gqlObjectType = gqlObjectTypeBuilder.build();
             this.field = newFieldDefinition()
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMember.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMember.java
index 425ae899a7..ce3af7664b 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMember.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMember.java
@@ -24,38 +24,36 @@ import 
org.apache.causeway.core.metamodel.spec.feature.ObjectMember;
 import org.apache.causeway.viewer.graphql.model.context.Context;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationProvider;
 
-import lombok.AccessLevel;
+import graphql.schema.GraphQLObjectType;
+
 import lombok.Getter;
-import lombok.Setter;
 
-public abstract class GqlvMember<T extends ObjectMember, H extends 
GqlvMember.Holder> {
+public abstract class GqlvMember<T extends ObjectMember, H extends 
GqlvMember.Holder>
+    extends GqlvAbstractCustom {
 
     @Getter final H holder;
     @Getter private final T objectMember;
 
-    final Context context;
-
-    @Getter @Setter(AccessLevel.PACKAGE)
-    GraphQLFieldDefinition field;
-
     public GqlvMember(
             final H holder,
             final T objectMember,
+            final GraphQLObjectType.Builder gqlObjectTypeBuilder,
             final Context context
     ) {
-        this(holder, objectMember, null, context);
+        this(holder, objectMember, gqlObjectTypeBuilder, null, context);
     }
 
     public GqlvMember(
             final H holder,
             final T objectMember,
+            final GraphQLObjectType.Builder gqlObjectTypeBuilder,
             final GraphQLFieldDefinition field,
             final Context context
     ) {
+        super(gqlObjectTypeBuilder, context);
         this.holder = holder;
         this.objectMember = objectMember;
         this.field = field;
-        this.context = context;
     }
 
     public String getId() {
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMemberDisabled.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMemberDisabled.java
index 351f45ee60..98ac117852 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMemberDisabled.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMemberDisabled.java
@@ -37,28 +37,26 @@ import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class GqlvMemberDisabled<T extends ObjectMember> {
+public class GqlvMemberDisabled<T extends ObjectMember> extends GqlvAbstract {
 
     private final Holder<T> holder;
-    private final Context context;
-    @Getter private final GraphQLFieldDefinition field;
 
     public GqlvMemberDisabled(
             final Holder<T> holder,
             final Context context
     ) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
-        this.field = newFieldDefinition()
+        setField(newFieldDefinition()
                 .name("disabled")
-                .type(this.context.typeMapper.scalarTypeFor(String.class))
-                .build();
+                .type(context.typeMapper.scalarTypeFor(String.class))
+                .build());
     }
 
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
-                holder.coordinatesFor(field),
+                holder.coordinatesFor(getField()),
                 this::disabled
         );
     }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMemberHidden.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMemberHidden.java
index b1f95f7993..ab116ebed8 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMemberHidden.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMemberHidden.java
@@ -37,28 +37,26 @@ import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class GqlvMemberHidden<T extends ObjectMember> {
+public class GqlvMemberHidden<T extends ObjectMember> extends GqlvAbstract {
 
     private final Holder<T> holder;
-    private final Context context;
-    @Getter private final GraphQLFieldDefinition field;
 
     public GqlvMemberHidden(
             final Holder<T> holder,
             final Context context
     ) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
-        this.field = newFieldDefinition()
+        setField(newFieldDefinition()
                 .name("hidden")
                 .type(this.context.typeMapper.scalarTypeFor(boolean.class))
-                .build();
+                .build());
     }
 
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
-                holder.coordinatesFor(field),
+                holder.coordinatesFor(getField()),
                 this::hidden
         );
     }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMeta.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMeta.java
index fb9950c52c..515f026067 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMeta.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMeta.java
@@ -42,7 +42,7 @@ import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationP
 import lombok.Getter;
 import lombok.val;
 
-public class GqlvMeta {
+public class GqlvMeta extends GqlvAbstractCustom {
 
     static GraphQLFieldDefinition id = 
newFieldDefinition().name("id").type(nonNull(Scalars.GraphQLString)).build();
     static GraphQLFieldDefinition logicalTypeName = 
newFieldDefinition().name("logicalTypeName").type(nonNull(Scalars.GraphQLString)).build();
@@ -50,38 +50,23 @@ public class GqlvMeta {
 
     private final Holder holder;
 
-    private final Context context;
-
-    private final GraphQLObjectType objectType;
-
-    @Getter private final GraphQLFieldDefinition field;
-
     public GqlvMeta(
             final Holder holder,
             final Context context
     ) {
-        this.holder = holder;
+        
super(newObject().name(TypeNames.metaTypeNameFor(holder.getObjectSpecification())),
 context);
 
-        this.context = context;
+        this.holder = holder;
 
-        // we can build the metafield and meta type eagerly because we know 
exactly which fields it has.
-        val objectTypeBuilder = 
newObject().name(TypeNames.metaTypeNameFor(this.holder.getObjectSpecification()));
 
-        objectTypeBuilder.field(id);
-        objectTypeBuilder.field(logicalTypeName);
+        field(id);
+        field(logicalTypeName);
         if (this.holder.getObjectSpecification().getBeanSort() == 
BeanSort.ENTITY) {
-            objectTypeBuilder.field(version);
+            field(version);
         }
 
         val fieldName = 
context.causewayConfiguration.getViewer().getGraphql().getMetaData().getFieldName();
-
-        this.objectType = objectTypeBuilder.build();
-        field = newFieldDefinition()
-                        .name(fieldName)
-                        .type(objectType)
-                        .build();
-
-        context.graphQLTypeRegistry.addTypeIfNotAlreadyPresent(objectType);
+        buildObjectTypeAndSetFieldName(fieldName);
     }
 
 
@@ -95,16 +80,16 @@ public class GqlvMeta {
                         .orElseThrow());
 
         context.codeRegistryBuilder.dataFetcher(
-                coordinates(objectType, logicalTypeName),
+                coordinates(getGqlObjectType(), logicalTypeName),
                 (DataFetcher<Object>) environment -> 
environment.<Fetcher>getSource().logicalTypeName());
 
         context.codeRegistryBuilder.dataFetcher(
-                coordinates(objectType, id),
+                coordinates(getGqlObjectType(), id),
                 (DataFetcher<Object>) environment -> 
environment.<Fetcher>getSource().id());
 
         if (holder.getObjectSpecification().getBeanSort() == BeanSort.ENTITY) {
             context.codeRegistryBuilder.dataFetcher(
-                    coordinates(objectType, version),
+                    coordinates(getGqlObjectType(), version),
                     (DataFetcher<Object>) environment -> 
environment.<Fetcher>getSource().version());
         }
     }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForAction.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForAction.java
index 879af596cc..9b501a301b 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForAction.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForAction.java
@@ -41,34 +41,31 @@ 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.OneToManyActionParameter;
 import org.apache.causeway.core.metamodel.spec.feature.OneToOneActionParameter;
-import org.apache.causeway.viewer.graphql.model.types.TypeMapper;
 import org.apache.causeway.viewer.graphql.model.context.Context;
 import org.apache.causeway.viewer.graphql.model.exceptions.DisabledException;
 import org.apache.causeway.viewer.graphql.model.exceptions.HiddenException;
+import org.apache.causeway.viewer.graphql.model.types.TypeMapper;
 
-import lombok.Getter;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class GqlvMutationForAction {
+public class GqlvMutationForAction extends GqlvAbstract {
 
     private final Holder holder;
     private final ObjectSpecification objectSpec;
     private final ObjectAction objectAction;
-    private final Context context;
-    @Getter private final GraphQLFieldDefinition field;
     private String argumentName;
 
     public GqlvMutationForAction(
             final Holder holder,
             final ObjectSpecification objectSpec,
             final ObjectAction objectAction,
-        final Context context) {
+            final Context context) {
+        super(context);
         this.holder = holder;
         this.objectSpec = objectSpec;
         this.objectAction = objectAction;
-        this.context = context;
 
         this.argumentName = 
context.causewayConfiguration.getViewer().getGraphql().getMutation().getTargetArgName();
 
@@ -78,9 +75,9 @@ public class GqlvMutationForAction {
                     .name(fieldName(objectSpec, objectAction))
                     .type(type);
             addGqlArguments(fieldBuilder);
-            this.field = fieldBuilder.build();
+            setField(fieldBuilder.build());
         } else {
-            this.field = null;
+            setField(null);
         }
     }
 
@@ -123,7 +120,7 @@ public class GqlvMutationForAction {
 
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
-                holder.coordinatesFor(field),
+                holder.coordinatesFor(getField()),
                 this::invoke
         );
     }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForProperty.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForProperty.java
index f16a8e81ac..65ab2e2e40 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForProperty.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForProperty.java
@@ -42,24 +42,22 @@ import lombok.Getter;
 import lombok.val;
 
 //@Log4j2
-public class GqlvMutationForProperty {
+public class GqlvMutationForProperty extends GqlvAbstract {
 
     private final Holder holder;
     private final ObjectSpecification objectSpec;
     private final OneToOneAssociation oneToOneAssociation;
-    private final Context context;
-    @Getter private final GraphQLFieldDefinition field;
     private String argumentName;
 
     public GqlvMutationForProperty(
             final Holder holder,
             final ObjectSpecification objectSpec,
             final OneToOneAssociation oneToOneAssociation,
-        final Context context) {
+            final Context context) {
+        super(context);
         this.holder = holder;
         this.objectSpec = objectSpec;
         this.oneToOneAssociation = oneToOneAssociation;
-        this.context = context;
 
         this.argumentName = 
context.causewayConfiguration.getViewer().getGraphql().getMutation().getTargetArgName();
 
@@ -69,9 +67,9 @@ public class GqlvMutationForProperty {
                     .name(fieldName(objectSpec, oneToOneAssociation))
                     .type(type);
             addGqlArguments(fieldBuilder);
-            this.field = fieldBuilder.build();
+            setField(fieldBuilder.build());
         } else {
-            this.field = null;
+            setField(null);
         }
     }
 
@@ -91,16 +89,17 @@ public class GqlvMutationForProperty {
             case VIEW_MODEL:
             case ENTITY:
                 context.codeRegistryBuilder.dataFetcher(
-                        holder.coordinatesFor(field),
+                        holder.coordinatesFor(getField()),
                         this::set);
 
                 break;
         }
 
-        context.codeRegistryBuilder.dataFetcher(
-                holder.coordinatesFor(field),
-                this::set
-        );
+        // looks to be unnecessary...
+//        context.codeRegistryBuilder.dataFetcher(
+//                holder.coordinatesFor(getField()),
+//                this::set
+//        );
     }
 
     private Object set(final DataFetchingEnvironment dataFetchingEnvironment) {
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java
index d3cbadea51..967343dece 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java
@@ -45,8 +45,6 @@ public class GqlvProperty
                    GqlvPropertyValidate.Holder,
                    GqlvPropertySet.Holder {
 
-    private final GraphQLObjectType.Builder gqlObjectTypeBuilder;
-    private final GraphQLObjectType gqlObjectType;
     private final GqlvMemberHidden<OneToOneAssociation> hidden;
     private final GqlvMemberDisabled<OneToOneAssociation> disabled;
     private final GqlvPropertyGet get;
@@ -68,9 +66,7 @@ public class GqlvProperty
             final Holder holder,
             final OneToOneAssociation oneToOneAssociation,
             final Context context) {
-        super(holder, oneToOneAssociation, context);
-
-        this.gqlObjectTypeBuilder = 
newObject().name(TypeNames.propertyTypeNameFor(this.holder.getObjectSpecification(),
 oneToOneAssociation));
+        super(holder, oneToOneAssociation, 
newObject().name(TypeNames.propertyTypeNameFor(holder.getObjectSpecification(), 
oneToOneAssociation)), context);
 
         this.hidden = new GqlvMemberHidden<>(this, context);
         addField(hidden.getField());
@@ -109,14 +105,7 @@ public class GqlvProperty
         }
 
 
-        this.gqlObjectType = gqlObjectTypeBuilder.build();
-
-        setField(
-            newFieldDefinition()
-                .name(oneToOneAssociation.getId())
-                .type(gqlObjectTypeBuilder)
-                .build()
-        );
+        buildObjectTypeAndSetFieldName(oneToOneAssociation.getId());
     }
 
     public void addGqlArgument(
@@ -145,13 +134,6 @@ public class GqlvProperty
         return getObjectAssociation();
     }
 
-    private GraphQLFieldDefinition addField(GraphQLFieldDefinition field) {
-        if (field != null) {
-            gqlObjectTypeBuilder.field(field);
-        }
-        return field;
-    }
-
     public void addDataFetcher() {
         context.codeRegistryBuilder.dataFetcher(
                 holder.coordinatesFor(getField()),
@@ -173,12 +155,6 @@ public class GqlvProperty
     }
 
 
-    @Override
-    public FieldCoordinates coordinatesFor(GraphQLFieldDefinition 
fieldDefinition) {
-        return FieldCoordinates.coordinates(gqlObjectType, fieldDefinition);
-    }
-
-
     public interface Holder
             extends GqlvAssociation.Holder {
     }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyAutoComplete.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyAutoComplete.java
index 0cab63dd5f..09e1fa9840 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyAutoComplete.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyAutoComplete.java
@@ -23,7 +23,6 @@ import java.util.stream.Collectors;
 
 import graphql.schema.DataFetchingEnvironment;
 import graphql.schema.GraphQLArgument;
-import graphql.schema.GraphQLFieldDefinition;
 import graphql.schema.GraphQLList;
 
 import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
@@ -36,25 +35,19 @@ import 
org.apache.causeway.viewer.graphql.model.fetcher.BookmarkedPojo;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationProvider;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.OneToOneAssociationProvider;
 
-import lombok.Getter;
 import lombok.val;
 
-public class GqlvPropertyAutoComplete {
+public class GqlvPropertyAutoComplete extends GqlvAbstract {
 
     private static final String SEARCH_PARAM_NAME = "search";
 
     private final Holder holder;
-    private final Context context;
-    /**
-     * Populated iff there are choices for this property
-     */
-    @Getter final GraphQLFieldDefinition field;
 
     public GqlvPropertyAutoComplete(
             final Holder holder,
             final Context context) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
         val otoa = holder.getOneToOneAssociation();
         if (otoa.hasAutoComplete()) {
@@ -66,14 +59,14 @@ public class GqlvPropertyAutoComplete {
                             .name(SEARCH_PARAM_NAME)
                             
.type(nonNull(context.typeMapper.scalarTypeFor(String.class))))
                     .build();
-            this.field = fieldBuilder.build();
+            setField(fieldBuilder.build());
         } else {
-            this.field = null;
+            setField(null);
         }
     }
 
     boolean hasAutoComplete() {
-        return this.field != null;
+        return this.getField() != null;
     }
 
     void addDataFetcher() {
@@ -87,7 +80,7 @@ public class GqlvPropertyAutoComplete {
             case VIEW_MODEL:
             case ENTITY:
                 context.codeRegistryBuilder.dataFetcher(
-                        holder.coordinatesFor(field),
+                        holder.coordinatesFor(getField()),
                         this::autoComplete);
 
                 break;
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyChoices.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyChoices.java
index d4ec81e429..c6a9f3b905 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyChoices.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyChoices.java
@@ -30,29 +30,23 @@ import static 
graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
 import org.apache.causeway.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
 import org.apache.causeway.core.metamodel.spec.feature.OneToOneAssociation;
-import org.apache.causeway.viewer.graphql.model.types.TypeMapper;
 import org.apache.causeway.viewer.graphql.model.context.Context;
 import org.apache.causeway.viewer.graphql.model.fetcher.BookmarkedPojo;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationProvider;
 import 
org.apache.causeway.viewer.graphql.model.mmproviders.OneToOneAssociationProvider;
+import org.apache.causeway.viewer.graphql.model.types.TypeMapper;
 
-import lombok.Getter;
 import lombok.val;
 
-public class GqlvPropertyChoices {
+public class GqlvPropertyChoices extends GqlvAbstract {
 
     final Holder holder;
-    private final Context context;
-    /**
-     * Populated iff there are choices for this property
-     */
-    @Getter final GraphQLFieldDefinition field;
 
     public GqlvPropertyChoices(
             final Holder holder,
             final Context context) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
         val otoa = holder.getOneToOneAssociation();
         if (otoa.hasChoices()) {
@@ -61,14 +55,14 @@ public class GqlvPropertyChoices {
                     .name("choices")
                     
.type(GraphQLList.list(context.typeMapper.outputTypeFor(elementType)));
             holder.addGqlArgument(otoa, fieldBuilder, 
TypeMapper.InputContext.CHOICES);
-            this.field = fieldBuilder.build();
+            setField(fieldBuilder.build());
         } else {
-            this.field = null;
+            setField(null);
         }
     }
 
     boolean hasChoices() {
-        return this.field != null;
+        return this.getField() != null;
     }
 
     void addDataFetcher() {
@@ -82,7 +76,7 @@ public class GqlvPropertyChoices {
             case VIEW_MODEL:
             case ENTITY:
                 context.codeRegistryBuilder.dataFetcher(
-                        holder.coordinatesFor(field),
+                        holder.coordinatesFor(getField()),
                         this::choices);
 
                 break;
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyGet.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyGet.java
index 0fd8531258..cb8b5e14a1 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyGet.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyGet.java
@@ -25,7 +25,7 @@ import 
org.apache.causeway.viewer.graphql.model.context.Context;
 
 import lombok.val;
 
-public class GqlvPropertyGet  extends GqlvAssociationGet<OneToOneAssociation> {
+public class GqlvPropertyGet extends GqlvAssociationGet<OneToOneAssociation> {
 
     public GqlvPropertyGet(
             final Holder holder,
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertySet.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertySet.java
index fb563ef73b..d3d91c102d 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertySet.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertySet.java
@@ -42,17 +42,15 @@ import 
org.apache.causeway.viewer.graphql.model.mmproviders.OneToOneAssociationP
 import lombok.Getter;
 import lombok.val;
 
-public class GqlvPropertySet {
+public class GqlvPropertySet extends GqlvAbstract {
 
     final Holder holder;
-    final Context context;
-    @Getter final GraphQLFieldDefinition field;
 
     public GqlvPropertySet(
             final Holder holder,
             final Context context) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
         GraphQLOutputType graphQLOutputType = outputTypeFor(holder);
         if (graphQLOutputType != null) {
@@ -60,9 +58,9 @@ public class GqlvPropertySet {
                     .name("set")
                     .type(graphQLOutputType);
             holder.addGqlArgument(holder.getOneToOneAssociation(), 
fieldBuilder, TypeMapper.InputContext.INVOKE);
-            this.field = fieldBuilder.build();
+            setField(fieldBuilder.build());
         } else {
-            this.field = null;
+            setField(null);
         }
     }
 
@@ -70,7 +68,6 @@ public class GqlvPropertySet {
         return 
context.typeMapper.outputTypeFor(holder.getObjectSpecification());   // setters 
return void, so we return the domain object instead
     }
 
-
     void addDataFetcher() {
 
         val association = holder.getOneToOneAssociation();
@@ -82,7 +79,7 @@ public class GqlvPropertySet {
             case VIEW_MODEL:
             case ENTITY:
                 context.codeRegistryBuilder.dataFetcher(
-                        holder.coordinatesFor(field),
+                        holder.coordinatesFor(getField()),
                         this::set);
 
                 break;
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java
index 1392f77ff8..2664888d58 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java
@@ -35,24 +35,22 @@ import 
org.apache.causeway.viewer.graphql.model.mmproviders.OneToOneAssociationP
 import lombok.Getter;
 import lombok.val;
 
-public class GqlvPropertyValidate {
+public class GqlvPropertyValidate extends GqlvAbstract {
 
     final Holder holder;
-    private final Context context;
-    @Getter final GraphQLFieldDefinition field;
 
     public GqlvPropertyValidate(
             final Holder holder,
             final Context context) {
+        super(context);
         this.holder = holder;
-        this.context = context;
 
         val fieldBuilder = newFieldDefinition()
                 .name("validate")
                 .type(context.typeMapper.scalarTypeFor(String.class));
         holder.addGqlArgument(holder.getOneToOneAssociation(), fieldBuilder, 
TypeMapper.InputContext.VALIDATE);
 
-        this.field = fieldBuilder.build();
+        setField(fieldBuilder.build());
     }
 
     void addDataFetcher() {
@@ -66,7 +64,7 @@ public class GqlvPropertyValidate {
             case VIEW_MODEL:
             case ENTITY:
                 context.codeRegistryBuilder.dataFetcher(
-                        holder.coordinatesFor(field),
+                        holder.coordinatesFor(getField()),
                         this::validate);
 
                 break;
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenario.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenario.java
index a957e38e8d..b929fec17a 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenario.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenario.java
@@ -38,60 +38,43 @@ import lombok.Getter;
 /**
  * Exposes a domain service (view model or entity) via the GQL viewer.
  */
-public class GqlvScenario implements GqlvScenarioName.Holder, 
GqlvScenarioGiven.Holder {
+public class GqlvScenario
+        extends GqlvAbstractCustom
+        implements GqlvScenarioName.Holder, GqlvScenarioGiven.Holder {
 
     private final Holder holder;
-    private final Context context;
 
-    private final GraphQLObjectType.Builder gqlObjectTypeBuilder;
     private final Scenario scenarioPojo;
 
     private final GqlvScenarioName scenarioName;
     private final GqlvScenarioGiven scenarioGiven;
 
-    @Getter private GraphQLFieldDefinition field;
-
-    private GraphQLObjectType gqlObjectType;
-
     public GqlvScenario(
             final GqlvScenario.Holder holder,
             final Context context) {
+        super(newObject().name("Scenario"), context);
         this.holder = holder;
-        this.context = context;
 
         this.scenarioPojo = 
context.serviceRegistry.lookupService(Scenario.class).orElseThrow();
 
-        this.gqlObjectTypeBuilder = newObject().name("Scenario");
-
         this.scenarioName = new GqlvScenarioName(this, context);
         addField(scenarioName.getField());
         this.scenarioGiven = new GqlvScenarioGiven(this, context);
         addField(scenarioGiven.getField());
 
-        this.gqlObjectType = gqlObjectTypeBuilder.build();
+        buildObjectType();
 
-        this.field = new GraphQLFieldDefinition.Builder()
+        setField(new GraphQLFieldDefinition.Builder()
                             .name("Scenario")
-                            .type(gqlObjectType)
+                            .type(getGqlObjectType())
                             .argument(new GraphQLArgument.Builder()
                                                 .name("name")
                                                 .type(Scalars.GraphQLString)
                             )
-                            .build();
-    }
-
-
-    private GraphQLFieldDefinition addField(GraphQLFieldDefinition field) {
-        if (field != null) {
-            gqlObjectTypeBuilder.field(field);
-        }
-        return field;
+                            .build()
+        );
     }
 
-    @Override
-    public FieldCoordinates coordinatesFor(GraphQLFieldDefinition 
fieldDefinition) {
-        return coordinates(gqlObjectType, fieldDefinition);
-    }
 
     public void addDataFetchers() {
         context.codeRegistryBuilder.dataFetcher(
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioGiven.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioGiven.java
index da0d4b5e5c..6f24294f32 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioGiven.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioGiven.java
@@ -15,15 +15,13 @@ import 
org.apache.causeway.viewer.graphql.model.context.Context;
 
 import static graphql.schema.GraphQLObjectType.newObject;
 
-public class GqlvScenarioGiven implements GqlvDomainService.Holder, 
GqlvDomainObject.Holder {
+public class GqlvScenarioGiven
+        extends GqlvAbstractCustom
+        implements GqlvDomainService.Holder, GqlvDomainObject.Holder {
 
     private static final String OBJECT_TYPE_NAME = "Given";
 
-    final GraphQLObjectType.Builder gqlObjectTypeBuilder;
-    @Getter private final GraphQLObjectType objectType;
-
     private final Holder holder;
-    @Getter private final GraphQLFieldDefinition field;
 
     private final List<GqlvDomainService> domainServices = new ArrayList<>();
     private final List<GqlvDomainObject> domainObjects = new ArrayList<>();
@@ -31,11 +29,10 @@ public class GqlvScenarioGiven implements 
GqlvDomainService.Holder, GqlvDomainOb
     public GqlvScenarioGiven(
             final GqlvScenarioGiven.Holder holder,
             final Context context) {
+        super(newObject().name(OBJECT_TYPE_NAME), context);
 
         this.holder = holder;
 
-        this.gqlObjectTypeBuilder = newObject().name(OBJECT_TYPE_NAME);
-
         context.objectSpecifications().forEach(objectSpec -> {
             switch (objectSpec.getBeanSort()) {
 
@@ -43,7 +40,7 @@ public class GqlvScenarioGiven implements 
GqlvDomainService.Holder, GqlvDomainOb
                 case VIEW_MODEL: // @DomainObject(nature=VIEW_MODEL)
                 case ENTITY:     // @DomainObject(nature=ENTITY)
 
-                    domainObjects.add(GqlvDomainObject.of(objectSpec, this, 
context));
+                    domainObjects.add(new GqlvDomainObject(this, objectSpec, 
context));
 
                     break;
             }
@@ -53,7 +50,7 @@ public class GqlvScenarioGiven implements 
GqlvDomainService.Holder, GqlvDomainOb
             if (Objects.requireNonNull(objectSpec.getBeanSort()) == 
BeanSort.MANAGED_BEAN_CONTRIBUTING) { // @DomainService
                 
context.serviceRegistry.lookupBeanById(objectSpec.getLogicalTypeName())
                         .ifPresent(servicePojo -> {
-                            GqlvDomainService gqlvDomainService = 
GqlvDomainService.of(objectSpec, this, servicePojo, context);
+                            GqlvDomainService gqlvDomainService = new 
GqlvDomainService(this, objectSpec, servicePojo, context);
                             addField(gqlvDomainService.getField());
                             domainServices.add(gqlvDomainService);
                         });
@@ -66,24 +63,10 @@ public class GqlvScenarioGiven implements 
GqlvDomainService.Holder, GqlvDomainOb
         }
 
 
-        objectType = gqlObjectTypeBuilder.build();
-
-        this.field = 
GraphQLFieldDefinition.newFieldDefinition().name("Given").type(objectType).build();
+        buildObjectTypeAndSetFieldName("Given");
     }
 
 
-    @Override
-    public FieldCoordinates coordinatesFor(GraphQLFieldDefinition 
fieldDefinition) {
-        return FieldCoordinates.coordinates(objectType, fieldDefinition);
-    }
-
-    private GraphQLFieldDefinition addField(GraphQLFieldDefinition field) {
-        if (field != null) {
-            gqlObjectTypeBuilder.field(field);
-        }
-        return field;
-    }
-
     public void addDataFetchers() {
         domainServices.forEach(domainService -> {
             boolean actionsAdded = domainService.hasActions();
@@ -92,7 +75,6 @@ public class GqlvScenarioGiven implements 
GqlvDomainService.Holder, GqlvDomainOb
             }
         });
 
-
         domainObjects.forEach(GqlvDomainObject::addDataFetchers);
     }
 
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioName.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioName.java
index d6ee87f989..aa5c7ddd76 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioName.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioName.java
@@ -1,5 +1,6 @@
 package org.apache.causeway.viewer.graphql.model.domain;
 
+import graphql.GraphQLContext;
 import graphql.Scalars;
 import graphql.schema.DataFetcher;
 import graphql.schema.DataFetchingEnvironment;
@@ -7,33 +8,39 @@ import graphql.schema.GraphQLFieldDefinition;
 
 import lombok.Getter;
 
+import static graphql.schema.GraphQLFieldDefinition.*;
 import static graphql.schema.GraphQLObjectType.newObject;
 
 import org.apache.causeway.viewer.graphql.model.context.Context;
 
-public class GqlvScenarioName  {
+public class GqlvScenarioName extends GqlvAbstract {
 
     private final Holder holder;
-    private final Context context;
-    @Getter private final GraphQLFieldDefinition field;
 
     public GqlvScenarioName(
             final GqlvScenarioName.Holder holder,
             final Context context) {
 
+        super(context);
+
         this.holder = holder;
-        this.context = context;
 
-        this.field = 
GraphQLFieldDefinition.newFieldDefinition().name("Name").type(Scalars.GraphQLString).build();
+        setField(newFieldDefinition()
+                    .name("Name")
+                    .type(Scalars.GraphQLString)
+                    .build()
+        );
     }
 
     public void addDataFetchers() {
         context.codeRegistryBuilder.dataFetcher(
-                holder.coordinatesFor(field),
+                holder.coordinatesFor(getField()),
                 (DataFetcher<Object>) environment ->  name(environment));
     }
 
     private String name(DataFetchingEnvironment environment) {
+        // TODO: use graphQlContext instead.
+        GraphQLContext graphQlContext = environment.getGraphQlContext();
         return 
context.serviceRegistry.lookupService(Scenario.class).map(Scenario::getName).orElseThrow();
     }
 
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/toplevel/GqlvTopLevelQuery.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/toplevel/GqlvTopLevelQuery.java
index 207c6aad06..c98207bff8 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/toplevel/GqlvTopLevelQuery.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/toplevel/GqlvTopLevelQuery.java
@@ -39,7 +39,7 @@ public class GqlvTopLevelQuery implements 
GqlvDomainService.Holder, GqlvDomainOb
                 case VIEW_MODEL: // @DomainObject(nature=VIEW_MODEL)
                 case ENTITY:     // @DomainObject(nature=ENTITY)
 
-                    domainObjects.add(GqlvDomainObject.of(objectSpec, this, 
context));
+                    domainObjects.add(new GqlvDomainObject(this, objectSpec, 
context));
 
                     break;
             }
@@ -51,7 +51,7 @@ public class GqlvTopLevelQuery implements 
GqlvDomainService.Holder, GqlvDomainOb
                 case MANAGED_BEAN_CONTRIBUTING: // @DomainService
                     
context.serviceRegistry.lookupBeanById(objectSpec.getLogicalTypeName())
                             .ifPresent(servicePojo -> {
-                                GqlvDomainService gqlvDomainService = 
GqlvDomainService.of(objectSpec, this, servicePojo, context);
+                                GqlvDomainService gqlvDomainService = new 
GqlvDomainService(this, objectSpec, servicePojo, context);
                                 addField(gqlvDomainService.getField());
                                 domainServices.add(gqlvDomainService);
                             });

Reply via email to