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

sseifert pushed a commit to branch feature/SLING-11812-collection-default-values
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit 4d49bc9ea137dbdbf67e884fc94cc5c219b1bbb6
Author: Stefan Seifert <[email protected]>
AuthorDate: Tue Mar 28 12:33:18 2023 +0200

    SLING-11812 support default value injection for Collection and List types
---
 .../impl/model/AbstractInjectableElement.java      | 43 +++++++++++++++++++-
 .../models/impl/ResourceModelClassesTest.java      | 45 ++++++++++++++++++++-
 .../classes/CollectionDefaultsModel.java           | 46 ++++++++++++++++++++++
 .../testmodels/classes/ListDefaultsModel.java      | 46 ++++++++++++++++++++++
 4 files changed, 178 insertions(+), 2 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/models/impl/model/AbstractInjectableElement.java
 
b/src/main/java/org/apache/sling/models/impl/model/AbstractInjectableElement.java
index 72ccb18..cdb79f8 100644
--- 
a/src/main/java/org/apache/sling/models/impl/model/AbstractInjectableElement.java
+++ 
b/src/main/java/org/apache/sling/models/impl/model/AbstractInjectableElement.java
@@ -19,7 +19,12 @@
 package org.apache.sling.models.impl.model;
 
 import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Array;
+import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 
 import javax.inject.Named;
 
@@ -37,6 +42,7 @@ import org.apache.sling.models.impl.ReflectionUtil;
 import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
 import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor2;
 import 
