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 9d9651540d11e2cd72ac96e8ee0c652532a31003
Author: danhaywood <[email protected]>
AuthorDate: Tue Mar 12 17:20:13 2024 +0000

    CAUSEWAY-3676: reworks to use an SPI instead of annotation
---
 api/applib/src/main/java/module-info.java          |  1 +
 .../apache/causeway/applib/annotation/Action.java  | 13 ------
 .../causeway/applib/annotation/Collection.java     | 13 ------
 .../causeway/applib/annotation/Parameter.java      | 13 ------
 .../causeway/applib/annotation/Property.java       | 13 ------
 .../services/ascii/AsciiIdentifierService.java     | 20 +++++++++
 core/metamodel/src/main/java/module-info.java      |  1 -
 .../metamodel/context/HasMetaModelContext.java     |  6 +++
 .../core/metamodel/context/MetaModelContext.java   |  2 +
 .../action/ActionAnnotationFacetFactory.java       | 12 ------
 .../ascii/AsciiFacetForActionAnnotation.java       | 48 ----------------------
 .../metamodel/facets/all/ascii/AsciiFacet.java     | 29 -------------
 .../facets/all/ascii/AsciiFacetAbstract.java       | 48 ----------------------
 .../CollectionAnnotationFacetFactory.java          | 11 -----
 .../ascii/AsciiFacetForCollectionAnnotation.java   | 48 ----------------------
 .../ascii/AsciiFacetForParameterAnnotation.java    | 47 ---------------------
 .../parameter/ParameterAnnotationFacetFactory.java | 13 ------
 .../ascii/AsciiFacetForPropertyAnnotation.java     | 48 ----------------------
 .../property/PropertyAnnotationFacetFactory.java   | 12 ------
 .../core/metamodel/spec/feature/ObjectFeature.java |  1 +
 .../specloader/specimpl/ObjectActionDefault.java   |  5 +++
 .../specimpl/ObjectActionParameterAbstract.java    |  7 ++++
 .../specloader/specimpl/ObjectMemberAbstract.java  |  5 +++
 viewers/graphql/adoc/modules/ROOT/pages/i18n.adoc  | 27 +++++++++---
 .../viewer/graphql/model/context/Context.java      |  3 +-
 .../viewer/graphql/model/domain/TypeNames.java     |  2 +-
 .../domain/common/query/ObjectFeatureUtils.java    |  4 +-
 .../model/domain/simple/query/SimpleAction.java    |  2 +-
 ...iiIdentifierServiceSupportingGraphqlViewer.java | 13 ++++++
 .../viewer/test/domain/i18n/I18nCalculator.java    |  4 +-
 30 files changed, 87 insertions(+), 384 deletions(-)

diff --git a/api/applib/src/main/java/module-info.java 
b/api/applib/src/main/java/module-info.java
index ba3c1d6f38..bfd4bca708 100644
--- a/api/applib/src/main/java/module-info.java
+++ b/api/applib/src/main/java/module-info.java
@@ -154,5 +154,6 @@ module org.apache.causeway.applib {
     opens org.apache.causeway.applib.layout.links;
     opens org.apache.causeway.applib.layout.menubars.bootstrap;
     opens org.apache.causeway.applib.layout.menubars;
+    exports org.apache.causeway.applib.services.ascii;
 
 }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/annotation/Action.java 
b/api/applib/src/main/java/org/apache/causeway/applib/annotation/Action.java
index 9795ecfaf4..6b100014a7 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/annotation/Action.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/annotation/Action.java
@@ -213,17 +213,4 @@ public @interface Action {
     String fileAccept()
             default "";
 
-    /**
-     * Returns an alternative id for the action, using only ASCII characters.
-     *
-     * <p>
-     *     Although Java itself allows the full UTF character set for 
identifiers, some integrations (such as GraphQL)
-     *     have restrictions to only allow a more limited set of characters, 
in essence ASCII.
-     *     This attribute allows a version of the action's Id using only the 
ASCII character set to be provided.
-     * </p>
-     *
-     * @return an alternative id for the action, using only ASCII characters.
-     */
-    String asciiId() default "";
-
 }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/annotation/Collection.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/annotation/Collection.java
