You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2021/05/06 16:25:57 UTC

[sling-whiteboard] branch master updated (a88e408 -> 3eff62c)

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

bdelacretaz pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git.


    from a88e408  Move unused modules aside
     new 9529f22  Tweak annotations
     new 3eff62c  Add sling:dmap:debug

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../documentmapper/api/Annotations.java            | 65 ++++++++++++++++++++--
 .../documentmapper/api/DocumentMapper.java         | 11 +++-
 .../documentmapper/impl/ContentDocumentMapper.java | 64 ++++++++++++++++-----
 .../documentmapper/impl/PropertiesMapper.java      |  3 +
 .../samples/graphql/DocumentDataFetcher.java       | 10 +---
 .../samples/graphql/DocumentsDataFetcher.java      | 17 +++---
 .../annotations/AnnotationsRegistryImpl.java       | 48 +++++++++-------
 .../apps/samples/graphql/GQLschema.jsp             |  4 +-
 .../features/feature-sample-graphql-api.json       |  2 +-
 9 files changed, 164 insertions(+), 60 deletions(-)

[sling-whiteboard] 01/02: Tweak annotations

Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

bdelacretaz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git

commit 9529f2269285ae84296ed6e3dc3538652d8904be
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Thu May 6 17:15:45 2021 +0200

    Tweak annotations
---
 .../documentmapper/api/Annotations.java            | 27 +++++++++++++++++++
 .../documentmapper/impl/ContentDocumentMapper.java | 18 ++++++++-----
 .../documentmapper/impl/PropertiesMapper.java      |  3 +++
 .../annotations/AnnotationsRegistryImpl.java       | 31 +++++++++-------------
 .../features/feature-sample-graphql-api.json       |  2 +-
 5 files changed, 55 insertions(+), 26 deletions(-)

diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java
index c460ac8..a0402a0 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java
@@ -19,6 +19,7 @@
 
 package org.apache.sling.remotecontent.documentmapper.api;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -42,6 +43,21 @@ public class Annotations {
         this.resourceType = resourceType;
     }
 
