You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2026/05/18 04:48:42 UTC

(causeway) branch main updated: CAUSEWAY-3997: ListingUtil: allow for more advanced line adapters

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

andi-huber pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/main by this push:
     new 03c17f0d837 CAUSEWAY-3997: ListingUtil: allow for more advanced line adapters
03c17f0d837 is described below

commit 03c17f0d837c28b0a7c76e829830c358ace004b8
Author: andi-huber <ah...@apache.org>
AuthorDate: Mon May 18 06:48:32 2026 +0200

    CAUSEWAY-3997: ListingUtil: allow for more advanced line adapters
---
 .../columnorder/Object_patchColumnOrder.java       |  5 +-
 .../org/apache/causeway/applib/util/Listing.java   | 71 +++++++++++++++-------
 .../apache/causeway/applib/util/ListingTest.java   | 15 +++--
 3 files changed, 58 insertions(+), 33 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/causeway/applib/services/columnorder/Object_patchColumnOrder.java b/api/applib/src/main/java/org/apache/causeway/applib/services/columnorder/Object_patchColumnOrder.java
index 118dcdb5949..bf6fc9c53bc 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/services/columnorder/Object_patchColumnOrder.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/services/columnorder/Object_patchColumnOrder.java
@@ -45,7 +45,6 @@
 import org.apache.causeway.applib.services.metamodel.MetaModelService;
 import org.apache.causeway.applib.services.metamodel.MetaModelService.AssociationsLookup;
 import org.apache.causeway.applib.util.Listing;
-import org.apache.causeway.applib.util.Listing.ListingHandler;
 import org.apache.causeway.applib.util.Listing.MergePolicy;
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.internal.exceptions._Exceptions;
@@ -157,8 +156,8 @@ private Listing<String> listing(final Stream<Identifier> availableIds, final Str
         return enabled.merge(MergePolicy.ADD_NEW_AS_DISABLED, available);
     }
 
