SLING-8706 - Injections for java.util.Optional<> should be automatic optional
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java
index f24b367..92036f7 100644
--- a/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java
+++ b/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java
@@ -23,6 +23,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import java.util.Optional;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.ObjectUtils;
@@ -98,6 +99,11 @@
return null;
}
Class<?> collectionType = (Class<?>) pType.getRawType();
+
+ if (collectionType.equals(Optional.class)) {
+ return Optional.ofNullable(map.get(name));
+ }
+
if (!(collectionType.equals(Collection.class) || collectionType.equals(List.class))) {
return null;
}
diff --git a/src/test/java/org/apache/sling/models/impl/OptionalObjectsTest.java b/src/test/java/org/apache/sling/models/impl/OptionalObjectsTest.java
new file mode 100644
index 0000000..13a63b6
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/OptionalObjectsTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.impl;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.models.impl.injectors.ValueMapInjector;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class OptionalObjectsTest {
+
+ private ModelAdapterFactory factory;
+
+ @Before
+ public void setup() {
+ factory = AdapterFactoryTest.createModelAdapterFactory();
+ factory.bindInjector(new ValueMapInjector(), new ServicePropertiesMap(2, 2));
+ factory.adapterImplementations.addClassesAsAdapterAndImplementation(
+ org.apache.sling.models.testmodels.classes.OptionalObjectsModel.class);
+ }
+
+ @Test
+ public void testFieldInjectionClass() {
+ Map<String, Object> map = new HashMap<>();
+ map.put("optionalString", "foo bar baz");
+ map.put("optionalByte", Byte.valueOf("1"));
+ map.put("optionalInteger", Integer.valueOf("1"));
+ map.put("optionalShort", Short.valueOf("1"));
+ map.put("optionalLong", Long.valueOf("1"));
+ map.put("optionalShort", Short.valueOf("1"));
+ map.put("optionalDouble", Double.valueOf("1"));
+ map.put("optionalFloat", Float.valueOf("1"));
+ map.put("optionalChar", '1');
+ map.put("optionalBoolean", Boolean.valueOf("true"));
+ map.put("optionalList", Arrays.asList("foo", "bar", "baz"));
+ map.put("optionalArray", new String[]{"qux", "quux"});
+
+ Resource res = mock(Resource.class);
+ when(res.adaptTo(ValueMap.class)).thenReturn(new ValueMapDecorator(map));
+
+ org.apache.sling.models.testmodels.classes.OptionalObjectsModel model = factory.getAdapter(res,
+ org.apache.sling.models.testmodels.classes.OptionalObjectsModel.class);
+ assertNotNull(model);
+
+ assertEquals(Optional.of("foo bar baz"), model.getOptionalString());
+ assertEquals(Optional.empty(), model.getOptionalNullString());
+
+ assertEquals(Optional.of(1), model.getOptionalInteger());
+ assertEquals(Optional.empty(), model.getOptionalNullInteger());
+
+ assertEquals(Optional.of(Byte.valueOf("1")), model.getOptionalByte());
+ assertEquals(Optional.empty(), model.getOptionalNullByte());
+
+ assertEquals(Optional.of(Long.valueOf("1")), model.getOptionalLong());
+ assertEquals(Optional.empty(), model.getOptionalNullLong());
+
+ assertEquals(Optional.of(Short.valueOf("1")), model.getOptionalShort());
+ assertEquals(Optional.empty(), model.getOptionalNullShort());
+
+ assertEquals(Optional.of(Double.valueOf("1")), model.getOptionalDouble());
+ assertEquals(Optional.empty(), model.getOptionalNullDouble());
+
+ assertEquals(Optional.of(Float.valueOf("1")), model.getOptionalFloat());
+ assertEquals(Optional.empty(), model.getOptionalNullFloat());
+
+ assertEquals(Optional.of(1L), model.getOptionalLong());
+ assertEquals(Optional.empty(), model.getOptionalNullLong());
+
+ assertEquals(Optional.of('1'), model.getOptionalChar());
+ assertEquals(Optional.empty(), model.getOptionalNullChar());
+
+ assertEquals(Optional.of(Boolean.valueOf("true")), model.getOptionalBoolean());
+ assertEquals(Optional.empty(), model.getOptionalNullBoolean());
+
+ assertEquals(Optional.of(Arrays.asList("foo", "bar", "baz")), model.getOptionalList());
+ assertEquals(Optional.empty(), model.getOptionalNullList());
+
+ assertTrue(model.getOptionalArray().isPresent());
+ assertTrue("qux".equalsIgnoreCase(model.getOptionalArray().get()[0]));
+ assertTrue("quux".equalsIgnoreCase(model.getOptionalArray().get()[1]));
+ assertEquals(Optional.empty(), model.getOptionalNullArray());
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/OptionalObjectsModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/OptionalObjectsModel.java
new file mode 100644
index 0000000..a130e3d
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/OptionalObjectsModel.java
@@ -0,0 +1,182 @@
+/*
+ * 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 java.util.Optional;
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+public class OptionalObjectsModel {
+
+ @Inject
+ private Optional<String> optionalString;
+
+ @Inject
+ private Optional<String> optionalNullString;
+
+ @Inject
+ private Optional<Byte> optionalByte;
+
+ @Inject
+ private Optional<Byte> optionalNullByte;
+
+ @Inject
+ private Optional<Short> optionalShort;
+
+ @Inject
+ private Optional<Short> optionalNullShort;
+
+ @Inject
+ private Optional<Integer> optionalInteger;
+
+ @Inject
+ private Optional<Integer> optionalNullInteger;
+
+ @Inject
+ private Optional<Long> optionalLong;
+
+ @Inject
+ private Optional<Long> optionalNullLong;
+
+ @Inject
+ private Optional<Float> optionalFloat;
+
+ @Inject
+ private Optional<Float> optionalNullFloat;
+
+ @Inject
+ private Optional<Double> optionalDouble;
+
+ @Inject
+ private Optional<Double> optionalNullDouble;
+
+ @Inject
+ private Optional<Character> optionalChar;
+
+ @Inject
+ private Optional<Character> optionalNullChar;
+
+ @Inject
+ private Optional<Boolean> optionalBoolean;
+
+ @Inject
+ private Optional<Boolean> optionalNullBoolean;
+
+ @Inject
+ private Optional<? extends Collection> optionalList;
+
+ @Inject
+ private Optional<? extends Collection> optionalNullList;
+
+ @Inject
+ private Optional<String[]> optionalArray;
+
+ @Inject
+ private Optional<String[]> optionalNullArray;
+
+ public Optional<String> getOptionalString() {
+ return optionalString;
+ }
+
+ public Optional<String> getOptionalNullString() {
+ return optionalNullString;
+ }
+
+ public Optional<Byte> getOptionalByte() {
+ return optionalByte;
+ }
+
+ public Optional<Byte> getOptionalNullByte() {
+ return optionalNullByte;
+ }
+
+ public Optional<Short> getOptionalShort() {
+ return optionalShort;
+ }
+
+ public Optional<Short> getOptionalNullShort() {
+ return optionalNullShort;
+ }
+
+ public Optional<Integer> getOptionalInteger() {
+ return optionalInteger;
+ }
+
+ public Optional<Integer> getOptionalNullInteger() {
+ return optionalNullInteger;
+ }
+
+ public Optional<Long> getOptionalLong() {
+ return optionalLong;
+ }
+
+ public Optional<Long> getOptionalNullLong() {
+ return optionalNullLong;
+ }
+
+ public Optional<Float> getOptionalFloat() {
+ return optionalFloat;
+ }
+
+ public Optional<Float> getOptionalNullFloat() {
+ return optionalNullFloat;
+ }
+
+ public Optional<Double> getOptionalDouble() {
+ return optionalDouble;
+ }
+
+ public Optional<Double> getOptionalNullDouble() {
+ return optionalNullDouble;
+ }
+
+ public Optional<Character> getOptionalChar() {
+ return optionalChar;
+ }
+
+ public Optional<Character> getOptionalNullChar() {
+ return optionalNullChar;
+ }
+
+ public Optional<Boolean> getOptionalBoolean() {
+ return optionalBoolean;
+ }
+
+ public Optional<Boolean> getOptionalNullBoolean() {
+ return optionalNullBoolean;
+ }
+
+ public Optional<? extends Collection> getOptionalList() {
+ return optionalList;
+ }
+
+ public Optional<? extends Collection> getOptionalNullList() {
+ return optionalNullList;
+ }
+
+ public Optional<String[]> getOptionalArray() {
+ return optionalArray;
+ }
+
+ public Optional<String[]> getOptionalNullArray() {
+ return optionalNullArray;
+ }
+}