index 01b9ae8089..5f8837dcb6 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/annotation/Collection.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/annotation/Collection.java
@@ -95,17 +95,4 @@ public @interface Collection {
     Class<?> typeOf()
             default void.class; // represents unspecified
 
-    /**
-     * Returns an alternative id for the collection, using only ASCII 
characters.
-     *
-     * <p>
-     *     Although Java itself allows the full UTF character set for 
identifiers, some integrations (such as GraphQL)
-     *     have restrictions to only allow a more limited set of characters, 
in essence ASCII.
-     *     This attribute allows a version of the collection's Id using only 
the ASCII character set to be provided.
-     * </p>
-     *
-     * @return an alternative id for the collection, using only ASCII 
characters.
-     */
-    String asciiId() default "";
-
 }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/annotation/Parameter.java 
b/api/applib/src/main/java/org/apache/causeway/applib/annotation/Parameter.java
index 207fd6390b..d825be3d3e 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/annotation/Parameter.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/annotation/Parameter.java
@@ -142,17 +142,4 @@ public @interface Parameter {
     PrecedingParamsPolicy precedingParamsPolicy()
             default PrecedingParamsPolicy.AS_CONFIGURED;
 
-    /**
-     * Returns an alternative id for the parameter, using only ASCII 
characters.
-     *
-     * <p>
-     *     Although Java itself allows the full UTF character set for 
identifiers, some integrations (such as GraphQL)
-     *     have restrictions to only allow a more limited set of characters, 
in essence ASCII.
-     *     This attribute allows a version of the parameter's Id using only 
the ASCII character set to be provided.
-     * </p>
-     *
-     * @return an alternative id for the parameter, using only ASCII 
characters.
-     */
-    String asciiId() default "";
-
 }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/annotation/Property.java 
b/api/applib/src/main/java/org/apache/causeway/applib/annotation/Property.java
index 432fa9f047..3e7df41f92 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/annotation/Property.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/annotation/Property.java
@@ -289,17 +289,4 @@ public @interface Property {
      */
     String regexPatternReplacement()
             default "Doesn't match pattern";
-
-    /**
-     * Returns an alternative id for the property, using only ASCII characters.
-     *
-     * <p>
-     *     Although Java itself allows the full UTF character set for 
identifiers, some integrations (such as GraphQL)
-     *     have restrictions to only allow a more limited set of characters, 
in essence ASCII.
-     *     This attribute allows a version of the property's Id using only the 
ASCII character set to be provided.
-     * </p>
-     *
-     * @return an alternative id for the property, using only ASCII characters.
-     */
-    String asciiId() default "";
 }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/ascii/AsciiIdentifierService.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/ascii/AsciiIdentifierService.java
