You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/08/11 13:29:25 UTC

[isis] branch master updated: ISIS-3119: refactors IdStringifierLookupService into IdStringifierService

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 8a39779183 ISIS-3119: refactors IdStringifierLookupService into IdStringifierService
8a39779183 is described below

commit 8a39779183e51ad4ac23155e39c97198af14a7c9
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Aug 11 15:29:18 2022 +0200

    ISIS-3119: refactors IdStringifierLookupService into
    IdStringifierService
    
    - that is, with a more focused responsibility (for internal use by
    entity facets)
---
 .../applib/services/bookmark/IdStringifier.java    |  2 +-
 .../isis/core/runtime/IsisModuleCoreRuntime.java   |  4 +-
 ...ookupService.java => IdStringifierService.java} | 58 ++++++++++++++--------
 .../metamodel/facets/entity/JdoEntityFacet.java    | 20 ++------
 .../jpa/integration/entity/JpaEntityFacet.java     | 25 +++-------
 5 files changed, 50 insertions(+), 59 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/IdStringifier.java b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/IdStringifier.java
index f8ad36560c..c585083f2f 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/IdStringifier.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/IdStringifier.java
@@ -44,7 +44,7 @@ import lombok.val;
  *     An example of such is the JPA implementation of the <code>commandlog</code> extension.
  * </p>
  *
