You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:55:37 UTC

[sling-org-apache-sling-models-impl] 07/24: SLING-3863 - adding initial values for primitives when injecting to fields and constructor params. Thanks to Stefan Seifert for the original patch!

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

rombert pushed a commit to annotated tag org.apache.sling.models.impl-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit ec0e0a1c7d32441f6e103695f5cee9710dee6df0
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Wed Aug 20 18:42:24 2014 +0000

    SLING-3863 - adding initial values for primitives when injecting to fields and constructor params. Thanks to Stefan Seifert for the original patch!
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1619199 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/models/impl/ModelAdapterFactory.java     |  74 ++++++++++++-
 .../sling/models/impl/OptionalPrimitivesTest.java  | 119 +++++++++++++++++++++
 .../classes/OptionalPrimitivesModel.java           |  84 +++++++++++++++
 .../OptionalPrimitivesModel.java                   |  89 +++++++++++++++
 .../interfaces/OptionalPrimitivesModel.java        |  52 +++++++++
 5 files changed, 415 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
index b77cce1..a81cc31 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -249,6 +249,8 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
          * @return true if injection was successful otherwise false
          */
         public boolean inject(AnnotatedElement element, Object value);
+
+        public boolean shouldInjectPrimitiveInitValue();
     }
 
     private static class SetFieldCallback implements InjectCallback {
@@ -263,6 +265,11 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         public boolean inject(AnnotatedElement element, Object value) {
             return setField((Field) element, object, value);
         }
+
+        @Override
+        public boolean shouldInjectPrimitiveInitValue() {
+            return false;
+        }
     }
 
     private static class SetMethodsCallback implements InjectCallback {
@@ -277,6 +284,11 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         public boolean inject(AnnotatedElement element, Object value) {
             return setMethod((Method) element, methods, value);
         }
+
+        @Override
+        public boolean shouldInjectPrimitiveInitValue() {
+            return true;
+        }
     }
     
     private static class SetConstructorParameterCallback implements InjectCallback {
@@ -291,6 +303,11 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         public boolean inject(AnnotatedElement element, Object value) {
             return setConstructorParameter((ConstructorParameter)element, parameterValues, value);
         }
+
+        @Override
+        public boolean shouldInjectPrimitiveInitValue() {
+            return true;
+        }
     }
 
     private boolean injectElement(final AnnotatedElement element, final Object adaptable, final Type type,
@@ -331,9 +348,16 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         }
 
         // if default is not set, check if mandatory
-        if (!wasInjectionSuccessful && !isOptional(element, modelAnnotation, annotationProcessor)) {
-            return false;
+        if (!wasInjectionSuccessful) {
+            if (isOptional(element, modelAnnotation, annotationProcessor)) {
+                if (callback.shouldInjectPrimitiveInitValue()) {
+                    injectPrimitiveInitialValue(element, type, callback);
+                }
+            } else {
+                return false;
+            }
         }
+        
         return true;
     }
 
@@ -613,6 +637,39 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         return callback.inject(point, value);
     }
 
+    /**
+     * Injects the default initial value for the given primitive class which
+     * cannot be null (e.g. int = 0, boolean = false).
+     * 
+     * @param point Annotated element
+     * @param wrapperType Non-primitive wrapper class for primitive class
+     * @param callback Inject callback
+     */
+    private void injectPrimitiveInitialValue(AnnotatedElement point, Type wrapperType, InjectCallback callback) {
+        Type primitiveType = mapWrapperClasses(wrapperType);
+        Object value = null;
+        if (primitiveType == int.class) {
+            value = Integer.valueOf(0);
+        } else if (primitiveType == long.class) {
+            value = Long.valueOf(0);
+        } else if (primitiveType == boolean.class) {
+            value = Boolean.FALSE;
+        } else if (primitiveType == double.class) {
+            value = Double.valueOf(0);
+        } else if (primitiveType == float.class) {
+            value = Float.valueOf(0);
+        } else if (primitiveType == short.class) {
+            value = Short.valueOf((short) 0);
+        } else if (primitiveType == byte.class) {
+            value = Byte.valueOf((byte) 0);
+        } else if (primitiveType == char.class) {
+            value = Character.valueOf('\u0000');
+        }
+        if (value != null) {
+            callback.inject(point, value);
+        };
+    }
+    
     private Object getAdaptable(Object adaptable, AnnotatedElement point, InjectAnnotationProcessor processor) {
         String viaPropertyName = null;
         if (processor != null) {
@@ -701,7 +758,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         }
     }
 
