diff --git a/changes.xml b/changes.xml
index 7546ec62..a7505f03 100644
--- a/changes.xml
+++ b/changes.xml
@@ -23,6 +23,12 @@
xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 http://maven.apache.org/plugins/maven-changes-plugin/xsd/changes-1.0.0.xsd">
+
+
+ Improve trace logging: Make log messages involving value maps and resource/page objects more compact and better readable.
+
+
+
Dynamic Media Support: Append fmt=png-alpha for PNG assets to ensure that the alpha channel is preserved in the Dynamic Media rendition.
diff --git a/src/main/java/io/wcm/handler/media/MediaArgs.java b/src/main/java/io/wcm/handler/media/MediaArgs.java
index af283690..5957ea0d 100644
--- a/src/main/java/io/wcm/handler/media/MediaArgs.java
+++ b/src/main/java/io/wcm/handler/media/MediaArgs.java
@@ -37,6 +37,7 @@
import org.osgi.annotation.versioning.ProviderType;
import io.wcm.handler.media.format.MediaFormat;
+import io.wcm.handler.media.impl.AemObjectsReflectionToStringBuilder;
import io.wcm.handler.media.markup.DragDropSupport;
import io.wcm.handler.media.markup.IPERatioCustomize;
import io.wcm.handler.mediasource.dam.AemRenditionType;
@@ -843,7 +844,7 @@ public String toString() {
sb.append("webOptimizedImageDeliveryDisabled", webOptimizedImageDeliveryDisabled);
}
if (properties != null && !properties.isEmpty()) {
- sb.append("properties", properties);
+ sb.append("properties", AemObjectsReflectionToStringBuilder.filteredValueMap(properties));
}
return sb.build();
}
diff --git a/src/main/java/io/wcm/handler/media/MediaRequest.java b/src/main/java/io/wcm/handler/media/MediaRequest.java
index 64a71267..1f0e1da1 100644
--- a/src/main/java/io/wcm/handler/media/MediaRequest.java
+++ b/src/main/java/io/wcm/handler/media/MediaRequest.java
@@ -21,9 +21,7 @@
import java.util.HashMap;
-import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
@@ -31,6 +29,8 @@
import org.jetbrains.annotations.Nullable;
import org.osgi.annotation.versioning.ProviderType;
+import io.wcm.handler.media.impl.AemObjectsReflectionToStringBuilder;
+
/**
* Holds all properties that are part of a media handling request.
*/
@@ -119,10 +119,11 @@ public MediaRequest(@Nullable Resource resource, @Nullable String mediaRef, @Nul
@Override
public String toString() {
- ToStringBuilder sb = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ ToStringBuilder sb = new ToStringBuilder(this,
+ io.wcm.wcm.commons.util.ToStringStyle.SHORT_PREFIX_OMIT_NULL_STYLE);
if (resource != null) {
sb.append("resource", resource.getPath());
- sb.append("resourceProperties", "[" + StringUtils.join(resource.getValueMap().entrySet(), ",") + "]");
+ sb.append("resourceProperties", AemObjectsReflectionToStringBuilder.filteredValueMap(resource.getValueMap()));
}
if (mediaRef != null) {
sb.append("mediaRef", mediaRef);
diff --git a/src/main/java/io/wcm/handler/media/impl/AemObjectsReflectionToStringBuilder.java b/src/main/java/io/wcm/handler/media/impl/AemObjectsReflectionToStringBuilder.java
new file mode 100644
index 00000000..16dda12e
--- /dev/null
+++ b/src/main/java/io/wcm/handler/media/impl/AemObjectsReflectionToStringBuilder.java
@@ -0,0 +1,89 @@
+/*
+ * #%L
+ * wcm.io
+ * %%
+ * Copyright (C) 2024 wcm.io
+ * %%
+ * Licensed 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.
+ * #L%
+ */
+package io.wcm.handler.media.impl;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+
+import com.day.cq.wcm.api.Page;
+
+/**
+ * Extends ReflectionToStringBuilder to provide custom handling for AEM-related objects
+ * (Resource, ValueMap, Page) for a more compact log output.
+ */
+public class AemObjectsReflectionToStringBuilder extends ReflectionToStringBuilder {
+
+ /**
+ * @param object Object to output
+ */
+ public AemObjectsReflectionToStringBuilder(Object object) {
+ super(object);
+ }
+
+ /**
+ * @param object Object to output
+ * @param style Style
+ */
+ public AemObjectsReflectionToStringBuilder(Object object, ToStringStyle style) {
+ super(object, style);
+ }
+
+ @Override
+ protected Object getValue(Field field) throws IllegalAccessException {
+ if (Resource.class.isAssignableFrom(field.getType())) {
+ Resource resource = (Resource)field.get(this.getObject());
+ if (resource != null) {
+ return resource.getPath();
+ }
+ }
+ else if (ValueMap.class.isAssignableFrom(field.getType())) {
+ ValueMap valueMap = (ValueMap)field.get(this.getObject());
+ if (valueMap != null) {
+ return filteredValueMap(valueMap);
+ }
+ }
+ else if (Page.class.isAssignableFrom(field.getType())) {
+ Page page = (Page)field.get(this.getObject());
+ if (page != null) {
+ return page.getPath();
+ }
+ }
+ return super.getValue(field);
+ }
+
+ /**
+ * Filter value map to exclude jcr:* properties and null values.
+ * @param props Value map
+ * @return Filtered value map, sorted by key
+ */
+ public static Map filteredValueMap(ValueMap props) {
+ return props.entrySet().stream()
+ .filter(entry -> !entry.getKey().startsWith("jcr:") && entry.getValue() != null)
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (o1, o2) -> o1, TreeMap::new));
+ }
+
+}
diff --git a/src/main/java/io/wcm/handler/mediasource/dam/impl/DamAsset.java b/src/main/java/io/wcm/handler/mediasource/dam/impl/DamAsset.java
index 430eb5b8..ac5e134e 100644
--- a/src/main/java/io/wcm/handler/mediasource/dam/impl/DamAsset.java
+++ b/src/main/java/io/wcm/handler/mediasource/dam/impl/DamAsset.java
@@ -21,7 +21,6 @@
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.sling.api.adapter.Adaptable;
import org.apache.sling.api.adapter.SlingAdaptable;
import org.apache.sling.api.resource.Resource;
@@ -41,11 +40,11 @@
import io.wcm.handler.media.Rendition;
import io.wcm.handler.media.UriTemplate;
import io.wcm.handler.media.UriTemplateType;
+import io.wcm.handler.media.impl.AemObjectsReflectionToStringBuilder;
import io.wcm.handler.media.spi.MediaHandlerConfig;
import io.wcm.handler.mediasource.dam.AssetRendition;
import io.wcm.handler.mediasource.dam.impl.dynamicmedia.DynamicMediaSupportService;
import io.wcm.handler.mediasource.dam.impl.weboptimized.WebOptimizedImageDeliveryService;
-import io.wcm.wcm.commons.util.ToStringStyle;
/**
* {@link Asset} implementation for DAM assets.
@@ -225,7 +224,8 @@ public AdapterType adaptTo(Class type) {
@Override
public String toString() {
- return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_OMIT_NULL_STYLE);
+ return new AemObjectsReflectionToStringBuilder(this,
+ io.wcm.wcm.commons.util.ToStringStyle.SHORT_PREFIX_OMIT_NULL_STYLE).build();
}
}
diff --git a/src/main/java/io/wcm/handler/mediasource/inline/InlineAsset.java b/src/main/java/io/wcm/handler/mediasource/inline/InlineAsset.java
index 3a8ffa28..96febe41 100644
--- a/src/main/java/io/wcm/handler/mediasource/inline/InlineAsset.java
+++ b/src/main/java/io/wcm/handler/mediasource/inline/InlineAsset.java
@@ -21,7 +21,6 @@
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.sling.api.adapter.Adaptable;
import org.apache.sling.api.adapter.SlingAdaptable;
import org.apache.sling.api.resource.Resource;
@@ -36,8 +35,8 @@
import io.wcm.handler.media.Rendition;
import io.wcm.handler.media.UriTemplate;
import io.wcm.handler.media.UriTemplateType;
+import io.wcm.handler.media.impl.AemObjectsReflectionToStringBuilder;
import io.wcm.handler.media.spi.MediaHandlerConfig;
-import io.wcm.wcm.commons.util.ToStringStyle;
/**
* {@link Asset} implementation for inline media objects stored in a node in a content page.
@@ -169,7 +168,8 @@ public AdapterType adaptTo(Class type) {
@Override
public String toString() {
- return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_OMIT_NULL_STYLE);
+ return new AemObjectsReflectionToStringBuilder(this,
+ io.wcm.wcm.commons.util.ToStringStyle.SHORT_PREFIX_OMIT_NULL_STYLE).build();
}
}
diff --git a/src/main/java/io/wcm/handler/mediasource/ngdm/NextGenDynamicMediaAsset.java b/src/main/java/io/wcm/handler/mediasource/ngdm/NextGenDynamicMediaAsset.java
index 4330065b..7283c0f5 100644
--- a/src/main/java/io/wcm/handler/mediasource/ngdm/NextGenDynamicMediaAsset.java
+++ b/src/main/java/io/wcm/handler/mediasource/ngdm/NextGenDynamicMediaAsset.java
@@ -19,6 +19,7 @@
*/
package io.wcm.handler.mediasource.ngdm;
+import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.ValueMap;
import org.jetbrains.annotations.NotNull;
@@ -119,4 +120,12 @@ final class NextGenDynamicMediaAsset implements Asset {
return null;
}
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("reference", context.getReference())
+ .append("metadata", context.getMetadata())
+ .toString();
+ }
+
}
diff --git a/src/test/java/io/wcm/handler/media/MediaRequestTest.java b/src/test/java/io/wcm/handler/media/MediaRequestTest.java
index 4a9e387b..68d43b82 100644
--- a/src/test/java/io/wcm/handler/media/MediaRequestTest.java
+++ b/src/test/java/io/wcm/handler/media/MediaRequestTest.java
@@ -23,13 +23,27 @@
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import io.wcm.handler.media.testcontext.AppAemContext;
+import io.wcm.testing.mock.aem.junit5.AemContext;
+import io.wcm.testing.mock.aem.junit5.AemContextExtension;
+
+@ExtendWith(AemContextExtension.class)
class MediaRequestTest {
+ private final AemContext context = AppAemContext.newAemContext();
+
@Test
void testToString() {
MediaRequest request = new MediaRequest("/path", null);
assertTrue(StringUtils.contains(request.toString(), "/path"));
}
+ @Test
+ void testToString_Resource() {
+ MediaRequest request = new MediaRequest(context.create().resource("/content/test"), null);
+ assertTrue(StringUtils.contains(request.toString(), "/content/test"));
+ }
+
}
diff --git a/src/test/java/io/wcm/handler/media/impl/AemObjectsReflectionToStringBuilderTest.java b/src/test/java/io/wcm/handler/media/impl/AemObjectsReflectionToStringBuilderTest.java
new file mode 100644
index 00000000..e902f4a1
--- /dev/null
+++ b/src/test/java/io/wcm/handler/media/impl/AemObjectsReflectionToStringBuilderTest.java
@@ -0,0 +1,94 @@
+/*
+ * #%L
+ * wcm.io
+ * %%
+ * Copyright (C) 2024 wcm.io
+ * %%
+ * Licensed 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.
+ * #L%
+ */
+package io.wcm.handler.media.impl;
+
+import static com.day.cq.commons.jcr.JcrConstants.JCR_CREATED;
+import static com.day.cq.commons.jcr.JcrConstants.JCR_PRIMARYTYPE;
+import static com.day.cq.commons.jcr.JcrConstants.NT_UNSTRUCTURED;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import com.day.cq.wcm.api.Page;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import io.wcm.handler.media.testcontext.AppAemContext;
+import io.wcm.sling.commons.resource.ImmutableValueMap;
+import io.wcm.testing.mock.aem.junit5.AemContext;
+import io.wcm.testing.mock.aem.junit5.AemContextExtension;
+
+@ExtendWith(AemContextExtension.class)
+class AemObjectsReflectionToStringBuilderTest {
+
+ private final AemContext context = AppAemContext.newAemContext();
+
+ @SuppressWarnings("null")
+ private static final ValueMap VALUEMAP_SAMPLE = ImmutableValueMap.of(
+ "prop1", "value1",
+ JCR_CREATED, new Date(),
+ JCR_PRIMARYTYPE, NT_UNSTRUCTURED,
+ "prop2", 5,
+ "prop3", null);
+
+ @Test
+ void testBuild() {
+ ClassWithFields obj = new ClassWithFields();
+ obj.prop1 = "value1";
+ obj.resource = context.create().resource("/content/resource1",
+ "prop2", "value2");
+ obj.page = context.create().page("/content/page1");
+ obj.props = VALUEMAP_SAMPLE;
+
+ assertEquals("[page=/content/page1,prop1=value1,props={prop1=value1, prop2=5},resource=/content/resource1]",
+ new AemObjectsReflectionToStringBuilder(obj, ToStringStyle.NO_CLASS_NAME_STYLE).build());
+ }
+
+ @Test
+ void testBuild_NullObjects() {
+ ClassWithFields obj = new ClassWithFields();
+
+ assertNotNull(new AemObjectsReflectionToStringBuilder(obj).build());
+ }
+
+ @Test
+ void testFilteredValueMap() {
+ Map filtered = AemObjectsReflectionToStringBuilder.filteredValueMap(VALUEMAP_SAMPLE);
+
+ assertEquals(Map.of("prop1", "value1", "prop2", 5), filtered);
+ }
+
+ @SuppressWarnings("unused")
+ @SuppressFBWarnings("URF_UNREAD_FIELD")
+ private static final class ClassWithFields {
+ String prop1;
+ Resource resource;
+ Page page;
+ ValueMap props;
+ }
+
+}