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

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


The following commit(s) were added to refs/heads/v4 by this push:
     new 4a1aacefab2 CAUSEWAY-3889: adds Markup factory method for image 
embedding
4a1aacefab2 is described below

commit 4a1aacefab293c497535e562e4e5cc1b08ccd331
Author: a.huber <[email protected]>
AuthorDate: Mon Aug 18 06:38:59 2025 +0200

    CAUSEWAY-3889: adds Markup factory method for image embedding
---
 .../org/apache/causeway/applib/value/Markup.java   | 24 +++++++++-
 .../causeway/applib/value/NamedWithMimeType.java   | 19 +++++++-
 commons/src/main/java/module-info.java             |  1 +
 .../org/apache/causeway/commons/net}/DataUri.java  |  6 ++-
 .../apache/causeway/commons/net}/DataUriTest.java  |  4 +-
 .../CausewayModuleCoreRuntimeServices.java         |  5 +--
 .../icons/ObjectIconServiceDefault.java            | 51 ++++++++++++----------
 7 files changed, 79 insertions(+), 31 deletions(-)

diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/value/Markup.java 
b/api/applib/src/main/java/org/apache/causeway/applib/value/Markup.java
index de346f815e7..0e21a70cfcc 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/value/Markup.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/value/Markup.java
@@ -21,17 +21,23 @@
 import java.io.Serializable;
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import jakarta.inject.Named;
 import jakarta.xml.bind.annotation.adapters.XmlAdapter;
 import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
+import org.jspecify.annotations.Nullable;
+
 import org.apache.causeway.applib.CausewayModuleApplib;
 import org.apache.causeway.applib.annotation.Value;
+import org.apache.causeway.applib.value.NamedWithMimeType.ImageType;
 import org.apache.causeway.commons.internal.base._Strings;
 import org.apache.causeway.commons.internal.base._Text;
 import org.apache.causeway.commons.io.TextUtils;
+import org.apache.causeway.commons.net.DataUri;
+import org.apache.causeway.commons.net.DataUri.Encoding;
 
 /**
  * Intended to be used as a read-only property, to render plain HTML.
@@ -43,10 +49,26 @@
 @XmlJavaTypeAdapter(Markup.JaxbToStringAdapter.class)   // for JAXB view model 
support
 public record Markup(String html) implements Serializable {
 
-    public static Markup valueOf(final String html) {
+    // -- FACTORIES
+
+    public static Markup valueOf(final @Nullable String html) {
         return new Markup(html);
     }
 
+    public static Markup embeddedImage(final @Nullable DataUri dataUri) {
+        return dataUri!=null
+                ? new Markup("<img src=\"" + dataUri.toExternalForm() + "\"/>")
+                : new Markup(null);
+    }
+
+    public static Markup embeddedImage(final ImageType imageType, byte[] 
imageData) {
+        Objects.requireNonNull(imageType);
+        Objects.requireNonNull(imageData);
+        return embeddedImage(new DataUri(imageType.mimeType().getBaseType(), 
null, Encoding.BASE64, imageData));
+    }
+
+    // -- CONSTRUCTION
+
     public Markup() {
         this(null);
     }
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/value/NamedWithMimeType.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/value/NamedWithMimeType.java
index ba2e373243f..7b9fb036811 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/value/NamedWithMimeType.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/value/NamedWithMimeType.java
@@ -31,6 +31,8 @@
 import org.apache.causeway.commons.internal.base._Strings;
 
 import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.experimental.Accessors;
 
 /**
  * @since 1.x {@index}
@@ -62,12 +64,27 @@ default int compareTo(final NamedWithMimeType o) {
                     : null);
     }
 
+    @RequiredArgsConstructor
+    @Getter @Accessors(fluent=true)
+    public enum ImageType {
+        BMP(CommonMimeType.BMP),
+        GIF(CommonMimeType.GIF),
+        ICO(CommonMimeType.ICO),
+        JPEG(CommonMimeType.JPEG),
+        PNG(CommonMimeType.PNG),
+        SVG(CommonMimeType.SVG),
+        TIFF(CommonMimeType.TIFF),
+        WEBP(CommonMimeType.WEBP);
+        @Getter @Accessors(fluent=true)
+        final CommonMimeType mimeType;
+    }
+
     /**
      * Subset of MimeTypes most commonly used.
      *
      * @since 2.0
      */
