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 <[email protected]> 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 "[email protected]" <[email protected]>.
