You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ju...@apache.org on 2014/06/24 20:37:50 UTC

svn commit: r1605150 - in /sling/trunk/bundles/extensions/models: api/src/main/java/org/apache/sling/models/annotations/ impl/src/main/java/org/apache/sling/models/impl/ impl/src/test/java/org/apache/sling/models/impl/ impl/src/test/java/org/apache/sli...

Author: justin
Date: Tue Jun 24 18:37:50 2014
New Revision: 1605150

URL: http://svn.apache.org/r1605150
Log:
SLING-3696 - adding support for defining a default injection strategy of required or optional. Also adding a @Required annotation

Added:
    sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/DefaultInjectionStrategy.java
      - copied, changed from r1605101, sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java
    sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java
      - copied, changed from r1605101, sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredFieldOptionalStrategy.java
      - copied, changed from r1605101, sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java
Modified:
    sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java
    sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java
    sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java

Copied: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/DefaultInjectionStrategy.java (from r1605101, sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java)
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/DefaultInjectionStrategy.java?p2=sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/DefaultInjectionStrategy.java&p1=sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java&r1=1605101&r2=1605150&rev=1605150&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java (original)
+++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/DefaultInjectionStrategy.java Tue Jun 24 18:37:50 2014
@@ -14,7 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0.0")
 package org.apache.sling.models.annotations;
 
-import aQute.bnd.annotation.Version;
\ No newline at end of file
+public enum DefaultInjectionStrategy {
+
+    REQUIRED, OPTIONAL
+
+}

Modified: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java?rev=1605150&r1=1605149&r2=1605150&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java (original)
+++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java Tue Jun 24 18:37:50 2014
@@ -31,4 +31,6 @@ public @interface Model {
 
     public Class<?>[] adaptables();
 
+    public DefaultInjectionStrategy defaultInjectionStrategy() default DefaultInjectionStrategy.REQUIRED;
+
 }

Copied: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java (from r1605101, sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java)
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java?p2=sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java&p1=sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java&r1=1605101&r2=1605150&rev=1605150&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java (original)
+++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java Tue Jun 24 18:37:50 2014
@@ -22,13 +22,10 @@ import java.lang.annotation.RetentionPol
 import java.lang.annotation.Target;
 
 /**
- * Mark a class as adaptable via YAMF.
- *
+ * Marker annotation for required injections.
  */