-    private final static ListingHandler<String> listingHandler() {
-    	return new ListingHandler<>(String.class, UnaryOperator.identity(), UnaryOperator.identity(), UnaryOperator.identity());
+    private final static Listing.LineAdapter<String> listingHandler() {
+    	return Listing.lineAdapter(String.class, UnaryOperator.identity(), UnaryOperator.identity(), UnaryOperator.identity());
     }
 
 }
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/util/Listing.java b/api/applib/src/main/java/org/apache/causeway/applib/util/Listing.java
index cb3b5d0ca2e..73a8ef836db 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/util/Listing.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/util/Listing.java
@@ -50,36 +50,37 @@
  */
 @Programmatic
 public record Listing<T>(
-        @NonNull ListingHandler<T> handler,
+        @NonNull LineAdapter<T> lineAdapter,
         @NonNull Can<Line> lines) {
 
-    public record ListingHandler<T> (
-            @NonNull Class<T> objectType,
-            @NonNull Function<T, String> stringifier,
-            @NonNull Function<String, T> destringifier,
-            @NonNull Function<T, ?> keyExtractor) {
+	public interface LineAdapter<T> {
+		Class<T> objectType();
+		String stringify(T t);
+        T destringify(String literal);
+        Object extractKey(T t);
 
         // -- LISTING FACTORIES
 
-        public Listing<T> emptyListing() {
+		default Listing<T> emptyListing() {
             return createListing(Can.empty());
         }
 
-        public Listing<T> createListing(@Nullable final Iterable<T> enabledElements) {
+		default Listing<T> createListing(@Nullable final Iterable<T> enabledElements) {
             return createListing(_NullSafe.stream(enabledElements));
         }
-        public Listing<T> createListing(@Nullable final Stream<T> enabledElementStream) {
-            if(enabledElementStream==null) return emptyListing();
+		default Listing<T> createListing(@Nullable final Stream<T> enabledElementStream) {
+            if(enabledElementStream==null)
+            	return emptyListing();
             return new Listing<>(this, enabledElementStream
-                    .map(t->new LineEnabled<>(t, stringifier().apply(t)))
+                    .map(t->new LineEnabled<>(t, stringify(t)))
                     .collect(Can.toCan()));
         }
 
-        public Listing<T> parseListing(@Nullable final String wholeText) {
+		default Listing<T> parseListing(@Nullable final String wholeText) {
             if(wholeText==null) return emptyListing();
             return parseListing(TextUtils.readLines(wholeText));
         }
-        public Listing<T> parseListing(@Nullable final Can<String> textLines) {
+		default Listing<T> parseListing(@Nullable final Can<String> textLines) {
             if(textLines==null) return emptyListing();
             return new Listing<>(this, textLines.map(this::parseLine));
         }
@@ -92,7 +93,7 @@ public Listing<T> parseListing(@Nullable final Can<String> textLines) {
          * <p>If a line is not a comment, but can also not be mapped to {@code T},
          * then it is commented out.
          */
-        public Line parseLine(final String wholeLine) {
+		default Line parseLine(final String wholeLine) {
             final var line = wholeLine.trim();
             if(line.isBlank())
                 return new LineComment(line);
@@ -120,9 +121,35 @@ line, objectType().getSimpleName(), e)))
         // -- HELPER
 
         private Try<T> asT(final String stringified) {
-            return Try.call(()->destringifier().apply(stringified));
+            return Try.call(()->destringify(stringified));
         }
 
+	}
+
+    // -- ADAPTERS
+
+	public static <T> LineAdapter<T> lineAdapter(
+            @NonNull final Class<T> objectType,
+            @NonNull final Function<T, String> stringifier,
+            @NonNull final Function<String, T> destringifier,
+            @NonNull final Function<T, ?> keyExtractor) {
+		return new SimpleLineAdapter<>(objectType, stringifier, destringifier, keyExtractor);
+	}
+
+    private record SimpleLineAdapter<T> (
+            @NonNull Class<T> objectType,
+            @NonNull Function<T, String> stringifier,
+            @NonNull Function<String, T> destringifier,
+            @NonNull Function<T, ?> keyExtractor) implements LineAdapter<T> {
+		@Override public String stringify(final T t) {
+			return stringifier.apply(t);
+		}
+	    @Override public T destringify(final String literal) {
+			return destringifier.apply(literal);
+		}
+	    @Override public Object extractKey(final T t) {
+			return keyExtractor.apply(t);
+		}
     }
 
     public sealed interface Line
@@ -249,11 +276,11 @@ public enum MergePolicy {
     public <K> Listing<T> merge(@NonNull final MergePolicy policy, @Nullable final Listing<T> newerVersion) {
         if(newerVersion==null) return this;
         final Map<Object, LineEnabled<T>> incomingByKey = newerVersion.streamEnabledLines()
-                .collect(Collectors.toMap(
-                        line->handler().keyExtractor().apply(line.object()),
-                        UnaryOperator.identity(),
-                        (a, b)->a,
-                        LinkedHashMap::new));
+            .collect(Collectors.toMap(
+                line->lineAdapter().extractKey(line.object()),
+                UnaryOperator.identity(),
+                (a, b)->a,
+                LinkedHashMap::new));
         if(incomingByKey.isEmpty()) return this;
 
         var mergedLines = new ArrayList<Line>();
@@ -265,7 +292,7 @@ public <K> Listing<T> merge(@NonNull final MergePolicy policy, @Nullable final L
         .forEach((final Line line)->{
             @SuppressWarnings("unchecked")
             var key = (line instanceof MappedLine mappedLine)
-                    ? handler().keyExtractor().apply((T) mappedLine.object())
+                    ? lineAdapter().extractKey((T) mappedLine.object())
                     : null;
             final boolean incomingContainsKey = key!=null
                     ? incomingByKey.remove(key)!=null
@@ -309,7 +336,7 @@ public <K> Listing<T> merge(@NonNull final MergePolicy policy, @Nullable final L
             }
         }
 
-        return new Listing<>(handler, Can.ofCollection(mergedLines));
+        return new Listing<>(lineAdapter, Can.ofCollection(mergedLines));
     }
 
 }
diff --git a/api/applib/src/test/java/org/apache/causeway/applib/util/ListingTest.java b/api/applib/src/test/java/org/apache/causeway/applib/util/ListingTest.java
index 459cfd8c588..f16bb0b9357 100644
--- a/api/applib/src/test/java/org/apache/causeway/applib/util/ListingTest.java
+++ b/api/applib/src/test/java/org/apache/causeway/applib/util/ListingTest.java
@@ -25,7 +25,7 @@
 
 import org.springframework.util.StringUtils;
 
-import org.apache.causeway.applib.util.Listing.ListingHandler;
+import org.apache.causeway.applib.util.Listing.LineAdapter;
 import org.apache.causeway.applib.util.Listing.MergePolicy;
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.io.TextUtils;
@@ -60,10 +60,9 @@ static Customer destringify(final String input) {
         }
     }
 
-    private final ListingHandler<Customer> listingHandler =
-            new ListingHandler<>(Customer.class, Customer::stringify, Customer::destringify, Customer::id);
-    private final Listing<Customer> listing =
-            sampleListing(listingHandler);
+    private final LineAdapter<Customer> lineAdapter = Listing
+    		.lineAdapter(Customer.class, Customer::stringify, Customer::destringify, Customer::id);
+    private final Listing<Customer> listing = sampleListing(lineAdapter);
 
     @Test
     void parsing() {
@@ -106,7 +105,7 @@ void merging() {
                 [c] Henry
                 [d] Martha
                 """;
-        var updateListing = listingHandler.parseListing(upd);
+        var updateListing = lineAdapter.parseListing(upd);
         var merged = listing.merge(MergePolicy.ADD_NEW_AS_DISABLED, updateListing);
         String expectedOutputAfterMerge = """
                 # this is a regular comment
@@ -129,7 +128,7 @@ void merging() {
 
     // -- HELPER
 
-    private Listing<Customer> sampleListing(final ListingHandler<Customer> listingHandler) {
+    private Listing<Customer> sampleListing(final LineAdapter<Customer> lineAdapter) {
         String input = """
                 # this is a regular comment
                 [a] Jeff
@@ -140,7 +139,7 @@ private Listing<Customer> sampleListing(final ListingHandler<Customer> listingHa
 
                 [b] Jane
                 """;
-        return listingHandler.parseListing(input);
+        return lineAdapter.parseListing(input);
     }
 
     private static void assertTextLinesMatch(final String a, final String b) {