-    public static enum CommonMimeType {
+    public enum CommonMimeType {
 
         // see
         // 
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types
diff --git a/commons/src/main/java/module-info.java 
b/commons/src/main/java/module-info.java
index fd5cc6fdc27..1da63b2ab4a 100644
--- a/commons/src/main/java/module-info.java
+++ b/commons/src/main/java/module-info.java
@@ -26,6 +26,7 @@
     exports org.apache.causeway.commons.handler;
     exports org.apache.causeway.commons.having;
     exports org.apache.causeway.commons.io;
+    exports org.apache.causeway.commons.net;
     exports org.apache.causeway.commons.tabular;
     // internals exported as well
     exports org.apache.causeway.commons.internal;
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/value/DataUri.java 
b/commons/src/main/java/org/apache/causeway/commons/net/DataUri.java
similarity index 98%
rename from 
api/applib/src/main/java/org/apache/causeway/applib/value/DataUri.java
rename to commons/src/main/java/org/apache/causeway/commons/net/DataUri.java
index 1c8a2fc4432..6199cda8e2f 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/value/DataUri.java
+++ b/commons/src/main/java/org/apache/causeway/commons/net/DataUri.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.causeway.applib.value;
+package org.apache.causeway.commons.net;
 
 import java.net.URI;
 import java.net.URLEncoder;
@@ -51,6 +51,8 @@ public enum Encoding {
         BASE64
     }
 
+    // -- FACTORIES
+
     @SneakyThrows
     public static DataUri parse(String dataURI) {
         var uri = new URI(dataURI);
@@ -81,6 +83,8 @@ public static DataUri parse(String dataURI) {
         return new DataUri(mediaType, parameters, encoding, 
decodeData(encoding, dataPart));
     }
 
+    // -- CONSTRUCTION
+
     // canonical constructor
     @SneakyThrows
     public DataUri(
diff --git 
a/api/applib/src/test/java/org/apache/causeway/applib/value/DataUriTest.java 
b/commons/src/test/java/org/apache/causeway/commons/net/DataUriTest.java
similarity index 96%
rename from 
api/applib/src/test/java/org/apache/causeway/applib/value/DataUriTest.java
rename to commons/src/test/java/org/apache/causeway/commons/net/DataUriTest.java
index 92601995851..3fd6f9b17ef 100644
--- a/api/applib/src/test/java/org/apache/causeway/applib/value/DataUriTest.java
+++ b/commons/src/test/java/org/apache/causeway/commons/net/DataUriTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.causeway.applib.value;
+package org.apache.causeway.commons.net;
 
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
@@ -27,6 +27,8 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
+import org.apache.causeway.commons.net.DataUri;
+
 import lombok.RequiredArgsConstructor;
 
 class DataUriTest {
diff --git 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/CausewayModuleCoreRuntimeServices.java
 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/CausewayModuleCoreRuntimeServices.java
index 2ec2bbaff05..e6203862006 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/CausewayModuleCoreRuntimeServices.java
+++ 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/CausewayModuleCoreRuntimeServices.java
@@ -37,7 +37,6 @@
 import 
org.apache.causeway.core.runtimeservices.homepage.HomePageResolverServiceDefault;
 import org.apache.causeway.core.runtimeservices.i18n.po.TranslationServicePo;
 import 
org.apache.causeway.core.runtimeservices.i18n.po.TranslationServicePoMenu;
-import org.apache.causeway.core.runtimeservices.icons.ObjectIconServiceDefault;
 import 
org.apache.causeway.core.runtimeservices.interaction.InteractionDtoFactoryDefault;
 import org.apache.causeway.core.runtimeservices.jaxb.JaxbServiceDefault;
 import org.apache.causeway.core.runtimeservices.locale.LanguageProviderDefault;
@@ -71,7 +70,7 @@
 import org.apache.causeway.core.runtimeservices.xml.XmlServiceDefault;
 import 
org.apache.causeway.core.runtimeservices.xmlsnapshot.XmlSnapshotServiceDefault;
 
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @Import({
         // Modules
         CausewayModuleCoreRuntime.class,
@@ -103,7 +102,7 @@
         MenuBarsMarshallerServiceBootstrap.class,
         MenuBarsServiceBootstrap.class,
         MessageServiceDefault.class,
-        ObjectIconServiceDefault.class,
+//        ObjectIconServiceDefault.class, // no longer public, but discovered 
anyway
         ObjectLifecyclePublisherDefault.class,
         PlaceholderRenderServiceDefault.class,
         LifecycleCallbackNotifier.class,
diff --git 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/icons/ObjectIconServiceDefault.java
 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/icons/ObjectIconServiceDefault.java
index f00c7d6e813..12bd8592f46 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/icons/ObjectIconServiceDefault.java
+++ 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/icons/ObjectIconServiceDefault.java
@@ -21,21 +21,27 @@
 import java.net.URL;
 import java.util.Map;
 import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
 
 import jakarta.annotation.Priority;
 import jakarta.inject.Inject;
 import jakarta.inject.Named;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.core.io.ResourceLoader;
-import org.jspecify.annotations.Nullable;
 import org.springframework.stereotype.Service;
 
 import org.apache.causeway.applib.annotation.PriorityPrecedence;
+import org.apache.causeway.applib.value.NamedWithMimeType;
 import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
+import org.apache.causeway.applib.value.NamedWithMimeType.ImageType;
 import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.commons.internal.base._StableValue;
 import org.apache.causeway.commons.internal.base._Strings;
-import org.apache.causeway.commons.internal.collections._Maps;
 import org.apache.causeway.commons.internal.exceptions._Exceptions;
 import org.apache.causeway.commons.internal.resources._Resources;
 import org.apache.causeway.core.metamodel.facets.object.icon.ObjectIcon;
@@ -43,8 +49,6 @@
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import 
org.apache.causeway.core.runtimeservices.CausewayModuleCoreRuntimeServices;
 
-import org.jspecify.annotations.NonNull;
-import lombok.RequiredArgsConstructor;
 import lombok.SneakyThrows;
 
 /**
@@ -55,29 +59,23 @@
 @Named(CausewayModuleCoreRuntimeServices.NAMESPACE + 
".ObjectIconServiceDefault")
 @Priority(PriorityPrecedence.MIDPOINT)
 @Qualifier("Default")
-@RequiredArgsConstructor(onConstructor_ = {@Inject})
-public class ObjectIconServiceDefault
+record ObjectIconServiceDefault(
+        ResourceLoader resourceLoader,
+        Map<String, ObjectIcon> iconByKey,
+        _StableValue<ObjectIcon> fallbackIcon)
 implements ObjectIconService {
 
     private static final String DEFAULT_IMAGE_RESOURCE_PATH = 
"classpath:images";
     private static final Can<CommonMimeType> IMAGE_TYPES =
-            Can.of(
-                CommonMimeType.PNG,
-                CommonMimeType.GIF,
-                CommonMimeType.JPEG,
-                CommonMimeType.SVG);
-
-    private final ResourceLoader resourceLoader;
-
-    private final Map<String, ObjectIcon> iconByKey = 
_Maps.newConcurrentHashMap();
-
-    private final ObjectIcon fallbackIcon =
-            ObjectIcon.eager(
-                    "ObjectIconFallback",
-                    _Resources.getResourceUrl(
-                            ObjectIconServiceDefault.class,
-                            "ObjectIconFallback.png"),
-                    CommonMimeType.PNG);
+            Stream.of(NamedWithMimeType.ImageType.values())
+                .map(ImageType::mimeType)
+                .collect(Can.toCan());
+
+    // non-canonical constructor
+    @Inject
+    public ObjectIconServiceDefault(ResourceLoader resourceLoader) {
+        this(resourceLoader, new ConcurrentHashMap<>(), new _StableValue<>());
+    }
 
     @Override
     public ObjectIcon getObjectIcon(
@@ -109,7 +107,12 @@ public ObjectIcon getObjectIcon(
 
     //@Override
     private ObjectIcon getObjectFallbackIcon() {
-        return fallbackIcon;
+        return fallbackIcon.orElseSet(()->ObjectIcon.eager(
+                "ObjectIconFallback",
+                _Resources.getResourceUrl(
+                        ObjectIconServiceDefault.class,
+                        "ObjectIconFallback.png"),
+                CommonMimeType.PNG));
     }
 
     // -- HELPER

Reply via email to