-@Target(ElementType.TYPE)
+@Target({ ElementType.FIELD, ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
-public @interface Model {
-
-    public Class<?>[] adaptables();
+public @interface Required {
 
 }

Modified: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java?rev=1605150&r1=1605149&r2=1605150&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java (original)
+++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java Tue Jun 24 18:37:50 2014
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0.0")
+@Version("1.1.0")
 package org.apache.sling.models.annotations;
 
 import aQute.bnd.annotation.Version;
\ No newline at end of file

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=1605150&r1=1605149&r2=1605150&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 Tue Jun 24 18:37:50 2014
@@ -61,8 +61,10 @@ import org.apache.sling.api.adapter.Adap
 import org.apache.sling.api.adapter.AdapterFactory;
 import org.apache.sling.commons.osgi.ServiceUtil;
 import org.apache.sling.models.annotations.Default;
+import org.apache.sling.models.annotations.DefaultInjectionStrategy;
 import org.apache.sling.models.annotations.Model;
 import org.apache.sling.models.annotations.Optional;
+import org.apache.sling.models.annotations.Required;
 import org.apache.sling.models.annotations.Source;
 import org.apache.sling.models.annotations.Via;
 import org.apache.sling.models.spi.DisposalCallback;
@@ -187,7 +189,7 @@ public class ModelAdapterFactory impleme
         }
 
         if (type.isInterface()) {
-            InvocationHandler handler = createInvocationHandler(adaptable, type);
+            InvocationHandler handler = createInvocationHandler(adaptable, type, modelAnnotation);
             if (handler != null) {
                 return (AdapterType) Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[] { type }, handler);
             } else {
@@ -195,7 +197,7 @@ public class ModelAdapterFactory impleme
             }
         } else {
             try {
-                return createObject(adaptable, type);
+                return createObject(adaptable, type, modelAnnotation);
             } catch (Exception e) {
                 log.error("unable to create object", e);
                 return null;
@@ -276,7 +278,7 @@ public class ModelAdapterFactory impleme
     }
 
     private boolean injectFieldOrMethod(final AnnotatedElement element, final Object adaptable, final Type type,
-            final DisposalCallbackRegistry registry, InjectCallback callback) {
+            final Model modelAnnotation, final DisposalCallbackRegistry registry, InjectCallback callback) {
 
         InjectAnnotationProcessor annotationProcessor = null;
         String source = getSource(element);
@@ -310,13 +312,13 @@ public class ModelAdapterFactory impleme
         }
 
         // if default is not set, check if mandatory
-        if (!wasInjectionSuccessful && !isOptional(element, annotationProcessor)) {
+        if (!wasInjectionSuccessful && !isOptional(element, modelAnnotation, annotationProcessor)) {
             return false;
         }
         return true;
     }
 
-    private InvocationHandler createInvocationHandler(final Object adaptable, final Class<?> type) {
+    private InvocationHandler createInvocationHandler(final Object adaptable, final Class<?> type, Model modelAnnotation) {
         Set<Method> injectableMethods = collectInjectableMethods(type);
         final Map<Method, Object> methods = new HashMap<Method, Object>();
         SetMethodsCallback callback = new SetMethodsCallback(methods);
@@ -327,7 +329,7 @@ public class ModelAdapterFactory impleme
 
         for (Method method : injectableMethods) {
             Type returnType = mapPrimitiveClasses(method.getGenericReturnType());
-            if (!injectFieldOrMethod(method, adaptable, returnType, registry, callback)) {
+            if (!injectFieldOrMethod(method, adaptable, returnType, modelAnnotation, registry, callback)) {
                 requiredMethods.add(method);
             }
         }
@@ -379,7 +381,7 @@ public class ModelAdapterFactory impleme
     }
 
     @SuppressWarnings("unchecked")
-    private <AdapterType> AdapterType createObject(Object adaptable, Class<AdapterType> type)
+    private <AdapterType> AdapterType createObject(Object adaptable, Class<AdapterType> type, Model modelAnnotation)
             throws InstantiationException, InvocationTargetException, IllegalAccessException {
         Set<Field> injectableFields = collectInjectableFields(type);
 
@@ -431,7 +433,7 @@ public class ModelAdapterFactory impleme
 
         for (Field field : injectableFields) {
             Type fieldType = mapPrimitiveClasses(field.getGenericType());
-            if (!injectFieldOrMethod(field, adaptable, fieldType, registry, callback)) {
+            if (!injectFieldOrMethod(field, adaptable, fieldType, modelAnnotation, registry, callback)) {
                 requiredFields.add(field);
             }
         }
@@ -451,14 +453,19 @@ public class ModelAdapterFactory impleme
 
     }
 
-    private boolean isOptional(AnnotatedElement point, InjectAnnotationProcessor annotationProcessor) {
+    private boolean isOptional(AnnotatedElement point, Model modelAnnotation, InjectAnnotationProcessor annotationProcessor) {
         if (annotationProcessor != null) {
             Boolean isOptional = annotationProcessor.isOptional();
             if (isOptional != null) {
                 return isOptional.booleanValue();
             }
         }
-        return (point.getAnnotation(Optional.class) != null);
+        if (modelAnnotation.defaultInjectionStrategy() == DefaultInjectionStrategy.REQUIRED) {
+            return (point.getAnnotation(Optional.class) != null);
+        } else {
+            return (point.getAnnotation(Required.class) == null);
+        }
+        
     }
 
     private boolean injectDefaultValue(AnnotatedElement point, Type type, InjectAnnotationProcessor processor,

Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java?rev=1605150&r1=1605149&r2=1605150&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java Tue Jun 24 18:37:50 2014
@@ -37,6 +37,7 @@ import org.apache.sling.models.testmodel
 import org.apache.sling.models.testmodels.classes.ChildValueMapModel;
 import org.apache.sling.models.testmodels.classes.ParentModel;
 import org.apache.sling.models.testmodels.classes.ResourceModelWithRequiredField;
+import org.apache.sling.models.testmodels.classes.ResourceModelWithRequiredFieldOptionalStrategy;
 import org.apache.sling.models.testmodels.classes.SimplePropertyModel;
 import org.junit.Before;
 import org.junit.Test;
@@ -156,6 +157,39 @@ public class ResourceModelClassesTest {
     }
 
     @Test
+    public void testRequiredPropertyModelOptionalStrategyAvailable() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("first", "first-value");
+        map.put("third", "third-value");
+        ValueMap vm = spy(new ValueMapDecorator(map));
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        ResourceModelWithRequiredFieldOptionalStrategy model = factory.getAdapter(res, ResourceModelWithRequiredFieldOptionalStrategy.class);
+        assertNull(model);
+
+        verify(vm).get("optional", String.class);
+        verify(vm).get("required", String.class);
+    }
+
+    @Test
+    public void testRequiredPropertyModelOptionalStrategyNotAvailable() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("required", "first-value");
+        ValueMap vm = spy(new ValueMapDecorator(map));
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        ResourceModelWithRequiredFieldOptionalStrategy model = factory.getAdapter(res, ResourceModelWithRequiredFieldOptionalStrategy.class);
+        assertNotNull(model);
+
+        verify(vm).get("optional", String.class);
+        verify(vm).get("required", String.class);
+    }
+
+    @Test
     public void testChildResource() {
         Resource child = mock(Resource.class);
         Resource secondChild = mock(Resource.class);

Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java?rev=1605150&r1=1605149&r2=1605150&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java Tue Jun 24 18:37:50 2014
@@ -23,10 +23,10 @@ import org.apache.sling.models.annotatio
 
 @Model(adaptables = Resource.class)
 public class ResourceModelWithRequiredField {
-    
+
     @Inject
     private String required;
-    
+
     public String getRequired() {
         return required;
     }

Copied: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredFieldOptionalStrategy.java (from r1605101, sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java)
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredFieldOptionalStrategy.java?p2=sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredFieldOptionalStrategy.java&p1=sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java&r1=1605101&r2=1605150&rev=1605150&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredFieldOptionalStrategy.java Tue Jun 24 18:37:50 2014
@@ -19,16 +19,26 @@ package org.apache.sling.models.testmode
 import javax.inject.Inject;
 
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.DefaultInjectionStrategy;
 import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Required;
+
+@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
+public class ResourceModelWithRequiredFieldOptionalStrategy {
+
+    @Inject
+    private String optional;
 
-@Model(adaptables = Resource.class)
-public class ResourceModelWithRequiredField {
-    
     @Inject
+    @Required
     private String required;
-    
+
     public String getRequired() {
         return required;
     }
 
+    public String getOptional() {
+        return optional;
+    }
+
 }