new file mode 100644
index 0000000000..b39ae2219a
--- /dev/null
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/ascii/AsciiIdentifierService.java
@@ -0,0 +1,20 @@
+package org.apache.causeway.applib.services.ascii;
+
+/**
+ * Optional SPI to provide an equivalent identifier using only ASCII character 
set, for the specified feature
+ * (a property, collection, action or action parameter).
+ *
+ * <p>
+ *     The GraphQL API (viewer) may require this SPI to be implemented if any 
of the features use non-ASCII characters,
+ *     because feature Ids are used as GraphQL (field) names.
+ * </p>
+ *
+ * @see <a href="https://spec.graphql.org/October2021/#sec-Names";>GraphQL 
specification</a>.
+ *
+ * @since 2.x {@index}
+ */
+public interface AsciiIdentifierService {
+
+    String asciiIdFor(String featureId);
+
+}
diff --git a/core/metamodel/src/main/java/module-info.java 
b/core/metamodel/src/main/java/module-info.java
index f8b25dc9d0..e3f8907630 100644
--- a/core/metamodel/src/main/java/module-info.java
+++ b/core/metamodel/src/main/java/module-info.java
@@ -145,7 +145,6 @@ open module org.apache.causeway.core.metamodel {
     exports org.apache.causeway.core.metamodel.services.grid.spi;
     exports org.apache.causeway.core.metamodel.facets.object.layout;
     exports org.apache.causeway.core.metamodel.facets.all.hide;
-    exports org.apache.causeway.core.metamodel.facets.all.ascii;
 
     requires jakarta.activation;
     requires java.annotation;
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/HasMetaModelContext.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/HasMetaModelContext.java
index 3702cb62f9..9b6e17bf58 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/HasMetaModelContext.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/HasMetaModelContext.java
@@ -22,6 +22,8 @@ import java.util.Optional;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
+import org.apache.causeway.applib.services.ascii.AsciiIdentifierService;
+
 import org.springframework.lang.Nullable;
 
 import org.apache.causeway.applib.locale.UserLocale;
@@ -196,6 +198,10 @@ public interface HasMetaModelContext {
         return 
getMetaModelContext().getServiceRegistry().lookupService(MessageBroker.class);
     }
 
+    public default AsciiIdentifierService getAsciiIdentifierService() {
+        return 
getMetaModelContext().getServiceRegistry().lookupService(AsciiIdentifierService.class).orElse(featureId
 -> featureId);
+    }
+
     default ManagedObject lookupServiceAdapterById(final String serviceId) {
         return getMetaModelContext().lookupServiceAdapterById(serviceId);
     }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/MetaModelContext.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/MetaModelContext.java
index 6ec16c6dcf..f53092ed8a 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/MetaModelContext.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/MetaModelContext.java
@@ -21,6 +21,8 @@ package org.apache.causeway.core.metamodel.context;
 import java.util.Optional;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.apache.causeway.applib.services.ascii.AsciiIdentifierService;
+
 import org.springframework.lang.Nullable;
 
 import org.apache.causeway.commons.internal.assertions._Assert;
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
index dde09ec048..c3b6272925 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
@@ -29,7 +29,6 @@ import 
org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.facetapi.FeatureType;
 import org.apache.causeway.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.causeway.core.metamodel.facets.actcoll.typeof.TypeOfFacet;
-import 
org.apache.causeway.core.metamodel.facets.actions.action.ascii.AsciiFacetForActionAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.actions.action.choicesfrom.ChoicesFromFacetForActionAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacetForActionAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet;
@@ -74,7 +73,6 @@ extends FacetFactoryAbstract {
         processChoicesFrom(processMethodContext, actionIfAny);
 
         processFileAccept(processMethodContext, actionIfAny);
-        processAsciiName(processMethodContext, actionIfAny);
     }
 
     Optional<Action> actionIfAny(final ProcessMethodContext 
processMethodContext) {
@@ -253,15 +251,5 @@ extends FacetFactoryAbstract {
                 .create(actionIfAny, holder));
     }
 
-    void processAsciiName(final ProcessMethodContext processMethodContext, 
final Optional<Action> actionIfAny) {
-
-        val holder = processMethodContext.getFacetHolder();
-
-        // check for @Action(ascii=...)
-        addFacetIfPresent(
-                AsciiFacetForActionAnnotation
-                .create(actionIfAny, holder));
-    }
-
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ascii/AsciiFacetForActionAnnotation.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ascii/AsciiFacetForActionAnnotation.java
deleted file mode 100644
index bb94ad1fd7..0000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/ascii/AsciiFacetForActionAnnotation.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  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.core.metamodel.facets.actions.action.ascii;
-
-import java.util.Optional;
-
-import org.apache.causeway.applib.annotation.Action;
-import org.apache.causeway.commons.internal.base._Strings;
-import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-import org.apache.causeway.core.metamodel.facets.FacetedMethod;
-import org.apache.causeway.core.metamodel.facets.all.ascii.AsciiFacet;
-import org.apache.causeway.core.metamodel.facets.all.ascii.AsciiFacetAbstract;
-
-public class AsciiFacetForActionAnnotation
-extends AsciiFacetAbstract {
-
-    public static Optional<AsciiFacet> create(
-            final Optional<Action> collectionIfAny,
-            final FacetedMethod facetHolder) {
-
-        return collectionIfAny
-                .map(Action::asciiId)
-                .filter(_Strings::isNotEmpty)
-                .map(asciiId -> new AsciiFacetForActionAnnotation(asciiId, 
facetHolder));
-    }
-
-    private AsciiFacetForActionAnnotation(
-            final String value, final FacetHolder holder) {
-        super(value, holder);
-    }
-
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/all/ascii/AsciiFacet.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/all/ascii/AsciiFacet.java
deleted file mode 100644
index c3775bba00..0000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/all/ascii/AsciiFacet.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- *  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.core.metamodel.facets.all.ascii;
-
-import org.apache.causeway.core.metamodel.facetapi.Facet;
-
-public interface AsciiFacet
-extends
-    Facet {
-
-    String asciiId();
-
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/all/ascii/AsciiFacetAbstract.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/all/ascii/AsciiFacetAbstract.java
deleted file mode 100644
index 41be0c0268..0000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/all/ascii/AsciiFacetAbstract.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  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.core.metamodel.facets.all.ascii;
-
-import org.apache.causeway.core.metamodel.facetapi.FacetAbstract;
-import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-
-/**
- * @since 2.0
- */
-public abstract class AsciiFacetAbstract
-extends FacetAbstract
-implements AsciiFacet {
-
-    private final String asciiId;
-
-    public static final Class<AsciiFacet> type() {
-        return AsciiFacet.class;
-    }
-
-    protected AsciiFacetAbstract(
-            final String asciiId,
-            final FacetHolder holder) {
-        super(type(), holder, Precedence.DEFAULT);
-        this.asciiId = asciiId;
-    }
-
-    @Override
-    public String asciiId() {
-        return asciiId;
-    }
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/collection/CollectionAnnotationFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/collection/CollectionAnnotationFacetFactory.java
index b5ae00f2f3..08d8c629b4 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/collection/CollectionAnnotationFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/collection/CollectionAnnotationFacetFactory.java
@@ -32,7 +32,6 @@ import 
org.apache.causeway.core.metamodel.facets.FacetedMethod;
 import org.apache.causeway.core.metamodel.facets.actcoll.typeof.TypeOfFacet;
 import 
org.apache.causeway.core.metamodel.facets.actions.contributing.ContributingFacetAbstract;
 import 
org.apache.causeway.core.metamodel.facets.actions.semantics.ActionSemanticsFacetAbstract;
-import 
org.apache.causeway.core.metamodel.facets.collections.collection.ascii.AsciiFacetForCollectionAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.collections.collection.modify.CollectionDomainEventFacet;
 import 
org.apache.causeway.core.metamodel.facets.collections.collection.typeof.TypeOfFacetForCollectionAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
@@ -61,7 +60,6 @@ extends FacetFactoryAbstract {
 
         processDomainEvent(processMethodContext, collectionIfAny);
         processTypeOf(processMethodContext, collectionIfAny);
-        processAsciiName(processMethodContext, collectionIfAny);
     }
 
     Optional<Collection> collectionIfAny(final ProcessMethodContext 
processMethodContext) {
@@ -124,14 +122,5 @@ extends FacetFactoryAbstract {
         });
     }
 
-    void processAsciiName(final ProcessMethodContext processMethodContext, 
final Optional<Collection> collectionIfAny) {
-
-        val holder = processMethodContext.getFacetHolder();
-
-        // check for @Collection(asciiId=...)
-        addFacetIfPresent(
-                AsciiFacetForCollectionAnnotation
-                        .create(collectionIfAny, holder));
-    }
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/collection/ascii/AsciiFacetForCollectionAnnotation.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/collection/ascii/AsciiFacetForCollectionAnnotation.java
deleted file mode 100644
index b2b9da8a41..0000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/collection/ascii/AsciiFacetForCollectionAnnotation.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  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.core.metamodel.facets.collections.collection.ascii;
-
-import java.util.Optional;
-
-import org.apache.causeway.applib.annotation.Collection;
-import org.apache.causeway.commons.internal.base._Strings;
-import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-import org.apache.causeway.core.metamodel.facets.FacetedMethod;
-import org.apache.causeway.core.metamodel.facets.all.ascii.AsciiFacet;
-import org.apache.causeway.core.metamodel.facets.all.ascii.AsciiFacetAbstract;
-
-public class AsciiFacetForCollectionAnnotation
-extends AsciiFacetAbstract {
-
-    public static Optional<AsciiFacet> create(
-            final Optional<Collection> collectionIfAny,
-            final FacetedMethod facetHolder) {
-
-        return collectionIfAny
-                .map(Collection::asciiId)
-                .filter(_Strings::isNotEmpty)
-                .map(asciiId -> new AsciiFacetForCollectionAnnotation(asciiId, 
facetHolder));
-    }
-
-    private AsciiFacetForCollectionAnnotation(
-            final String value, final FacetHolder holder) {
-        super(value, holder);
-    }
-
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/param/ascii/AsciiFacetForParameterAnnotation.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/param/ascii/AsciiFacetForParameterAnnotation.java
deleted file mode 100644
index c7d7f73d1f..0000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/param/ascii/AsciiFacetForParameterAnnotation.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *  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.core.metamodel.facets.param.ascii;
-
-import java.util.Optional;
-
-import org.apache.causeway.applib.annotation.Parameter;
-import org.apache.causeway.commons.internal.base._Strings;
-import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-import org.apache.causeway.core.metamodel.facets.all.ascii.AsciiFacet;
-import org.apache.causeway.core.metamodel.facets.all.ascii.AsciiFacetAbstract;
-
-public class AsciiFacetForParameterAnnotation
-extends AsciiFacetAbstract {
-
-    public static Optional<AsciiFacet> create(
-            final Optional<Parameter> collectionIfAny,
-            final FacetHolder facetHolder) {
-
-        return collectionIfAny
-                .map(Parameter::asciiId)
-                .filter(_Strings::isNotEmpty)
-                .map(asciiId -> new AsciiFacetForParameterAnnotation(asciiId, 
facetHolder));
-    }
-
-    private AsciiFacetForParameterAnnotation(
-            final String value, final FacetHolder holder) {
-        super(value, holder);
-    }
-
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/param/parameter/ParameterAnnotationFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/param/parameter/ParameterAnnotationFacetFactory.java
index 459a394ee6..d224e6f1f3 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/param/parameter/ParameterAnnotationFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/param/parameter/ParameterAnnotationFacetFactory.java
@@ -25,7 +25,6 @@ import org.apache.causeway.applib.annotation.Parameter;
 import org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.facetapi.FeatureType;
 import org.apache.causeway.core.metamodel.facets.FacetFactoryAbstract;
-import 
org.apache.causeway.core.metamodel.facets.param.ascii.AsciiFacetForParameterAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.param.parameter.fileaccept.FileAcceptFacetForParameterAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.param.parameter.mandatory.MandatoryFacetForParameterAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.param.parameter.mandatory.MandatoryFacetInvertedByNullableAnnotationOnParameter;
@@ -53,7 +52,6 @@ extends FacetFactoryAbstract {
         processParamsRegEx(processParameterContext);
         processParamsOptional(processParameterContext);
         processParamsFileAccept(processParameterContext);
-        processParamsAsciiId(processParameterContext);
     }
 
     // check for @Parameter(precedingParamsPolicy=...)
@@ -134,16 +132,5 @@ extends FacetFactoryAbstract {
                 .create(parameterIfAny, holder));
     }
 
-    void processParamsAsciiId(final ProcessParameterContext 
processParameterContext) {
-
-        val holder = processParameterContext.getFacetHolder();
-        val parameterIfAny = 
processParameterContext.synthesizeOnParameter(Parameter.class);
-
-        // check for @Parameter(asciiId=...)
-        addFacetIfPresent(
-                AsciiFacetForParameterAnnotation
-                        .create(parameterIfAny, holder));
-    }
-
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/properties/ascii/AsciiFacetForPropertyAnnotation.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/properties/ascii/AsciiFacetForPropertyAnnotation.java
deleted file mode 100644
index 9529053bdc..0000000000
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/properties/ascii/AsciiFacetForPropertyAnnotation.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  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.core.metamodel.facets.properties.ascii;
-
-import java.util.Optional;
-
-import org.apache.causeway.applib.annotation.Property;
-import org.apache.causeway.commons.internal.base._Strings;
-import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
-import org.apache.causeway.core.metamodel.facets.FacetedMethod;
-import org.apache.causeway.core.metamodel.facets.all.ascii.AsciiFacet;
-import org.apache.causeway.core.metamodel.facets.all.ascii.AsciiFacetAbstract;
-
-public class AsciiFacetForPropertyAnnotation
-extends AsciiFacetAbstract {
-
-    public static Optional<AsciiFacet> create(
-            final Optional<Property> collectionIfAny,
-            final FacetedMethod facetHolder) {
-
-        return collectionIfAny
-                .map(Property::asciiId)
-                .filter(_Strings::isNotEmpty)
-                .map(asciiId -> new AsciiFacetForPropertyAnnotation(asciiId, 
facetHolder));
-    }
-
-    private AsciiFacetForPropertyAnnotation(
-            final String value, final FacetHolder holder) {
-        super(value, holder);
-    }
-
-}
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
index 9c9c395cfb..a83aace192 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
@@ -37,7 +37,6 @@ import 
org.apache.causeway.core.metamodel.facets.members.publish.command.Command
 import 
org.apache.causeway.core.metamodel.facets.members.publish.execution.ExecutionPublishingFacet;
 import 
org.apache.causeway.core.metamodel.facets.members.publish.execution.ExecutionPublishingFacetForPropertyAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
-import 
org.apache.causeway.core.metamodel.facets.properties.ascii.AsciiFacetForPropertyAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.properties.projection.ProjectingFacetFromPropertyAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.properties.property.disabled.DisabledFacetForPropertyAnnotation;
 import 
org.apache.causeway.core.metamodel.facets.properties.property.entitychangepublishing.EntityPropertyChangePublishingPolicyFacetForPropertyAnnotation;
@@ -89,7 +88,6 @@ extends FacetFactoryAbstract {
         processOptional(processMethodContext, propertyIfAny);
         processRegEx(processMethodContext, propertyIfAny);
         processFileAccept(processMethodContext, propertyIfAny);
-        processAsciiName(processMethodContext, propertyIfAny);
     }
 
     Optional<Property> propertyIfAny(final ProcessMethodContext 
processMethodContext) {
@@ -326,14 +324,4 @@ extends FacetFactoryAbstract {
     }
 
 
-    void processAsciiName(final ProcessMethodContext processMethodContext, 
final Optional<Property> propertyIfAny) {
-
-        val holder = processMethodContext.getFacetHolder();
-
-        // check for @Property(asciiId=...)
-        addFacetIfPresent(
-                AsciiFacetForPropertyAnnotation
-                        .create(propertyIfAny, holder));
-    }
-
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectFeature.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectFeature.java
index 939a4e0e74..d1cf61f080 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectFeature.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectFeature.java
@@ -170,4 +170,5 @@ public interface ObjectFeature extends Specification {
         return !MandatoryFacet.isMandatory(this);
     }
 
+    String asciiId();
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionDefault.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionDefault.java
index 40515a0a18..1462849174 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionDefault.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionDefault.java
@@ -90,6 +90,11 @@ implements ObjectAction {
         return new ObjectActionDefault(facetedMethod.getFeatureIdentifier(), 
facetedMethod, true, false);
     }
 
+    @Override
+    public String asciiId() {
+        return 
getMetaModelContext().getAsciiIdentifierService().asciiIdFor(getId());
+    }
+
     /**
      * JUnit Support
      */
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
index 74a5774ac2..afa404db87 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
@@ -103,6 +103,11 @@ implements
         return javaSourceParamName;
     }
 
+    @Override
+    public String asciiId() {
+        return 
getMetaModelContext().getAsciiIdentifierService().asciiIdFor(getId());
+    }
+
     @Override
     public final String getFriendlyName(final Supplier<ManagedObject> 
domainObjectProvider) {
         //as we don't support imperative naming for parameters yet ..
@@ -382,6 +387,7 @@ implements
         return validResult.createConsent();
     }
 
+
     // -- CONTRACT
 
     @Override
@@ -389,4 +395,5 @@ implements
         return String.format("ObjectActionParameter[id=%s]", 
getFeatureIdentifier());
     }
 
+
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
index 300ed8f46a..98220ba449 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
@@ -326,4 +326,9 @@ implements
         return 
getServiceRegistry().lookupServiceElseFail(CommandDtoFactory.class);
     }
 
+    @Override
+    public String asciiId() {
+        return 
getMetaModelContext().getAsciiIdentifierService().asciiIdFor(getId());
+    }
+
 }
diff --git a/viewers/graphql/adoc/modules/ROOT/pages/i18n.adoc 
b/viewers/graphql/adoc/modules/ROOT/pages/i18n.adoc
index 3559769d2a..ef31b47f03 100644
--- a/viewers/graphql/adoc/modules/ROOT/pages/i18n.adoc
+++ b/viewers/graphql/adoc/modules/ROOT/pages/i18n.adoc
@@ -3,12 +3,12 @@
 :Notice: 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 ag [...]
 
 
-The GraphQL Specification 
(link:https://spec.graphql.org/June2018/#sec-Names[]) requires that names of 
fields and types use only a subset of ASCII characters.
+The GraphQL Specification 
(link:https://spec.graphql.org/October2021/#sec-Names[]) requires that names of 
fields and types use only a subset of ASCII characters.
 On the other hand the GraphQL viewer will infer these fields from the Java 
domain objects, which permits a wider range of characters.
 
-To ensure that only permitted characters are used in the GraphQL model, use 
the 
xref:refguide:applib:index/annotation/Property.adoc#asciiId[@Property#asciiId], 
xref:refguide:applib:index/annotation/Collection.adoc#asciiId[@Collection#asciiId],
 xref:refguide:applib:index/annotation/Action.adoc#asciiId[@Action#asciiId] and 
xref:refguide:applib:index/annotation/Parameter.adoc#asciiId[@Parameter#asciiId].
+To ensure that only permitted characters are used in the GraphQL model, 
provide an implementation of the 
xref:refguide:applib:index/services/ascii/AsciiIdentifierService.adoc[AsciiIdentifierService].
 
-For example:
+For example, suppose this class is part of the domain:
 
 [source,java]
 .I18nCalculator
@@ -19,13 +19,28 @@ For example:
 @RequiredArgsConstructor(onConstructor_ = {@Inject})
 public class I18nCalculator {
 
-    @Action(semantics = SemanticsOf.SAFE, asciiId = "concat")
+    @Action(semantics = SemanticsOf.SAFE)
     public String concät(
-            @Parameter(asciiId = "a1")
             String ä1,
-            @Parameter(asciiId = "a2")
             String ä2) {
         return ä1 + ä2;
     }
 }
 ----
+
+As this service uses a non-ASCII character, `ä`, we need to provide a service 
to convert it:
+
+[source,java]
+.AsciiIdentifierServiceSupportingGraphqlViewer
+----
+@Service
+public class AsciiIdentifierServiceSupportingGraphqlViewer
+    implements AsciiIdentifierService {
+
+    public String asciiIdFor(String featureId) {
+        return featureId.replace("ä", "a");
+    }
+}
+----
+
+This implementation could be fairly easily be extended for other Latin 
languages, but non-Latin languages such as Kanji would obviously need a more 
sophisticated implementation.
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/context/Context.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/context/Context.java
index 9197026363..6b824e790d 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/context/Context.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/context/Context.java
@@ -31,6 +31,8 @@ import graphql.schema.GraphQLEnumType;
 import static graphql.schema.GraphQLEnumType.newEnum;
 import static graphql.schema.GraphQLEnumValueDefinition.newEnumValueDefinition;
 
+import org.apache.causeway.core.metamodel.spec.feature.ObjectFeature;
+import org.apache.causeway.core.metamodel.spec.feature.OneToOneActionParameter;
 import org.springframework.stereotype.Component;
 
 import org.apache.causeway.applib.id.HasLogicalType;
@@ -121,5 +123,4 @@ public class Context {
                 )
                 .build();
     }
-
 }
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/TypeNames.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/TypeNames.java
index 7ea62fc73d..4fa5bf1e1f 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/TypeNames.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/TypeNames.java
@@ -64,7 +64,7 @@ public final class TypeNames {
             final ObjectSpecification owningType,
             final ObjectAction oa,
             final SchemaType schemaType) {
-        return objectTypeNameFor(owningType, schemaType) + "__" + 
ObjectFeatureUtils.asciiIdFor(oa) + "__gqlv_action";
+        return objectTypeNameFor(owningType, schemaType) + "__" + oa.asciiId() 
+ "__gqlv_action";
     }
 
     public static String actionInvokeTypeNameFor(
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/ObjectFeatureUtils.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/ObjectFeatureUtils.java
index 6001d9fedf..c6f890a074 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/ObjectFeatureUtils.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/ObjectFeatureUtils.java
@@ -25,7 +25,6 @@ import java.util.stream.Collectors;
 
 import org.apache.causeway.applib.services.bookmark.Bookmark;
 import org.apache.causeway.commons.collections.Can;
-import org.apache.causeway.core.metamodel.facets.all.ascii.AsciiFacet;
 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;
@@ -154,8 +153,7 @@ public class ObjectFeatureUtils {
     }
 
     public static String asciiIdFor(final ObjectFeature objectFeature) {
-        val asciiFacet = objectFeature.getFacet(AsciiFacet.class);
-        return asciiFacet != null ? asciiFacet.asciiId() : 
objectFeature.getId();
+        return objectFeature.getId();
     }
 
     private static ManagedObject adaptValue(
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/simple/query/SimpleAction.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/simple/query/SimpleAction.java
index ed65e8c24f..566c8d0734 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/simple/query/SimpleAction.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/simple/query/SimpleAction.java
@@ -284,7 +284,7 @@ public class SimpleAction
             final OneToOneActionParameter otoap,
             final TypeMapper.InputContext inputContext) {
         return GraphQLArgument.newArgument()
-                .name(ObjectFeatureUtils.asciiIdFor(otoap))
+                .name(otoap.asciiId())
                 .type(context.typeMapper.inputTypeFor(otoap, inputContext, 
objectInteractor.getSchemaType()))
                 .build();
     }
diff --git 
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/i18n/AsciiIdentifierServiceSupportingGraphqlViewer.java
 
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/i18n/AsciiIdentifierServiceSupportingGraphqlViewer.java
new file mode 100644
index 0000000000..0cb18bd068
--- /dev/null
+++ 
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/i18n/AsciiIdentifierServiceSupportingGraphqlViewer.java
@@ -0,0 +1,13 @@
+package org.apache.causeway.viewer.graphql.viewer.test.domain.i18n;
+
+import org.apache.causeway.applib.services.ascii.AsciiIdentifierService;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class AsciiIdentifierServiceSupportingGraphqlViewer implements 
AsciiIdentifierService {
+    @Override
+    public String asciiIdFor(String featureId) {
+        return featureId.replace("ä", "a");
+    }
+}
diff --git 
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/i18n/I18nCalculator.java
 
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/i18n/I18nCalculator.java
index 4e4db46f22..f60aed3a5c 100644
--- 
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/i18n/I18nCalculator.java
+++ 
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/i18n/I18nCalculator.java
@@ -19,11 +19,9 @@ import lombok.RequiredArgsConstructor;
 @RequiredArgsConstructor(onConstructor_ = {@Inject})
 public class I18nCalculator {
 
-    @Action(semantics = SemanticsOf.SAFE, asciiId = "concat")
+    @Action(semantics = SemanticsOf.SAFE)
     public String concät(
-            @Parameter(asciiId = "a1")
             String ä1,
-            @Parameter(asciiId = "a2")
             String ä2) {
         return ä1 + ä2;
     }


Reply via email to