diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java index a99caf95ba..af31853ba4 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java +++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java @@ -44,6 +44,27 @@ public @interface HierarchicalPageProperty { + /** + * Start traversing upwards in the hierarchy from a specific level, skipping lower levels. + * @since 6.0.16 + * @see https://developer.adobe.com/experience-manager/reference-materials/6-5/javadoc/com/day/cq/wcm/api/Page.html#getAbsoluteParent-int- + * | level | returned | + * | 0 | /content | + * | 1 | /content/geometrixx | + * | 2 | /content/geometrixx/en | + * | 3 | /content/geometrixx/en/products | + * | 4 | null + * If we'd use 1 in this example, we would skip over level 2 and 3. + * -1 means we disable this value. + */ + int traverseFromAbsoluteParent() default -1; + + /** + * Whether to use the current page (true) or the resource page (false). + * @return + */ + boolean useCurrentPage() default false; + /** * Specifies the name of the value from the value map to take. * If empty, then the name is derived from the method or field. diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java index 4e2f73a20c..75d4e6b19e 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java +++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java @@ -42,6 +42,11 @@ @Source(HierarchicalPagePropertyInjector.SOURCE) public @interface PageProperty { + /** + * Whether to use the current page (true) or the resource page (false). + * @return + */ + boolean useCurrentPage() default false; /** * Specifies the name of the value from the value map to take. diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/impl/PagePropertyAnnotationProcessorFactory.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/impl/PagePropertyAnnotationProcessorFactory.java new file mode 100644 index 0000000000..9706ded898 --- /dev/null +++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/impl/PagePropertyAnnotationProcessorFactory.java @@ -0,0 +1,70 @@ +/*- + * #%L + * ACS AEM Commons Bundle + * %% + * Copyright (C) 2013 - 2024 Adobe + * %% + * 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 com.adobe.acs.commons.models.injectors.annotation.impl; + +import com.adobe.acs.commons.models.injectors.annotation.HierarchicalPageProperty; +import com.adobe.acs.commons.models.injectors.annotation.PageProperty; +import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; +import org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor2; +import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor2; +import org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory; +import org.osgi.service.component.annotations.Component; + +import java.lang.reflect.AnnotatedElement; +import java.util.Optional; + +import static org.apache.commons.lang3.StringUtils.isBlank; + +/** + * The annotation processor for the {@link HierarchicalPageProperty} annotation + *

+ * Note: This can only be used together with Sling Models API bundle in version 1.2.0 (due to the dependency on InjectionStrategy) + */ +@Component(service = StaticInjectAnnotationProcessorFactory.class) +public class PagePropertyAnnotationProcessorFactory implements StaticInjectAnnotationProcessorFactory { + + @Override + public InjectAnnotationProcessor2 createAnnotationProcessor(AnnotatedElement element) { + return Optional.ofNullable(element.getAnnotation(PageProperty.class)).map(PagePropertyAnnotationProcessor::new).orElse(null); + } + + private class PagePropertyAnnotationProcessor extends AbstractInjectAnnotationProcessor2 { + private final PageProperty annotation; + + public PagePropertyAnnotationProcessor(PageProperty annotation) { + this.annotation = annotation; + } + + @Override + public InjectionStrategy getInjectionStrategy() { + return annotation.injectionStrategy(); + } + + @Override + public String getName() { + if (isBlank(annotation.value())) { + return null; + } + return annotation.value(); + } + + } + +} diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java index 706784875c..da5765ef75 100644 --- a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java +++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java @@ -24,17 +24,19 @@ import com.day.cq.commons.inherit.InheritanceValueMap; import com.day.cq.wcm.api.Page; import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ValueMap; import org.apache.sling.models.annotations.Source; import org.apache.sling.models.spi.DisposalCallbackRegistry; import org.apache.sling.models.spi.Injector; import org.osgi.framework.Constants; import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Type; -import static com.adobe.acs.commons.models.injectors.impl.InjectorUtils.getResource; -import static com.adobe.acs.commons.models.injectors.impl.InjectorUtils.getResourcePage; +import static com.adobe.acs.commons.models.injectors.impl.InjectorUtils.*; @Component( property = { @@ -51,6 +53,8 @@ public class HierarchicalPagePropertyInjector implements Injector { */ public static final String SOURCE = "hierarchical-page-property"; + private static final Logger LOG = LoggerFactory.getLogger(HierarchicalPagePropertyInjector.class); + @Override public String getName() { return SOURCE; @@ -66,13 +70,13 @@ public Object getValue(Object adaptable, String name, Type declaredType, Annotat Resource currentResource = getResource(adaptable); if (currentResource != null) { - Resource adaptableRes = lookUpFromPage(currentResource); + Resource adaptableRes = lookUpFromPage(adaptable, currentResource, element); if (adaptableRes != null) { - if (element.isAnnotationPresent(PageProperty.class) || !element.getAnnotation(HierarchicalPageProperty.class).inherit()) { - return ReflectionUtil.convertValueMapValue(adaptableRes.getValueMap(), name, declaredType); - } else { + if (useInheritance(element)) { InheritanceValueMap inheritanceValueMap = new HierarchyNodeInheritanceValueMap(adaptableRes); return ReflectionUtil.convertValueMapValue(inheritanceValueMap, name, declaredType); + } else { + return ReflectionUtil.convertValueMapValue(adaptableRes.getValueMap(), name, declaredType); } } @@ -81,10 +85,45 @@ public Object getValue(Object adaptable, String name, Type declaredType, Annotat } - private Resource lookUpFromPage(Resource currentResource) { - Page containingPage = getResourcePage(currentResource); + private Resource lookUpFromPage(Object adaptable, Resource currentResource, AnnotatedElement element) { + + boolean useCurrentPage = useCurrentPage(element); + Page containingPage; + + if(useCurrentPage){ + containingPage = getCurrentPage(adaptable); + if(containingPage == null){ + LOG.error("Could not find current page for resource: {}. Only SlingHttpServletRequest is supported as adaptable", getResource(adaptable).getPath()); + } + }else{ + containingPage = getResourcePage(currentResource); + } + + if(containingPage != null && element.isAnnotationPresent(HierarchicalPageProperty.class)) { + HierarchicalPageProperty annotation = element.getAnnotation(HierarchicalPageProperty.class); + if(annotation.traverseFromAbsoluteParent() > -1){ + containingPage = containingPage.getAbsoluteParent(annotation.traverseFromAbsoluteParent()); + } + } + return containingPage != null ? containingPage.getContentResource() : null; } + private boolean useCurrentPage(AnnotatedElement element){ + + if(element.isAnnotationPresent(HierarchicalPageProperty.class)){ + return element.getAnnotation(HierarchicalPageProperty.class).useCurrentPage(); + }else if (element.isAnnotationPresent(PageProperty.class)){ + return element.getAnnotation(PageProperty.class).useCurrentPage(); + } + return false; + + } + + private boolean useInheritance(AnnotatedElement element){ + return element.isAnnotationPresent(HierarchicalPageProperty.class) && element.getAnnotation(HierarchicalPageProperty.class).inherit(); + } + + } diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/via/annotations/PageContentResourceViaType.java b/bundle/src/main/java/com/adobe/acs/commons/models/via/annotations/PageContentResourceViaType.java new file mode 100644 index 0000000000..9aa8b4915c --- /dev/null +++ b/bundle/src/main/java/com/adobe/acs/commons/models/via/annotations/PageContentResourceViaType.java @@ -0,0 +1,26 @@ +/*- + * #%L + * ACS AEM Commons Bundle + * %% + * Copyright (C) 2013 - 2024 Adobe + * %% + * 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 com.adobe.acs.commons.models.via.annotations; + +import org.apache.sling.models.annotations.ViaProviderType; + +public interface PageContentResourceViaType extends ViaProviderType { + +} diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/via/annotations/package-info.java b/bundle/src/main/java/com/adobe/acs/commons/models/via/annotations/package-info.java new file mode 100644 index 0000000000..c476774cf3 --- /dev/null +++ b/bundle/src/main/java/com/adobe/acs/commons/models/via/annotations/package-info.java @@ -0,0 +1,24 @@ +/*- + * #%L + * ACS AEM Commons Bundle + * %% + * Copyright (C) 2013 - 2024 Adobe + * %% + * 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% + */ +@org.osgi.annotation.versioning.Version("1.0.0") +package com.adobe.acs.commons.models.via.annotations; + + + diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/via/impl/PageContentResourceViaProvider.java b/bundle/src/main/java/com/adobe/acs/commons/models/via/impl/PageContentResourceViaProvider.java new file mode 100644 index 0000000000..5ccb538871 --- /dev/null +++ b/bundle/src/main/java/com/adobe/acs/commons/models/via/impl/PageContentResourceViaProvider.java @@ -0,0 +1,73 @@ +/*- + * #%L + * ACS AEM Commons Bundle + * %% + * Copyright (C) 2013 - 2024 Adobe + * %% + * 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 com.adobe.acs.commons.models.via.impl; + + +import com.adobe.acs.commons.models.via.annotations.PageContentResourceViaType; +import org.apache.commons.lang3.StringUtils; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.annotations.ViaProviderType; +import org.apache.sling.models.spi.ViaProvider; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.adobe.acs.commons.models.injectors.impl.InjectorUtils.*; +import static com.adobe.acs.commons.models.injectors.impl.InjectorUtils.getResource; + +@Component(service = ViaProvider.class) +public class PageContentResourceViaProvider implements ViaProvider { + + public static final String VIA_CURRENT_PAGE = "currentPage"; + + private static final Logger logger = LoggerFactory.getLogger(PageContentResourceViaProvider.class); + + @Override + public Class getType() { + return PageContentResourceViaType.class; + } + + @Override + public Object getAdaptable(Object original, String value) { + + + try{ + final Resource resource; + + if(StringUtils.equals(value, VIA_CURRENT_PAGE)){ + resource = getCurrentPage(original).getContentResource(); + + if(resource == null){ + logger.error("Could not find current page for resource: {}. Only SlingHttpServletRequest is supported as adaptable", getResource(original).getPath()); + } + }else{ + resource = getResourcePage(original).getContentResource(); + } + + return resource; + + }catch(NullPointerException ex){ + logger.error("Error while getting content policy properties", ex); + } + + return null; + + } +} diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java index 2ad5625cc3..ccb11367a1 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java +++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java @@ -23,6 +23,7 @@ import com.adobe.acs.commons.models.injectors.impl.model.impl.TestHierarchicalPagePropertiesModelModelImpl; import com.adobe.acs.commons.models.injectors.impl.model.impl.TestPagePropertiesModelModelImpl; import io.wcm.testing.mock.aem.junit.AemContext; +import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; import org.apache.sling.models.spi.Injector; import org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory; @@ -48,17 +49,10 @@ public class HierarchicalPagePropertyInjectorTest { @Before public void setUp() throws Exception { - context.currentPage("/content/we-retail/language-masters/en/experience/arctic-surfing-in-lofoten"); - context.currentResource("/content/we-retail/language-masters/en/experience/arctic-surfing-in-lofoten/jcr:content/root"); - context.registerService(Injector.class, injector); context.registerService(StaticInjectAnnotationProcessorFactory.class, new HierarchicalPagePropertyAnnotationProcessorFactory()); context.addModelsForClasses(TestHierarchicalPagePropertiesModelModelImpl.class); context.addModelsForClasses(TestPagePropertiesModelModelImpl.class); - - Resource adaptable = context.request().getResource(); - hierarchicalModel = adaptable.adaptTo(TestHierarchicalPagePropertiesModel.class); - pageModel = adaptable.adaptTo(TestPagePropertiesModel.class); } @Test @@ -68,11 +62,19 @@ public void test_name() { @Test public void test() { + + context.currentPage("/content/we-retail/language-masters/en/experience"); + context.currentResource("/content/we-retail/language-masters/en/experience/arctic-surfing-in-lofoten/jcr:content/root"); + + SlingHttpServletRequest adaptable = context.request(); + hierarchicalModel = adaptable.adaptTo(TestHierarchicalPagePropertiesModel.class); + pageModel = adaptable.adaptTo(TestPagePropertiesModel.class); + assertNotNull(hierarchicalModel); assertEquals("inherited!", hierarchicalModel.getHierarchicalPagePropertyString()); assertNull(pageModel.getHierarchicalPagePropertyString()); assertEquals("not inherited", hierarchicalModel.getPagePropertyString()); - } - + assertEquals("inherited!", hierarchicalModel.getSkipLevelHierarchicalPagePropertyString()); + } } diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java index b38acaebb2..0c45c0c21e 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java +++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java @@ -25,8 +25,14 @@ public interface TestHierarchicalPagePropertiesModel { String getPagePropertyString(); + String getSkipLevelHierarchicalPagePropertyString(); + + String getCurrentPagePropertyString(); + String getHierarchicalPagePropertyString(); + String getCurrentPageHierarchicalPagePropertyString(); + String getUndefinedProperty(); boolean getPropertyBoolean(); diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java index ae255f5284..706d8b4d0e 100644 --- a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java +++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java @@ -40,6 +40,15 @@ public class TestHierarchicalPagePropertiesModelModelImpl implements TestHierarc @HierarchicalPageProperty private String hierarchicalPagePropertyString; + @HierarchicalPageProperty(useCurrentPage = true) + private String currentPagePropertyString; + + @HierarchicalPageProperty(useCurrentPage = true) + private String currentPageHierarchicalPagePropertyString; + + @HierarchicalPageProperty(traverseFromAbsoluteParent = 3) + private String skipLevelHierarchicalPagePropertyString; + @HierarchicalPageProperty(value = "hierarchicalPagePropertyBoolean", inherit = false) private boolean hierarchicalPagePropertyBoolean; @@ -70,11 +79,21 @@ public String getPagePropertyString() { return pagePropertyString; } + @Override + public String getCurrentPagePropertyString() { + return currentPagePropertyString; + } + @Override public String getHierarchicalPagePropertyString() { return hierarchicalPagePropertyString; } + @Override + public String getCurrentPageHierarchicalPagePropertyString() { + return currentPageHierarchicalPagePropertyString; + } + @Override public boolean getPropertyBoolean() { return hierarchicalPagePropertyBoolean; @@ -115,4 +134,8 @@ public Double[] getPropertyMultivalueWrappedDoubleArray() { return hierarchicalPagePropertyMultivalueWrappedDoubleArray; } + @Override + public String getSkipLevelHierarchicalPagePropertyString() { + return skipLevelHierarchicalPagePropertyString; + } } diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/via/impl/PageContentResourceViaProviderTest.java b/bundle/src/test/java/com/adobe/acs/commons/models/via/impl/PageContentResourceViaProviderTest.java new file mode 100644 index 0000000000..91421390e0 --- /dev/null +++ b/bundle/src/test/java/com/adobe/acs/commons/models/via/impl/PageContentResourceViaProviderTest.java @@ -0,0 +1,62 @@ +/*- + * #%L + * ACS AEM Commons Bundle + * %% + * Copyright (C) 2013 - 2024 Adobe + * %% + * 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 com.adobe.acs.commons.models.via.impl; + +import com.adobe.acs.commons.models.injectors.impl.InjectorAEMContext; +import com.adobe.acs.commons.models.via.annotations.PageContentResourceViaType; +import io.wcm.testing.mock.aem.junit.AemContext; +import org.apache.sling.api.resource.Resource; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.junit.jupiter.api.Assertions.*; + +@RunWith(MockitoJUnitRunner.class) +public class PageContentResourceViaProviderTest +{ + + + @Rule + public final AemContext context = InjectorAEMContext.provide(); + + @Test + public void test(){ + context.currentPage("/content/we-retail/language-masters/en/experience"); + context.currentResource("/content/we-retail/language-masters/en/experience/arctic-surfing-in-lofoten/jcr:content/root"); + + PageContentResourceViaProvider systemUnderTest = new PageContentResourceViaProvider(); + + Object newAdaptableResourcePage = systemUnderTest.getAdaptable(context.currentResource(), ""); + Resource resourcePageJcrContent = (Resource) newAdaptableResourcePage; + assertEquals("/content/we-retail/language-masters/en/experience/arctic-surfing-in-lofoten/jcr:content", resourcePageJcrContent.getPath()); + + + + Object newAdaptableCurrentPage = systemUnderTest.getAdaptable(context.request(), PageContentResourceViaProvider.VIA_CURRENT_PAGE); + Resource currentPageJcrContent = (Resource) newAdaptableCurrentPage; + assertEquals("/content/we-retail/language-masters/en/experience/jcr:content", currentPageJcrContent.getPath()); + } + + + + +} diff --git a/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json b/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json index aaa5df9760..da1dedef09 100644 --- a/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json +++ b/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json @@ -11,6 +11,8 @@ ], "cq:designPath": "/etc/designs/acs-commons", "hierarchicalPagePropertyString": "inherited!", + "currentPageHierarchicalPagePropertyString": "inherited!", + "skipLevelHierarchicalPagePropertyString": "inherited!", "pagePropertyString": "inherited!", "hierarchicalPagePropertyBoolean": true, "hierarchicalPagePropertyInteger": 11, @@ -115,6 +117,7 @@ "", "" ], + "currentPageHierarchicalPagePropertyString": "not inherited", "sling:resourceType": "weretail/components/structure/page", "cq:lastModifiedBy": "admin", "hideSubItemsInNav": true, @@ -183,6 +186,8 @@ "sling:resourceType": "weretail/components/structure/page", "cq:lastModifiedBy": "admin", "pagePropertyString": "not inherited", + "currentPageHierarchicalPagePropertyString": "this value should not be used", + "skipLevelHierarchicalPagePropertyString": "this value should not be used", "hierarchicalPagePropertyBoolean": false, "root": { "jcr:primaryType": "nt:unstructured",