Author: justin
Date: Wed Aug 20 18:42:24 2014
New Revision: 1619199
URL: http://svn.apache.org/r1619199
Log:
SLING-3863 - adding initial values for primitives when injecting to fields and
constructor params. Thanks to Stefan Seifert for the original patch!
Added:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/OptionalPrimitivesModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java
Modified:
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
Modified:
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java?rev=1619199&r1=1619198&r2=1619199&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
(original)
+++
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
Wed Aug 20 18:42:24 2014
@@ -249,6 +249,8 @@ public class ModelAdapterFactory impleme
* @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 impleme
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 impleme
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 impleme
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 impleme
}
// 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 impleme
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 impleme
}
}
- 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 impleme
}
}
+ 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 impleme
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);
}
Added:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java?rev=1619199&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
(added)
+++
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
Wed Aug 20 18:42:24 2014
@@ -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());
+ }
+
+}
Added:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java?rev=1619199&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java
(added)
+++
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java
Wed Aug 20 18:42:24 2014
@@ -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;
+ }
+
+}
Added:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/OptionalPrimitivesModel.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/OptionalPrimitivesModel.java?rev=1619199&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/OptionalPrimitivesModel.java
(added)
+++
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/OptionalPrimitivesModel.java
Wed Aug 20 18:42:24 2014
@@ -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;
+ }
+
+}
Added:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java?rev=1619199&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java
(added)
+++
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java
Wed Aug 20 18:42:24 2014
@@ -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();
+
+}