-    private Type mapPrimitiveClasses(Type type) {
+    private static Type mapPrimitiveClasses(Type type) {
         if (type instanceof Class<?>) {
             return ClassUtils.primitiveToWrapper((Class<?>) type);
         } else {
@@ -709,6 +766,14 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         }
     }
 
+    private static Type mapWrapperClasses(Type type) {
+        if (type instanceof Class<?>) {
+            return ClassUtils.wrapperToPrimitive((Class<?>) type);
+        } else {
+            return type;
+        }
+    }
+
     private static boolean setField(Field field, Object createdObject, Object value) {
         if (value != null) {
             if (!isAcceptableType(field.getType(), field.getGenericType(), value)) {
@@ -831,6 +896,9 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         if (type == Short.TYPE) {
             return Short.class.isInstance(value);
         }
+        if (type == Byte.TYPE) {
+            return Byte.class.isInstance(value);
+        }
         if (type == Character.TYPE) {
             return Character.class.isInstance(value);
         }
diff --git a/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java b/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
new file mode 100644
index 0000000..7e7637a
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.models.impl.injectors.ChildResourceInjector;
+import org.apache.sling.models.impl.injectors.ValueMapInjector;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+/**
+ * Validates that @Optional annotations works with primitive values which do not support null
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class OptionalPrimitivesTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    private ModelAdapterFactory factory;
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(new ValueMapInjector(), new ServicePropertiesMap(2, 2));
+        factory.bindInjector(new ChildResourceInjector(), new ServicePropertiesMap(1, 1));
+    }
+
+    @Test
+    public void testFieldInjectionClass() {
+        ValueMap vm = ValueMap.EMPTY;
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        org.apache.sling.models.testmodels.classes.OptionalPrimitivesModel model
+                = factory.getAdapter(res, org.apache.sling.models.testmodels.classes.OptionalPrimitivesModel.class);
+        assertNotNull(model);
+        assertEquals(0, model.getByteValue());
+        assertEquals(0, model.getShortValue());
+        assertEquals(0, model.getIntValue());
+        assertEquals(0L, model.getLongValue());
+        assertEquals(0.0f, model.getFloatValue(), 0.00001d);
+        assertEquals(0.0d, model.getDoubleValue(), 0.00001d);
+        assertEquals('\u0000', model.getCharValue());
+        assertEquals(false, model.getBooleanValue());
+    }
+
+    @Test
+    public void testConstructorInjection() {
+        ValueMap vm = ValueMap.EMPTY;
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.OptionalPrimitivesModel model
+                = factory.getAdapter(res, org.apache.sling.models.testmodels.classes.constructorinjection.OptionalPrimitivesModel.class);
+        assertNotNull(model);
+        assertEquals(0, model.getByteValue());
+        assertEquals(0, model.getShortValue());
+        assertEquals(0, model.getIntValue());
+        assertEquals(0L, model.getLongValue());
+        assertEquals(0.0f, model.getFloatValue(), 0.00001d);
+        assertEquals(0.0d, model.getDoubleValue(), 0.00001d);
+        assertEquals('\u0000', model.getCharValue());
+        assertEquals(false, model.getBooleanValue());
+    }
+
+    @Test
+    public void testFieldInjectionInterface() {
+        ValueMap vm = ValueMap.EMPTY;
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        org.apache.sling.models.testmodels.interfaces.OptionalPrimitivesModel model
+                = factory.getAdapter(res, org.apache.sling.models.testmodels.interfaces.OptionalPrimitivesModel.class);
+        assertNotNull(model);
+        assertEquals(0, model.getByteValue());
+        assertEquals(0, model.getShortValue());
+        assertEquals(0, model.getIntValue());
+        assertEquals(0L, model.getLongValue());
+        assertEquals(0.0f, model.getFloatValue(), 0.00001d);
+        assertEquals(0.0d, model.getDoubleValue(), 0.00001d);
+        assertEquals('\u0000', model.getCharValue());
+        assertEquals(false, model.getBooleanValue());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java
new file mode 100644
index 0000000..f97afa9
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java
@@ -0,0 +1,84 @@
+/*
+ * 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 javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Optional;
+
+@Model(adaptables = Resource.class)
+public class OptionalPrimitivesModel {
+
+    @Inject @Optional
+    private byte byteValue;
+
+    @Inject @Optional
+    private short shortValue;
+
+    @Inject @Optional
+    private int intValue;
+    
+    @Inject @Optional
+    private long longValue;
+    
+    @Inject @Optional
+    private float floatValue;
+    
+    @Inject @Optional
+    private double doubleValue;
+    
+    @Inject @Optional
+    private char charValue;
+    
+    @Inject @Optional
+    private boolean booleanValue;
+
+    public byte getByteValue() {
+        return this.byteValue;
+    }
+
+    public short getShortValue() {
+        return this.shortValue;
+    }
+
+    public int getIntValue() {
+        return this.intValue;
+    }
+
+    public long getLongValue() {
+        return this.longValue;
+    }
+
+    public float getFloatValue() {
+        return this.floatValue;
+    }
+
+    public double getDoubleValue() {
+        return this.doubleValue;
+    }
+
+    public char getCharValue() {
+        return this.charValue;
+    }
+
+    public boolean getBooleanValue() {
+        return this.booleanValue;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/OptionalPrimitivesModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/OptionalPrimitivesModel.java
new file mode 100644
index 0000000..c6f51c2
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/OptionalPrimitivesModel.java
@@ -0,0 +1,89 @@
+/*
+ * 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.constructorinjection;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Optional;
+
+@Model(adaptables = Resource.class)
+public class OptionalPrimitivesModel {
+
+    private final byte byteValue;
+    private final short shortValue;
+    private final int intValue;
+    private final long longValue;
+    private final float floatValue;
+    private final double doubleValue;
+    private final char charValue;
+    private final boolean booleanValue;
+    
+    @Inject
+    public OptionalPrimitivesModel(
+            @Optional byte byteValue,
+            @Optional short shortValue,
+            @Optional int intValue,
+            @Optional long longValue,
+            @Optional float floatValue,
+            @Optional double doubleValue,
+            @Optional char charValue,
+            @Optional boolean booleanValue) {
+        this.byteValue = byteValue;
+        this.shortValue = shortValue;
+        this.intValue = intValue;
+        this.longValue = longValue;
+        this.floatValue = floatValue;
+        this.doubleValue = doubleValue;
+        this.charValue = charValue;
+        this.booleanValue = booleanValue;
+    }
+
+    public byte getByteValue() {
+        return this.byteValue;
+    }
+
+    public short getShortValue() {
+        return this.shortValue;
+    }
+
+    public int getIntValue() {
+        return this.intValue;
+    }
+
+    public long getLongValue() {
+        return this.longValue;
+    }
+
+    public float getFloatValue() {
+        return this.floatValue;
+    }
+
+    public double getDoubleValue() {
+        return this.doubleValue;
+    }
+
+    public char getCharValue() {
+        return this.charValue;
+    }
+
+    public boolean getBooleanValue() {
+        return this.booleanValue;
+    }
+    
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java b/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java
new file mode 100644
index 0000000..8f8ed54
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java
@@ -0,0 +1,52 @@
+/*
+ * 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.interfaces;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Optional;
+
+@Model(adaptables = Resource.class)
+public interface OptionalPrimitivesModel {
+
+    @Inject @Optional
+    public byte getByteValue();
+
+    @Inject @Optional
+    public short getShortValue();
+
+    @Inject @Optional
+    public int getIntValue();
+    
+    @Inject @Optional
+    public long getLongValue();
+    
+    @Inject @Optional
+    public float getFloatValue();
+    
+    @Inject @Optional
+    public double getDoubleValue();
+    
+    @Inject @Optional
+    public char getCharValue();
+    
+    @Inject @Optional
+    public boolean getBooleanValue();
+    
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.