- * @since 2.x {@index}
+ * @since 2.0 {@index}
  */
 public interface IdStringifier<T> {
 
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/IsisModuleCoreRuntime.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/IsisModuleCoreRuntime.java
index 063ea58bd9..dd5a2de831 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/IsisModuleCoreRuntime.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/IsisModuleCoreRuntime.java
@@ -25,7 +25,7 @@ import org.apache.isis.core.interaction.IsisModuleCoreInteraction;
 import org.apache.isis.core.metamodel.IsisModuleCoreMetamodel;
 import org.apache.isis.core.runtime.events.MetamodelEventService;
 import org.apache.isis.core.runtime.events.TransactionEventEmitter;
-import org.apache.isis.core.runtime.idstringifier.IdStringifierLookupService;
+import org.apache.isis.core.runtime.idstringifier.IdStringifierService;
 import org.apache.isis.core.transaction.IsisModuleCoreTransaction;
 import org.apache.isis.valuetypes.jodatime.integration.IsisModuleValJodatimeIntegration;
 
@@ -42,7 +42,7 @@ import org.apache.isis.valuetypes.jodatime.integration.IsisModuleValJodatimeInte
         // @Service's
         MetamodelEventService.class,
         TransactionEventEmitter.class,
-        IdStringifierLookupService.class,
+        IdStringifierService.class,
 
         // @Configuration's
 
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/idstringifier/IdStringifierLookupService.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/idstringifier/IdStringifierService.java
similarity index 63%
rename from core/runtime/src/main/java/org/apache/isis/core/runtime/idstringifier/IdStringifierLookupService.java
rename to core/runtime/src/main/java/org/apache/isis/core/runtime/idstringifier/IdStringifierService.java
index 4bb0cebd6a..8a27baccef 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/idstringifier/IdStringifierLookupService.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/idstringifier/IdStringifierService.java
@@ -35,9 +35,11 @@ import org.springframework.stereotype.Service;
 import org.springframework.util.ClassUtils;
 
 import org.apache.isis.applib.annotation.PriorityPrecedence;
+import org.apache.isis.applib.annotation.ValueSemantics;
 import org.apache.isis.applib.services.bookmark.IdStringifier;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Casts;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.runtime.IsisModuleCoreRuntime;
 
 import lombok.NonNull;
@@ -46,24 +48,27 @@ import lombok.val;
 /**
  * Convenience service that looks up (and caches) the {@link IdStringifier}
  * available for a given value class, and optionally the class of the owning entity.
- *
  * <p>
- *     This is intended for framework use, there is little reason to call it or override it.
- * </p>
+ * This is intended for framework use, there is little reason to call it or override it.
+ *
+ * @implNote yet does not support per member ValueSemantics selection;
+ *      future work would look for {@link ValueSemantics} annotations on primary key members and
+ *      would then honor {@link ValueSemantics#provider()} attribute,
+ *      to narrow the {@link IdStringifier} search
  *
  * @since 2.0
  */
 @Service
-@Named(IsisModuleCoreRuntime.NAMESPACE + ".IdStringifierLookupService")
+@Named(IsisModuleCoreRuntime.NAMESPACE + ".IdStringifierService")
 @Priority(PriorityPrecedence.MIDPOINT)
 @Qualifier("Default")
-public class IdStringifierLookupService {
+public class IdStringifierService {
 
     private final Can<IdStringifier<?>> idStringifiers;
     private final Map<Class<?>, IdStringifier<?>> stringifierByClass = new ConcurrentHashMap<>();
 
     @Inject
-    public IdStringifierLookupService(
+    public IdStringifierService(
             final List<IdStringifier<?>> idStringifiers,
             final Optional<IdStringifier<Serializable>> idStringifierForSerializableIfAny) {
         // IdStringifierForSerializable is enforced to go last, so any custom IdStringifier(s)
@@ -77,22 +82,33 @@ public class IdStringifierLookupService {
         this.idStringifiers = Can.ofCollection(idStringifiers);
     }
 
-    public <T> IdStringifier<T> lookupElseFail(final Class<T> candidateValueClass) {
-        val idStringifier = stringifierByClass.computeIfAbsent(candidateValueClass, aClass -> {
-            for (val candidateStringifier : idStringifiers) {
-                if (handles(candidateStringifier, candidateValueClass)) {
-                    return candidateStringifier;
-                }
-            }
-            return null;
-        });
-        return Optional.<IdStringifier<T>>ofNullable(_Casts.uncheckedCast(idStringifier))
-                .orElseThrow(() -> new IllegalStateException(
-                        String.format("Could not locate an IdStringifier to handle '%s'",
-                                candidateValueClass)));
+    public <T> String enstringPrimaryKey(final @NonNull Class<T> primaryKeyType, final @NonNull Object primaryKey) {
+        val idStringifier = lookupElseFail(ClassUtils.resolvePrimitiveIfNecessary(primaryKeyType));
+        return idStringifier.enstring(_Casts.uncheckedCast(primaryKey));
+    }
+
+    public <T> T destringPrimaryKey(
+            final @NonNull Class<T> primaryKeyType,
+            final @NonNull Class<?> entityClass,
+            final @NonNull String stringifiedId) {
+        val idStringifier = lookupElseFail(ClassUtils.resolvePrimitiveIfNecessary(primaryKeyType));
+        @SuppressWarnings("unchecked")
+        val primaryKey = _Casts.castTo(IdStringifier.SupportingTargetEntityClass.class, idStringifier)
+                .map(stringifier->stringifier.destring(stringifiedId, entityClass))
+                .orElseGet(()->idStringifier.destring(stringifiedId));
+        return _Casts.uncheckedCast(primaryKey);
     }
 
-    public <T> Optional<IdStringifier<T>> lookup(final Class<T> candidateValueClass) {
+    // -- HELPER
+
+    private <T> IdStringifier<T> lookupElseFail(final Class<T> candidateValueClass) {
+        return lookup(candidateValueClass)
+            .orElseThrow(() -> _Exceptions.noSuchElement(
+                    "Could not locate an IdStringifier to handle '%s'",
+                    candidateValueClass));
+    }
+
+    private <T> Optional<IdStringifier<T>> lookup(final Class<T> candidateValueClass) {
         val idStringifier = stringifierByClass.computeIfAbsent(candidateValueClass, aClass -> {
             for (val candidateStringifier : idStringifiers) {
                 if (handles(candidateStringifier, candidateValueClass)) {
@@ -104,8 +120,6 @@ public class IdStringifierLookupService {
         return Optional.ofNullable(_Casts.uncheckedCast(idStringifier));
     }
 
-    // -- HELPER
-
     private boolean handles(final IdStringifier<?> idStringifier, final @NonNull Class<?> candidateValueClass) {
         return idStringifier.getCorrespondingClass()
                 .isAssignableFrom(ClassUtils.resolvePrimitiveIfNecessary(candidateValueClass));
diff --git a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
index 45f987cd2e..256407fdb5 100644
--- a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
+++ b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
@@ -37,7 +37,6 @@ import org.apache.isis.applib.query.AllInstancesQuery;
 import org.apache.isis.applib.query.NamedQuery;
 import org.apache.isis.applib.query.Query;
 import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.bookmark.IdStringifier;
 import org.apache.isis.applib.services.exceprecog.Category;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerService;
 import org.apache.isis.applib.services.repository.EntityState;
@@ -45,7 +44,6 @@ import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.applib.services.xactn.TransactionalProcessor;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.assertions._Assert;
-import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.debug._Debug;
@@ -59,7 +57,7 @@ import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.services.objectlifecycle.ObjectLifecyclePublisher;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.runtime.idstringifier.IdStringifierLookupService;
+import org.apache.isis.core.runtime.idstringifier.IdStringifierService;
 import org.apache.isis.persistence.jdo.datanucleus.entities.DnEntityStateProvider;
 import org.apache.isis.persistence.jdo.metamodel.facets.object.persistencecapable.JdoPersistenceCapableFacetFactory;
 import org.apache.isis.persistence.jdo.provider.entities.JdoFacetContext;
@@ -84,7 +82,7 @@ implements EntityFacet {
     @Inject private ObjectManager objectManager;
     @Inject private ExceptionRecognizerService exceptionRecognizerService;
     @Inject private JdoFacetContext jdoFacetContext;
-    @Inject private IdStringifierLookupService idStringifierLookupService;
+    @Inject private IdStringifierService idStringifierService;
 
     private final Class<?> entityClass;
 
@@ -135,11 +133,7 @@ implements EntityFacet {
                     pojo.getClass().getName());
         }
 
-
-        val primaryKeyType = primaryKey.getClass();
-        val idStringifier = _Casts.<IdStringifier<Object>>uncheckedCast(idStringifierLookupService.lookupElseFail(primaryKeyType));
-
-        return idStringifier.enstring(primaryKey);
+        return idStringifierService.enstringPrimaryKey(primaryKeyTypeFor(entityClass), primaryKey);
     }
 
 
@@ -153,12 +147,8 @@ implements EntityFacet {
         try {
 
             val persistenceManager = getPersistenceManager();
-            val primaryKeyType = primaryKeyTypeFor(entityClass);
-
-            val idStringifier = idStringifierLookupService.lookupElseFail(primaryKeyType);
-            val primaryKey = _Casts.castTo(IdStringifier.SupportingTargetEntityClass.class, idStringifier)
-                    .map(stringifier->stringifier.destring(bookmark.getIdentifier(), entityClass))
-                    .orElseGet(()->idStringifier.destring(bookmark.getIdentifier()));
+            val primaryKey = idStringifierService
+                    .destringPrimaryKey(primaryKeyTypeFor(entityClass), entityClass, bookmark.getIdentifier());
 
             val fetchPlan = persistenceManager.getFetchPlan();
             fetchPlan.addGroup(FetchGroup.DEFAULT);
diff --git a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/entity/JpaEntityFacet.java b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/entity/JpaEntityFacet.java
index fa7097205b..5a64c89efc 100644
--- a/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/entity/JpaEntityFacet.java
+++ b/persistence/jpa/integration/src/main/java/org/apache/isis/persistence/jpa/integration/entity/JpaEntityFacet.java
@@ -34,7 +34,6 @@ import org.apache.isis.applib.query.AllInstancesQuery;
 import org.apache.isis.applib.query.NamedQuery;
 import org.apache.isis.applib.query.Query;
 import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.bookmark.IdStringifier;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.repository.EntityState;
 import org.apache.isis.commons.collections.Can;
@@ -47,7 +46,7 @@ import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.object.entity.EntityFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.runtime.idstringifier.IdStringifierLookupService;
+import org.apache.isis.core.runtime.idstringifier.IdStringifierService;
 
 import lombok.NonNull;
 import lombok.val;
@@ -60,7 +59,7 @@ public class JpaEntityFacet
 
     private final Class<?> entityClass;
     private final ServiceRegistry serviceRegistry;
-    private final IdStringifierLookupService idStringifierLookupService;
+    private final IdStringifierService idStringifierService;
 
     protected JpaEntityFacet(
             final FacetHolder holder,
@@ -70,7 +69,7 @@ public class JpaEntityFacet
         super(EntityFacet.class, holder, Precedence.HIGH);
         this.entityClass = entityClass;
         this.serviceRegistry = serviceRegistry;
-        this.idStringifierLookupService = serviceRegistry.lookupServiceElseFail(IdStringifierLookupService.class);
+        this.idStringifierService = serviceRegistry.lookupServiceElseFail(IdStringifierService.class);
     }
 
     // -- ENTITY FACET
@@ -101,17 +100,7 @@ public class JpaEntityFacet
                     pojo.getClass().getName());
         }
 
-        val primaryKeyType = getPrimaryKeyType();
-        return identifierFor(primaryKeyType, _Casts.uncheckedCast(primaryKey));
-    }
-
-    private <T> String identifierFor(final Class<T> primaryKeyType, final T primaryKey) {
-        val stringifier = lookupIdStringifier(primaryKeyType);
-        return stringifier.enstring(primaryKey);
-    }
-
-    private <T> IdStringifier<T> lookupIdStringifier(final Class<T> primaryKeyType) {
-        return _Casts.uncheckedCast(idStringifierLookupService.lookupElseFail(primaryKeyType));
+        return idStringifierService.enstringPrimaryKey(getPrimaryKeyType(), primaryKey);
     }
 
     @Override
@@ -120,10 +109,8 @@ public class JpaEntityFacet
 
         log.debug("fetchEntity; bookmark={}", bookmark);
 
-        val idStringifier = lookupIdStringifier(getPrimaryKeyType());
-        val primaryKey = _Casts.castTo(IdStringifier.SupportingTargetEntityClass.class, idStringifier)
-                .map(stringifier->stringifier.destring(bookmark.getIdentifier(), entityClass))
-                .orElseGet(()->idStringifier.destring(bookmark.getIdentifier()));
+        val primaryKey = idStringifierService
+                .destringPrimaryKey(getPrimaryKeyType(), entityClass, bookmark.getIdentifier());
 
         val entityManager = getEntityManager();
         val entityPojo = entityManager.find(entityClass, primaryKey);