+    @Override
+    public String toString() {
+        return String.format(
+            "RT=%s N=%b VC=%b DR=%b VCRN=%s IP=%s EP=%s DR=%s",
+            resourceType,
+            navigable,
+            visitContent,
+            documentRoot,
+            visitContentResourceNamePattern,
+            includePropertyPattern,
+            excludePropertyPattern,
+            dereferenceByPathProperties
+        );
+    }
+
     // TODO equals + hashcode
 
     public String getResourceType() {
@@ -63,6 +79,7 @@ public class Annotations {
         return visitContentResourceNamePattern == null ? true : visitContentResourceNamePattern.matcher(resourceName).matches();
     }
 
+    // TODO should accept a parent Annotations - other methods as well?
     public boolean includeProperty(String name) {
         // include has priority over exclude
         boolean result = includePropertyPattern == null ? true : includePropertyPattern.matcher(name).matches();
@@ -120,6 +137,16 @@ public class Annotations {
             return this;
         }
 
+        public Builder withDereferenceByPathProperties(String ... names) {
+            if(target.dereferenceByPathProperties == null) {
+                target.dereferenceByPathProperties = new ArrayList<String>();
+            }
+            for(String name : names) {
+                target.dereferenceByPathProperties.add(name);
+            }
+            return this;
+        }
+
         public Annotations build() {
             return target;
         }
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java
index 47b95be..40cbfda 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java
@@ -45,18 +45,20 @@ public class ContentDocumentMapper implements DocumentMapper {
         final String resourceType = r.getResourceType();
         final Annotations annot = annotationsRegistry.getAnnotations(resourceType);
         dest.addValue("path", r.getPath());
+        log.debug("Top level Resource map {} as {}: {}", r.getPath(), r.getResourceType(), annot);
         mapResource(r, dest, urlb, resourceType, annot, annot.isDocumentRoot());
     }
 
     private void mapResource(@NotNull Resource r, @NotNull MappingTarget.TargetNode dest, 
-        UrlBuilder urlb, String parentResourceType, Annotations annot, boolean recurse) {
+        UrlBuilder urlb, String documentResourceType, Annotations documentAnnot, boolean recurse) {
 
-        log.debug("Mapping Resource {} as {}", r.getPath(), r.getResourceType());
-        propertiesMapper.mapProperties(dest, r, annot);
+        log.debug("Mapping Resource {} as {}: {}", r.getPath(), r.getResourceType(), documentAnnot);
+        propertiesMapper.mapProperties(dest, r, documentAnnot);
+        final Annotations thisAnnot = annotationsRegistry.getAnnotations(r.getResourceType());
 
         // Dereference by path if specified
         // TODO detect cycles which might lead to infinite loops
-        annot.dereferenceByPathPropertyNames().forEach(derefPathPropertyName -> {
+        thisAnnot.dereferenceByPathPropertyNames().forEach(derefPathPropertyName -> {
             log.debug("Dereferencing {} on {}", r.getPath(), derefPathPropertyName);
             final ValueMap vm = r.adaptTo(ValueMap.class);
             final String derefPath = vm == null ? null : vm.get(derefPathPropertyName, String.class);
@@ -64,7 +66,7 @@ public class ContentDocumentMapper implements DocumentMapper {
                 final Resource dereferenced = r.getResourceResolver().getResource(derefPath);
                 if(dereferenced != null) {
                     final MappingTarget.TargetNode derefNode = dest.addChild("dereferenced_by_" + derefPathPropertyName);
-                    mapResource(dereferenced, derefNode, urlb, parentResourceType, annot, recurse);
+                    mapResource(dereferenced, derefNode, urlb, documentResourceType, documentAnnot, recurse);
                 }
             }
         });
@@ -73,13 +75,15 @@ public class ContentDocumentMapper implements DocumentMapper {
         if(recurse) {
             log.debug("Recursing into {}", r.getPath());
             for(Resource child : r.getChildren()) {
-                if(!annot.visitChildResource(child.getName())) {
+                final boolean visit = thisAnnot.visitChildResource(child.getName());
+                log.debug("child resource {} visit decision {}", child.getName(), visit);
+                if(!visit) {
                     continue;
                 }
                 final String childResourceType = child.getResourceType();
                 if(annotationsRegistry.getAnnotations(childResourceType).visitContent()) {
                     final MappingTarget.TargetNode childDest = dest.addChild(child.getName());
-                    mapResource(child, childDest, urlb, childResourceType, annot, true);
+                    mapResource(child, childDest, urlb, childResourceType, documentAnnot, true);
                 }
             }
         } else if(log.isDebugEnabled()) {
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/PropertiesMapper.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/PropertiesMapper.java
index 1190e6a..825c238 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/PropertiesMapper.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/PropertiesMapper.java
@@ -20,6 +20,7 @@
 package org.apache.sling.remotecontent.documentmapper.impl;
 
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.Map;
 
 import org.apache.sling.api.resource.Resource;
@@ -38,6 +39,8 @@ class PropertiesMapper {
                 final Object value = e.getValue();
                 if(value instanceof Object[]) {
                     dest.addValue(e.getKey(), Arrays.asList((Object[])value));
+                } else if(value instanceof Calendar) {
+                    dest.addValue(e.getKey(), ((Calendar)value).getTime().toString());
                 } else {
                     dest.addValue(e.getKey(), String.valueOf(value));
                 }
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java
index 5b10de4..1750928 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java
@@ -51,7 +51,7 @@ public class AnnotationsRegistryImpl implements AnnotationsRegistry {
     @Activate
     public void activate() {
         add(
-            Annotations.forResourceType("cg:page")
+            Annotations.forResourceType("cq:Page")
             .withDocumentRoot(true)
             .withNavigable(true)
             .withVisitContent(true)
@@ -59,16 +59,20 @@ public class AnnotationsRegistryImpl implements AnnotationsRegistry {
             .withIncludePropertyPattern("sling:ResourceType|cq:tags")
             .withExcludePropertyPattern("jcr:.*|cq:.*")
         );
-        /*
         add(
-            Builder.forResourceType("cq:Page")
-            .withAnnotation(DOCUMENT_ROOT, TRUE)
-            .withAnnotation(NAVIGABLE, TRUE)
-            .withAnnotation(VISIT_CONTENT, TRUE)
-            .withAnnotation(VISIT_CONTENT_RESOURCE_NAME_PATTERN, "jcr:content")
-            .withAnnotation(CONTENT_INCLUDE_PROPERTY_REGEXP, "sling:ResourceType|cq:tags")
-            .withAnnotation(CONTENT_EXCLUDE_PROPERTY_REGEXP, "jcr:.*|cq:.*")
+            Annotations.forResourceType("wknd/components/page")
+            // TODO shall we only have "visit content"?
+            .withDocumentRoot(true)
+            .withVisitContent(true)
+            .withIncludePropertyPattern("sling:ResourceType|jcr:description")
+            .withExcludePropertyPattern("jcr:.*|cq:.*")
+        );
+        add(
+            Annotations.forResourceType("wknd/components/image")
+            .withVisitContent(true)
+            .withDereferenceByPathProperties("fileReference")
         );
+        /*
         add(
             Builder.forResourceType("sling:Folder")
             .withAnnotation(NAVIGABLE, TRUE)
@@ -82,15 +86,6 @@ public class AnnotationsRegistryImpl implements AnnotationsRegistry {
             .withAnnotation(NAVIGABLE, TRUE)
         );
         add(
-            Builder.forResourceType("wknd/components/page")
-            .withAnnotation(VISIT_CONTENT, TRUE)
-        );
-        add(
-            Builder.forResourceType("wknd/components/image")
-            .withAnnotation(VISIT_CONTENT, TRUE)
-            .withAnnotation(DEREFERENCE_BY_PATH, "fileReference")
-        );
-        add(
             Builder.forResourceType("wknd/components/carousel")
             .withAnnotation(VISIT_CONTENT, TRUE)
         );
diff --git a/remote-content-api/sample-graphql-api/src/main/resources/features/feature-sample-graphql-api.json b/remote-content-api/sample-graphql-api/src/main/resources/features/feature-sample-graphql-api.json
index ef1033c..3a3b62c 100644
--- a/remote-content-api/sample-graphql-api/src/main/resources/features/feature-sample-graphql-api.json
+++ b/remote-content-api/sample-graphql-api/src/main/resources/features/feature-sample-graphql-api.json
@@ -52,7 +52,7 @@
       "org.apache.sling.commons.log.level": "DEBUG",
       "org.apache.sling.commons.log.names":
         [
-          "org.apache.sling.documentmapper",
+          "org.apache.sling.remotecontent",
           "org.apache.sling.graphql"
         ],
       "org.apache.sling.commons.log.pattern": "%-5level [%-50logger{50}] %message ## %mdc{sling.InternalRequest} %n"

[sling-whiteboard] 02/02: Add sling:dmap:debug

Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

bdelacretaz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git

commit 3eff62c8cba12b1d912eda7c35ae037d5d642fa0
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Thu May 6 18:25:40 2021 +0200

    Add sling:dmap:debug
---
 .../documentmapper/api/Annotations.java            | 50 +++++++++++++++----
 .../documentmapper/api/DocumentMapper.java         | 11 +++-
 .../documentmapper/impl/ContentDocumentMapper.java | 58 ++++++++++++++++------
 .../samples/graphql/DocumentDataFetcher.java       | 10 +---
 .../samples/graphql/DocumentsDataFetcher.java      | 17 ++++---
 .../annotations/AnnotationsRegistryImpl.java       | 23 ++++++---
 .../apps/samples/graphql/GQLschema.jsp             |  4 +-
 7 files changed, 124 insertions(+), 49 deletions(-)

diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java
index a0402a0..4f00c4f 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/Annotations.java
@@ -34,10 +34,12 @@ public class Annotations {
     private boolean navigable;
     private boolean visitContent;
     private boolean documentRoot;
+    private String childSubstitutePath;
     private Pattern visitContentResourceNamePattern;
     private Pattern includePropertyPattern;
     private Pattern excludePropertyPattern;
-    private List<String> dereferenceByPathProperties;
+    private List<String> resolveByPathProperties;
+    private List<String> excludeNodeNames;
 
     private Annotations(String resourceType) {
         this.resourceType = resourceType;
@@ -46,7 +48,7 @@ public class Annotations {
     @Override
     public String toString() {
         return String.format(
-            "RT=%s N=%b VC=%b DR=%b VCRN=%s IP=%s EP=%s DR=%s",
+            "RT=%s N=%b VC=%b DR=%b VCRN=%s IP=%s EP=%s DR=%s ENN=%s",
             resourceType,
             navigable,
             visitContent,
@@ -54,7 +56,8 @@ public class Annotations {
             visitContentResourceNamePattern,
             includePropertyPattern,
             excludePropertyPattern,
-            dereferenceByPathProperties
+            resolveByPathProperties,
+            excludeNodeNames
         );
     }
 
@@ -89,14 +92,26 @@ public class Annotations {
         return result;
     }
 
-    public Collection<String> dereferenceByPathPropertyNames() {
-        if(dereferenceByPathProperties != null) {
-            return dereferenceByPathProperties;
+    public Collection<String> resolveByPathPropertyNames() {
+        if(resolveByPathProperties != null) {
+            return resolveByPathProperties;
         } else {
             return Collections.emptyList();
         }
     }
 
+    public Collection<String> excludeNodeNames() {
+        if(excludeNodeNames != null) {
+            return excludeNodeNames;
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    public String childSubstitutePath() {
+        return childSubstitutePath;
+    }
+
     public static Builder forResourceType(String resourceType) {
         return new Builder(resourceType);
     }
@@ -137,16 +152,31 @@ public class Annotations {
             return this;
         }
 
-        public Builder withDereferenceByPathProperties(String ... names) {
-            if(target.dereferenceByPathProperties == null) {
-                target.dereferenceByPathProperties = new ArrayList<String>();
+        public Builder withResolveByPathPropertyNames(String ... names) {
+            if(target.resolveByPathProperties == null) {
+                target.resolveByPathProperties = new ArrayList<String>();
+            }
+            for(String name : names) {
+                target.resolveByPathProperties.add(name);
+            }
+            return this;
+        }
+
+        public Builder withExcludeNodeNames(String ... names) {
+            if(target.excludeNodeNames == null) {
+                target.excludeNodeNames = new ArrayList<String>();
             }
             for(String name : names) {
-                target.dereferenceByPathProperties.add(name);
+                target.excludeNodeNames.add(name);
             }
             return this;
         }
 
+        public Builder withChildSubstituePath(String path) {
+            target.childSubstitutePath = path;
+            return this;
+        }
+
         public Annotations build() {
             return target;
         }
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/DocumentMapper.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/DocumentMapper.java
index 94e47d8..31435d0 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/DocumentMapper.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/api/DocumentMapper.java
@@ -34,6 +34,15 @@ public interface DocumentMapper {
     interface UrlBuilder {
         String pathToUrl(String path);
     }
+
+    public static class Options {
+        public final boolean debug;
+        public final UrlBuilder urlBuilder;
+        public Options(boolean debug, UrlBuilder urlBuilder) {
+            this.debug = debug;
+            this.urlBuilder = urlBuilder;
+        }
+    }
     
-    void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode destination, UrlBuilder urlb);
+    void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode destination, Options opt);
 }
\ No newline at end of file
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java
index 40cbfda..7561acc 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/documentmapper/impl/ContentDocumentMapper.java
@@ -41,32 +41,62 @@ public class ContentDocumentMapper implements DocumentMapper {
     private AnnotationsRegistry annotationsRegistry;
 
     @Override
-    public void map(@NotNull Resource r, @NotNull MappingTarget.TargetNode dest, UrlBuilder urlb) {
-        final String resourceType = r.getResourceType();
-        final Annotations annot = annotationsRegistry.getAnnotations(resourceType);
-        dest.addValue("path", r.getPath());
+    public void map(@NotNull Resource originalResource, @NotNull MappingTarget.TargetNode dest, DocumentMapper.Options opt) {
+        Annotations annot = annotationsRegistry.getAnnotations(originalResource.getResourceType());
+        dest.addValue("path", originalResource.getPath());
+        final String substPath = annot.childSubstitutePath();
+        Resource r = originalResource;
+        if(substPath != null) {
+            r = r.getChild(substPath);
+            if(r == null) {
+                throw new RuntimeException("Child " + substPath + " of resource " + originalResource.getPath() + "not found");
+            }
+            annot = annotationsRegistry.getAnnotations(r.getResourceType());
+        }
         log.debug("Top level Resource map {} as {}: {}", r.getPath(), r.getResourceType(), annot);
-        mapResource(r, dest, urlb, resourceType, annot, annot.isDocumentRoot());
+        mapResource(r, dest, opt, r.getResourceType(), annot, annot.isDocumentRoot());
     }
 
     private void mapResource(@NotNull Resource r, @NotNull MappingTarget.TargetNode dest, 
-        UrlBuilder urlb, String documentResourceType, Annotations documentAnnot, boolean recurse) {
+        DocumentMapper.Options opt, String documentResourceType, Annotations documentAnnot, boolean recurse) {
+
+        final Annotations resourceAnnot = annotationsRegistry.getAnnotations(r.getResourceType());
+        final MappingTarget.TargetNode debug = opt.debug ? dest.addChild("sling:dmap:debug") : null;
+        if(debug != null) {
+            debug.addValue("sling:dmap:path", r.getPath());
+            debug.addValue("sling:dmap:resourceType", r.getResourceType());
+            debug.addValue("sling:dmap:documentAnnot", documentAnnot.toString());
+            debug.addValue("sling:dmap:resourceAnnot", resourceAnnot.toString());
+        }
+    
+        for(String name : documentAnnot.excludeNodeNames()) {
+            if(name.equals(r.getName())) {
+                if(debug != null) {
+                    debug.addValue("sling:dmap:excluded", documentAnnot.toString());
+                }
+                log.debug("Resource {} excluded by node name ({})", r.getPath(), documentAnnot);
+                return;
+            }
+        }
 
         log.debug("Mapping Resource {} as {}: {}", r.getPath(), r.getResourceType(), documentAnnot);
         propertiesMapper.mapProperties(dest, r, documentAnnot);
-        final Annotations thisAnnot = annotationsRegistry.getAnnotations(r.getResourceType());
 
-        // Dereference by path if specified
+        // Resolve by path if specified
         // TODO detect cycles which might lead to infinite loops
-        thisAnnot.dereferenceByPathPropertyNames().forEach(derefPathPropertyName -> {
-            log.debug("Dereferencing {} on {}", r.getPath(), derefPathPropertyName);
+        resourceAnnot.resolveByPathPropertyNames().forEach(derefPathPropertyName -> {
+            log.debug("Resolving by path {} on {}", r.getPath(), derefPathPropertyName);
             final ValueMap vm = r.adaptTo(ValueMap.class);
             final String derefPath = vm == null ? null : vm.get(derefPathPropertyName, String.class);
             if(derefPath != null) {
                 final Resource dereferenced = r.getResourceResolver().getResource(derefPath);
                 if(dereferenced != null) {
-                    final MappingTarget.TargetNode derefNode = dest.addChild("dereferenced_by_" + derefPathPropertyName);
-                    mapResource(dereferenced, derefNode, urlb, documentResourceType, documentAnnot, recurse);
+                    final MappingTarget.TargetNode derefNode = dest.addChild("sling:dmap:resolved");
+                    derefNode.addValue("sling:dmap:resolvedFrom", derefPathPropertyName);
+                    derefNode.addValue("sling:dmap:resolvePath", derefPath);
+                    mapResource(dereferenced, derefNode, opt, documentResourceType, documentAnnot, recurse);
+                } else if(debug != null) {
+                    debug.addValue("Resolve by path " + derefPathPropertyName, "not found:" + derefPath);
                 }
             }
         });
@@ -75,7 +105,7 @@ public class ContentDocumentMapper implements DocumentMapper {
         if(recurse) {
             log.debug("Recursing into {}", r.getPath());
             for(Resource child : r.getChildren()) {
-                final boolean visit = thisAnnot.visitChildResource(child.getName());
+                final boolean visit = resourceAnnot.visitChildResource(child.getName());
                 log.debug("child resource {} visit decision {}", child.getName(), visit);
                 if(!visit) {
                     continue;
@@ -83,7 +113,7 @@ public class ContentDocumentMapper implements DocumentMapper {
                 final String childResourceType = child.getResourceType();
                 if(annotationsRegistry.getAnnotations(childResourceType).visitContent()) {
                     final MappingTarget.TargetNode childDest = dest.addChild(child.getName());
-                    mapResource(child, childDest, urlb, childResourceType, documentAnnot, true);
+                    mapResource(child, childDest, opt, childResourceType, documentAnnot, true);
                 }
             }
         } else if(log.isDebugEnabled()) {
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentDataFetcher.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentDataFetcher.java
index 69aa950..ff432e0 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentDataFetcher.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentDataFetcher.java
@@ -42,13 +42,6 @@ public class DocumentDataFetcher implements SlingDataFetcher<Object> {
     @Reference
     private DocumentMapper documentMapper;
 
-    static final UrlBuilder DUMMY_URL_BUILDER = new UrlBuilder() {
-        @Override
-        public String pathToUrl(String path) {
-            return getClass().getName();
-        }
-    };
-    
     @Override
     public @Nullable Object get(@NotNull SlingDataFetcherEnvironment e) throws Exception {
         final String path = e.getArgument("path");
@@ -56,13 +49,14 @@ public class DocumentDataFetcher implements SlingDataFetcher<Object> {
         final Map<String, Object> data = new HashMap<>();
         data.put("path", path);
         data.put("selectors", e.getArgument("selectors"));
+        final DocumentMapper.Options opt = new DocumentMapper.Options(e.getArgument("debug", true), new UrlBuilderStub());
 
         // Get the target Resource
         final Resource target = e.getCurrentResource().getResourceResolver().getResource(path);
 
         // Use DocumentMapper to build the body
         final MappingTarget.TargetNode body = mappingTarget.newTargetNode();
-        documentMapper.map(target, body, DUMMY_URL_BUILDER);
+        documentMapper.map(target, body, opt);
         body.close();
         data.put("body", body.adaptTo(Map.class));
         return data;
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentsDataFetcher.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentsDataFetcher.java
index 8f00320..581a905 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentsDataFetcher.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/DocumentsDataFetcher.java
@@ -45,22 +45,21 @@ public class DocumentsDataFetcher implements SlingDataFetcher<Object> {
     @Reference
     private DocumentMapper documentMapper;
 
-    private void addDocumentData(final Map<String, Object> data, String key, Resource r, DocumentMapper mapper) {
+    private void addDocumentData(final Map<String, Object> data, String key, Resource r, DocumentMapper mapper, DocumentMapper.Options opt) {
         final MappingTarget.TargetNode target = mappingTarget.newTargetNode();
-        mapper.map(r, target, new UrlBuilderStub());
+        mapper.map(r, target, opt);
         target.close();
         data.put(key, target.adaptTo(Map.class));
 
     }
 
-    private Map<String, Object> toDocument(Resource r) {
+    private Map<String, Object> toDocument(Resource r, DocumentMapper.Options opt) {
         final Map<String, Object> data = new HashMap<>();
         data.put("path", r.getPath());
 
-        // TODO how to find out whether those fields are actually needed
-        // or how to evaluate them lazily
-        addDocumentData(data, "body", r, documentMapper);
-        addDocumentData(data, "summary", r, documentMapper);
+        // TODO for now those are the same...
+        addDocumentData(data, "body", r, documentMapper, opt);
+        addDocumentData(data, "summary", r, documentMapper, opt);
 
         return data;
     }
@@ -70,6 +69,8 @@ public class DocumentsDataFetcher implements SlingDataFetcher<Object> {
         // Use a suffix as we might not keep these built-in language in the long term
         final String langSuffix = "2020";
 
+        final DocumentMapper.Options opt = new DocumentMapper.Options(e.getArgument("debug", true), new UrlBuilderStub());
+
         String lang = e.getArgument("lang", "xpath" + langSuffix);
         if(!lang.endsWith(langSuffix)) {
             throw new RuntimeException("Query langage must end with suffix " + langSuffix);
@@ -81,7 +82,7 @@ public class DocumentsDataFetcher implements SlingDataFetcher<Object> {
         final ResourceResolver resolver = e.getCurrentResource().getResourceResolver();
         final Iterator<Resource> it = resolver.findResources(query, lang);
         while(it.hasNext()) {
-            result.add(toDocument(it.next()));
+            result.add(toDocument(it.next(), opt));
         }
         return result;
     }
diff --git a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java
index 1750928..4915be7 100644
--- a/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java
+++ b/remote-content-api/sample-graphql-api/src/main/java/org/apache/sling/remotecontent/samples/graphql/annotations/AnnotationsRegistryImpl.java
@@ -50,28 +50,39 @@ public class AnnotationsRegistryImpl implements AnnotationsRegistry {
 
     @Activate
     public void activate() {
+        final String generalIgnoreProperties = "jcr:.*|cq:.*|crs:.*|tiff:.*|xmpMM:.*|xmp:.*|psAux:.*";
+        final String [] generalExcludeNodeNames = { "xmpMM:History", "xmpMM:DerivedFrom", "metadata" };
+
         add(
             Annotations.forResourceType("cq:Page")
             .withDocumentRoot(true)
+            .withChildSubstituePath("jcr:content")
             .withNavigable(true)
             .withVisitContent(true)
-            .withVisitContentChildResourceNamePattern("jcr:content")
-            .withIncludePropertyPattern("sling:ResourceType|cq:tags")
-            .withExcludePropertyPattern("jcr:.*|cq:.*")
+            .withIncludePropertyPattern("sling:ResourceType|cq:tags|jcr:title|jcr:description")
+            .withExcludePropertyPattern(generalIgnoreProperties)
+            .withExcludeNodeNames(generalExcludeNodeNames)
         );
         add(
             Annotations.forResourceType("wknd/components/page")
             // TODO shall we only have "visit content"?
             .withDocumentRoot(true)
             .withVisitContent(true)
-            .withIncludePropertyPattern("sling:ResourceType|jcr:description")
-            .withExcludePropertyPattern("jcr:.*|cq:.*")
+            .withIncludePropertyPattern("sling:ResourceType|jcr:title|jcr:description")
+            .withExcludePropertyPattern(generalIgnoreProperties)
+            .withExcludeNodeNames(generalExcludeNodeNames)
         );
         add(
             Annotations.forResourceType("wknd/components/image")
             .withVisitContent(true)
-            .withDereferenceByPathProperties("fileReference")
+            .withResolveByPathPropertyNames("fileReference")
+        );
+        add(
+            Annotations.forResourceType("wknd/components/contentfragment")
+            .withVisitContent(true)
+            .withResolveByPathPropertyNames("fragmentPath")
         );
+        
         /*
         add(
             Builder.forResourceType("sling:Folder")
diff --git a/remote-content-api/sample-graphql-api/src/main/resources/SLING-INF/initial-content/apps/samples/graphql/GQLschema.jsp b/remote-content-api/sample-graphql-api/src/main/resources/SLING-INF/initial-content/apps/samples/graphql/GQLschema.jsp
index 425ff57..79361a2 100644
--- a/remote-content-api/sample-graphql-api/src/main/resources/SLING-INF/initial-content/apps/samples/graphql/GQLschema.jsp
+++ b/remote-content-api/sample-graphql-api/src/main/resources/SLING-INF/initial-content/apps/samples/graphql/GQLschema.jsp
@@ -22,8 +22,8 @@
 scalar Object
 
 type Query {
-  document(path : String, selectors : [String]) : Document @fetcher(name:"samples/document")
-  documents(lang: String, query : String, selectors : [String]) : [Document] @fetcher(name:"samples/documents")
+  document(path : String, selectors : [String], debug : Boolean) : Document @fetcher(name:"samples/document")
+  documents(lang: String, query : String, selectors : [String], debug : Boolean) : [Document] @fetcher(name:"samples/documents")
 }
 
 type Mutation {