org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -148,7 +154,20 @@ abstract class AbstractInjectableElement implements 
InjectableElement {
 
         Object value = null;
 
-        if (type instanceof Class) {
+        if (type instanceof ParameterizedType) {
+            ParameterizedType parameterizedType = (ParameterizedType)type;
+            Class<?> rawType = (Class<?>)parameterizedType.getRawType();
+            if (Collection.class.isAssignableFrom(rawType)) {
+                value = getFirstNonEmptyArrayAsList(
+                        defaultAnnotation.values(),
+                        defaultAnnotation.intValues(),
+                        defaultAnnotation.longValues(),
+                        defaultAnnotation.floatValues(),
+                        defaultAnnotation.doubleValues(),
+                        defaultAnnotation.booleanValues());
+            }
+        }
+        else if (type instanceof Class) {
             Class<?> injectedClass = (Class<?>) type;
             if (injectedClass.isArray()) {
                 Class<?> componentType = injectedClass.getComponentType();
@@ -206,6 +225,28 @@ abstract class AbstractInjectableElement implements 
InjectableElement {
         return value;
     }
 
+    /**
+     * Gets the first non-empty array from the given list of arrays, and 
returns its values as list.
+     * @param arrays Arrays
+     * @return List with values of first non-empty array, or null.
+     */
+    private static @Nullable List<Object> 
getFirstNonEmptyArrayAsList(Object... arrays) {
+        for (Object array : arrays) {
+            if (array != null && array.getClass().isArray()) {
+                int arrayLength = Array.getLength(array);
+                if (arrayLength > 0) {
+                    List<Object> result = new ArrayList<>();
+                    for (int i=0; i<arrayLength; i++) {
+                        result.add(Array.get(array, i));
+                    }
+                    return result;
+                }
+
+            }
+        }
+        return null;
+    }
+
     private static boolean getOptional(AnnotatedElement element, 
InjectAnnotationProcessor annotationProcessor) {
         if (element.isAnnotationPresent(Optional.class)) {
             return true;
diff --git 
a/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java 
b/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
index 8bbdbf8..c6836a1 100644
--- a/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
@@ -46,6 +46,8 @@ import 
org.apache.sling.models.testmodels.classes.ArrayWrappersModel;
 import org.apache.sling.models.testmodels.classes.ChildModel;
 import org.apache.sling.models.testmodels.classes.ChildResourceModel;
 import org.apache.sling.models.testmodels.classes.ChildValueMapModel;
+import org.apache.sling.models.testmodels.classes.CollectionDefaultsModel;
+import org.apache.sling.models.testmodels.classes.ListDefaultsModel;
 import org.apache.sling.models.testmodels.classes.ListModel;
 import org.apache.sling.models.testmodels.classes.ParentModel;
 import 
org.apache.sling.models.testmodels.classes.ResourceModelWithRequiredField;
@@ -72,7 +74,18 @@ public class ResourceModelClassesTest {
         factory.bindInjector(new ChildResourceInjector(), new 
ServicePropertiesMap(1, 1));
 
         factory.injectAnnotationProcessorFactories = 
factory.injectAnnotationProcessorFactories = 
Collections.<InjectAnnotationProcessorFactory>singletonList(new 
ValueMapInjector());
-        
factory.adapterImplementations.addClassesAsAdapterAndImplementation(SimplePropertyModel.class,
 ArrayWrappersModel.class, ResourceModelWithRequiredField.class, 
ChildValueMapModel.class, ArrayPrimitivesModel.class, ChildResourceModel.class, 
ResourceModelWithRequiredFieldOptionalStrategy.class, ParentModel.class, 
ChildModel.class, ListModel.class);
+        
factory.adapterImplementations.addClassesAsAdapterAndImplementation(SimplePropertyModel.class,
+                ArrayWrappersModel.class,
+                ResourceModelWithRequiredField.class,
+                ChildValueMapModel.class,
+                ArrayPrimitivesModel.class,
+                ChildResourceModel.class,
+                ResourceModelWithRequiredFieldOptionalStrategy.class,
+                ParentModel.class,
+                ChildModel.class,
+                ListModel.class,
+                ListDefaultsModel.class,
+                CollectionDefaultsModel.class);
     }
 
     @Test
@@ -167,6 +180,36 @@ public class ResourceModelClassesTest {
         assertEquals("hello", model.getStringList().get(0));
     }
 
+    @Test
+    public void testListDefaultsModel() {
+        Map<String, Object> map = new HashMap<>();
+
+        ValueMap vm = new ValueMapDecorator(map);
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        ListDefaultsModel model = factory.getAdapter(res, 
ListDefaultsModel.class);
+        assertNotNull(model);
+
+        assertEquals(Arrays.asList(1,2,3), model.getIntList());
+        assertEquals(Arrays.asList("v1", "v2"), model.getStringList());
+    }
+
+    @Test
+    public void testCollectionDefaultsModel() {
+        Map<String, Object> map = new HashMap<>();
+
+        ValueMap vm = new ValueMapDecorator(map);
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        CollectionDefaultsModel model = factory.getAdapter(res, 
CollectionDefaultsModel.class);
+        assertNotNull(model);
+
+        assertEquals(Arrays.asList(1,2,3), model.getIntCollection());
+        assertEquals(Arrays.asList("v1", "v2"), model.getStringCollection());
+    }
+
     @SuppressWarnings({ "unused", "null" })
     @Test
     public void testRequiredPropertyModel() {
diff --git 
a/src/test/java/org/apache/sling/models/testmodels/classes/CollectionDefaultsModel.java
 
b/src/test/java/org/apache/sling/models/testmodels/classes/CollectionDefaultsModel.java
new file mode 100644
index 0000000..666f1c1
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/models/testmodels/classes/CollectionDefaultsModel.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.sling.models.testmodels.classes;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Default;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+public class CollectionDefaultsModel {
+
+    @Inject
+    @Default(intValues = {1,2,3})
+    private Collection<Integer> intList;
+
+    @Inject
+    @Default(values = {"v1","v2"})
+    private Collection<String> stringList;
+
+    public Collection<Integer> getIntCollection() {
+        return intList;
+    }
+
+    public Collection<String> getStringCollection() {
+        return stringList;
+    }
+
+}
diff --git 
a/src/test/java/org/apache/sling/models/testmodels/classes/ListDefaultsModel.java
 
b/src/test/java/org/apache/sling/models/testmodels/classes/ListDefaultsModel.java
new file mode 100644
index 0000000..4bef12c
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/models/testmodels/classes/ListDefaultsModel.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.sling.models.testmodels.classes;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Default;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+public class ListDefaultsModel {
+
+    @Inject
+    @Default(intValues = {1,2,3})
+    private List<Integer> intList;
+
+    @Inject
+    @Default(values = {"v1","v2"})
+    private List<String> stringList;
+
+    public List<Integer> getIntList() {
+        return intList;
+    }
+
+    public List<String> getStringList() {
+        return stringList;
+    }
+
+}

Reply via email to