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:30 UTC

[sling-org-apache-sling-models-impl] annotated tag org.apache.sling.models.impl-1.1.0 created (now d49b3c3)

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

rombert pushed a change 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.


      at d49b3c3  (tag)
 tagging f0c3f772108762de213b71de3bda6f59152985b1 (commit)
      by Justin Edelson
      on Tue Sep 2 19:14:45 2014 +0000

- Log -----------------------------------------------------------------
org.apache.sling.models.impl-1.1.0
-----------------------------------------------------------------------

This annotated tag includes the following new commits:

     new 58786a9  SLING-3313 - adding initial version of Sling Models (nee YAMF)
     new 45be0c6  set svn:ignore
     new d407d6f  SLING-3313 - actually use the seal() method to make the disposal callback list unmodifiable
     new 40ea6f5  SLING-3335 - add a models configuration printer to see the currently registered injectors
     new ae43b9e  SLING-3334 - explicitly rank injectors
     new e9a5ebd  SLING-3357 - allow a model class to have a single argument constructor which takes the adaptable as a parameter.
     new d193760  using release version
     new fe08a96  avoid the use of Integer.compare()
     new 5f168bc  [maven-release-plugin] prepare release org.apache.sling.models.impl-1.0.0
     new d951930  [maven-release-plugin] prepare for next development iteration
     new 41e7e3c  Using 1.0.0 breaks the build, reverting to SNAPSHOT, we might change back to 1.0.0 once it's out
     new 53a6c31  SLING-3429 - fix NPE in OSGiServiceInjector which impacted multi-valued properties
     new 3fda5d4  SLING-3430 - only embedding necessary parts of beanutils
     new 9fb2350  SLING-3340 - reverting change to restrict inclusion of beanutils. error prone.
     new 6d238d2  no need to depend upon SNAPSHOT version of API
     new 64ef324  adding test for array properties
     new f9c6619  SLING-3455 - fixing issue with injection adaption in classes
     new 392c1c6  [maven-release-plugin] prepare release org.apache.sling.models.impl-1.0.2
     new 8fa875f  [maven-release-plugin] prepare for next development iteration
     new 53b4d54  SLING-3460 - internal refactoring to ease meta-annotation support
     new 234cb27  Update to parent pom v19
     new 4597b97  SLING-3510 - checking for bad package, either one which doesn't exist or doesn't have classes in it. Thanks Chris Pilsworth for the patch!
     new a3ad23d  SLING-3536 - on each interval for callback disposal, continue to poll until all queue is exhausted.
     new 59464a2  fixing bad url
     new 6a281d3  [maven-release-plugin] prepare release org.apache.sling.models.impl-1.0.4
     new 6b7fdc5  [maven-release-plugin] prepare for next development iteration
     new 063b5d2  SLING-3547 - correctly dealing with primitive and wrapper default objects. applying slightly modified version of patch from Konrad to split out primitive from wrapper model classes.
     new 50eb3e2  unit test improvements
     new 189f1d3  SLING-3499 - adding support for custom annotation per injector (thanks Konrad Windszus for the patch!)
     new 7addafa  cleanup
     new 4fd9d71  SLING-3674 - automatically wrapping/unwrapping arrays where possible during value map injection
     new f6d3d61  SLING-3674 - avoiding duplicating code in ClassUtils
     new 0df8a43  SLING-3516 - adding ability to inject a list of grandchild resources. Thanks to Igor Sechyn for the initial patch!
     new a91e250  SLING-3683 - breaking apart annotation processor factory selection from injector selection
     new 4188a71  trivial formatting
     new 3ea34c4  SLING-3696 - adding support for defining a default injection strategy of required or optional. Also adding a @Required annotation
     new e95b122  SLING-3677 - converting arrays to lists in ValueMapInjector. Thanks to Krystian Panek for the patch!
     new 5d87969  SLING-3700 - adding a ResourceResolver injector
     new 43ca65f  using released version of API
     new ba6409f  [maven-release-plugin] prepare release org.apache.sling.models.impl-1.0.6
     new 8158a27  [maven-release-plugin] prepare for next development iteration
     new 71a5632  using next version during release
     new 60a094f  SLING-3703 - referencing older version of commons osgi
     new 4154731  Updated to parent version 20
     new 76f3fae  SLING-3716 SLING-3718 - adding support for constructor injection and self injection based on a patch from Stefan Seifert
     new 5060375  SLING-3861 - adding condition option for @Model annotation
     new ec0e0a1  SLING-3863 - adding initial values for primitives when injecting to fields and constructor params. Thanks to Stefan Seifert for the original patch!
     new fd0324d  SLING-3863 - correcting behavior where optional methods and constructor parameters were injected with non-null wrapper classes.
     new 9c6fb1e  SLING-3869 - fixing branding issues with Sling Models. Thanks to Stefan Seifert for the patch!
     new ad90196  fixing error in Sling Models test code - service ranking must be an integer to be effective
     new 025b2ae  SLING-3876 - ensuring that class-based self injection only happens on the first constructor parameter. Otherwise the @Self annotation is necessary. Also changing the ranking so that other injectors have the opportunity to inject to the first constructor parameter before.
     new a6b32c1  SLING-3877 - adding a resource path injector. also did some minor refactoring to avoid code duplication between injectors.
     new 895766f  SLING-3860 - allowing maximum recursion depth to be configured
     new 035d660  SLING-3878 - allowing the injection of parameterized request attributes
     new ead97d0  SLING-3715 - adding sling object injector. Thanks to Stefan for the patch!
     new b5304a4  SLING-3879 - fixing NPE in PathInjector. Thanks Stefan for the patch!
     new 3041e79  SLING-3894 - removing duplicate type checks in Request and SlingBindings injectors
     new 9a66a4b  SLING-3895 - supporting list adaptation for method and constructor injection
     new 8fd239e  SLING-3897 - fixing copy&paste error in unbind method. Thanks to Stefan for the patch!
     new db87d40  SLING-3897 - fixing synchronization block error
     new d387900  SLING-3886 - adding support for adapter indirection where the adapting target is a superclass or implemented interface of the implementation class. Thanks to Stefan for the patch!
     new f3b034c  release prep
     new 2f179b1  [maven-release-plugin] prepare release org.apache.sling.models.impl-1.1.0
     new f0c3f77  [maven-release-plugin]  copy for tag org.apache.sling.models.impl-1.1.0

The 64 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


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

[sling-org-apache-sling-models-impl] 14/24: SLING-3878 - allowing the injection of parameterized request attributes

Posted by ro...@apache.org.
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 035d6602769f6320f37578e2323b4f44a091dcae
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Sun Aug 24 12:41:58 2014 +0000

    SLING-3878 - allowing the injection of parameterized request attributes
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1620132 13f79535-47bb-0310-9956-ffa450edef68
---
 .../impl/injectors/RequestAttributeInjector.java   | 31 ++++++--
 .../ParameterizedTypeFromRequestAttributeTest.java | 87 ++++++++++++++++++++++
 2 files changed, 110 insertions(+), 8 deletions(-)

diff --git a/src/main/java/org/apache/sling/models/impl/injectors/RequestAttributeInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/RequestAttributeInjector.java
index 23c3907..081bcbf 100644
--- a/src/main/java/org/apache/sling/models/impl/injectors/RequestAttributeInjector.java
+++ b/src/main/java/org/apache/sling/models/impl/injectors/RequestAttributeInjector.java
@@ -17,6 +17,7 @@
 package org.apache.sling.models.impl.injectors;
 
 import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 
 import javax.servlet.ServletRequest;
@@ -51,16 +52,30 @@ public class RequestAttributeInjector implements Injector, InjectAnnotationProce
             DisposalCallbackRegistry callbackRegistry) {
         if (!(adaptable instanceof ServletRequest)) {
             return null;
-        } else if (declaredType instanceof Class<?>) {
-            Class<?> clazz = (Class<?>) declaredType;
+        } else {
             Object attribute = ((ServletRequest) adaptable).getAttribute(name);
-            if (clazz.isInstance(attribute)) {
-                return attribute;
-            } else {
-                return null;
+            if (attribute != null) {
+                if (declaredType instanceof Class<?>) {
+                    Class<?> clazz = (Class<?>) declaredType;
+                    if (clazz.isInstance(attribute)) {
+                        return attribute;
+                    } else {
+                        return null;
+                    }
+                } else if (declaredType instanceof ParameterizedType) {
+                    ParameterizedType parameterizedType = (ParameterizedType) declaredType;
+                    Type rawType = parameterizedType.getRawType();
+                    if (rawType instanceof Class<?>) {
+                        Class<?> clazz = (Class<?>) rawType;
+                        if (clazz.isInstance(attribute)) {
+                            return attribute;
+                        } else {
+                            return null;
+                        }
+                    }
+                }
+                log.debug("RequestAttributeInjector doesn't support type {}, type class {}.", declaredType, declaredType.getClass());
             }
-        } else {
-            log.debug("BindingsInjector doesn't support non-class type {}", declaredType);
             return null;
         }
     }
diff --git a/src/test/java/org/apache/sling/models/impl/ParameterizedTypeFromRequestAttributeTest.java b/src/test/java/org/apache/sling/models/impl/ParameterizedTypeFromRequestAttributeTest.java
new file mode 100644
index 0000000..3c9240a
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ParameterizedTypeFromRequestAttributeTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
+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;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ParameterizedTypeFromRequestAttributeTest {
+    private ModelAdapterFactory factory;
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    @Mock
+    private SlingHttpServletRequest request;
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+
+        RequestAttributeInjector injector = new RequestAttributeInjector();
+        factory.bindInjector(injector, new ServicePropertiesMap(1, 1));
+    }
+
+    @Test
+    public void test() {
+        Iterator<Resource> it = Collections.<Resource> emptySet().iterator();
+
+        when(request.getAttribute("someResources")).thenReturn(it);
+        TestModel model = factory.getAdapter(request, TestModel.class);
+        assertNotNull(model);
+        assertEquals(it, model.getSomeResources());
+    }
+
+    @Model(adaptables = SlingHttpServletRequest.class)
+    public static class TestModel {
+
+        @Inject
+        private Iterator<Resource> someResources;
+
+        public Iterator<Resource> getSomeResources() {
+            return someResources;
+        }
+    }
+}

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

[sling-org-apache-sling-models-impl] 01/24: [maven-release-plugin] prepare for next development iteration

Posted by ro...@apache.org.
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 8158a277f3142b2b3ca9e951e9217bc7be9468d7
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Wed Jun 25 15:56:11 2014 +0000

    [maven-release-plugin] prepare for next development iteration
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1605462 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index ecf02ca..5e7b1fc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,16 +28,16 @@
     <groupId>org.apache.sling</groupId>
     <artifactId>org.apache.sling.models.impl</artifactId>
     <packaging>bundle</packaging>
-    <version>1.0.6</version>
+    <version>1.0.7-SNAPSHOT</version>
     <name>Sling Models Implementation</name>
     <description>Sling Models Implementation</description>
     <properties>
         <sling.java.version>6</sling.java.version>
     </properties>
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.models.impl-1.0.6</connection>
-        <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.models.impl-1.0.6</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.models.impl-1.0.6</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl</connection>
+        <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl</url>
     </scm>
     <build>
         <plugins>

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

[sling-org-apache-sling-models-impl] 05/24: SLING-3716 SLING-3718 - adding support for constructor injection and self injection based on a patch from Stefan Seifert

Posted by ro...@apache.org.
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 76f3fae7933d72c0cbb4cd8f9e96b0c681dd94c0
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Tue Aug 19 22:51:36 2014 +0000

    SLING-3716 SLING-3718 - adding support for constructor injection and self injection based on a patch from Stefan Seifert
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1619007 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |   2 +-
 .../sling/models/impl/ConstructorParameter.java    |  87 ++++++
 .../models/impl/MapBackedInvocationHandler.java    |  37 +++
 .../sling/models/impl/ModelAdapterFactory.java     | 304 ++++++++++++++-------
 .../impl/ParameterCountInjectComparator.java       |  63 +++++
 .../models/impl/injectors/OSGiServiceInjector.java |   3 +-
 .../sling/models/impl/injectors/SelfInjector.java  |  87 ++++++
 .../apache/sling/models/impl/ConstructorTest.java  |  39 ++-
 .../org/apache/sling/models/impl/DefaultTest.java  |  62 ++++-
 .../impl/InjectorSpecificAnnotationTest.java       | 106 ++++++-
 .../sling/models/impl/OSGiInjectionTest.java       |  62 ++++-
 .../sling/models/impl/RequestInjectionTest.java    |  11 +-
 .../sling/models/impl/SelfDependencyTest.java      |  95 +++++++
 .../impl/injectors/BindingsInjectorTest.java       |  98 +++++++
 .../injectors/RequestAttributeInjectorTest.java    |  86 ++++++
 .../models/impl/injectors/SelfInjectorTest.java    |  86 ++++++
 .../impl/injectors/ValueMapInjectorTest.java       |  86 ++++++
 .../classes/DirectCyclicSelfDependencyModel.java   |  36 +++
 .../IndirectCyclicSelfDependencyModelA.java        |  36 +++
 .../IndirectCyclicSelfDependencyModelB.java        |  36 +++
 .../testmodels/classes/SelfDependencyModelA.java   |  36 +++
 .../testmodels/classes/SelfDependencyModelB.java   |  36 +++
 .../constructorinjection/BindingsModel.java        |  41 +++
 .../DefaultPrimitivesModel.java                    |  62 +++++
 .../constructorinjection/DefaultStringModel.java   |  48 ++++
 .../constructorinjection/DefaultWrappersModel.java |  63 +++++
 .../InjectorSpecificAnnotationModel.java           |  91 ++++++
 .../constructorinjection/ListOSGiModel.java        |  42 +++
 .../classes/constructorinjection/NoNameModel.java  |  42 +++
 .../constructorinjection/SimpleOSGiModel.java      |  40 +++
 .../WithThreeConstructorsOneInjectModel.java       |  59 ++++
 31 files changed, 1850 insertions(+), 132 deletions(-)

diff --git a/pom.xml b/pom.xml
index 94c9d3c..426fb1d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,7 +63,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.models.api</artifactId>
-            <version>1.0.2</version>
+            <version>1.0.3-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java b/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java
new file mode 100644
index 0000000..eab70ae
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java
@@ -0,0 +1,87 @@
+/*
+ * 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.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+
+/**
+ * Constructor parameters aren't normally accessible using the
+ * AnnotatedElement. This class acts as a facade to ease
+ * compatibility with field and method injection.
+ */
+class ConstructorParameter implements AnnotatedElement {
+
+    private final Annotation[] annotations;
+    private final Class<?> type;
+    private final Type genericType;
+    private final int parameterIndex;
+
+    ConstructorParameter(Annotation[] annotations, Class<?> type, Type genericType, int parameterIndex) {
+        this.annotations = annotations;
+        this.type = type;
+        this.genericType = genericType;
+        this.parameterIndex = parameterIndex;
+    }
+
+    @Override
+    public boolean isAnnotationPresent(Class<? extends Annotation> paramClass) {
+        return getAnnotation(paramClass) != null;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> paramClass) {
+        for (Annotation annotation : this.annotations) {
+            if (paramClass.isInstance(annotation)) {
+                return (T)annotation;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Annotation[] getAnnotations() {
+        return annotations;
+    }
+
+    @Override
+    public Annotation[] getDeclaredAnnotations() {
+        return annotations;
+    }
+
+    public Class<?> getType() {
+        return this.type;
+    }
+
+    public Type getGenericType() {
+        return this.genericType;
+    }
+
+    public int getParameterIndex() {
+        return this.parameterIndex;
+    }
+    
+    @Override
+    public String toString() {
+        return "Parameter" + this.parameterIndex + "[" + this.genericType.toString() + "]";
+    }
+    
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/models/impl/MapBackedInvocationHandler.java b/src/main/java/org/apache/sling/models/impl/MapBackedInvocationHandler.java
new file mode 100644
index 0000000..c486781
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/MapBackedInvocationHandler.java
@@ -0,0 +1,37 @@
+/*
+ * 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.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+class MapBackedInvocationHandler implements InvocationHandler {
+
+    private Map<Method, Object> methods;
+
+    public MapBackedInvocationHandler(Map<Method, Object> methods) {
+        this.methods = methods;
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        return methods.get(method);
+    }
+
+}
\ No newline at end of file
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 8532de4..b77cce1 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -32,7 +32,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -69,6 +68,7 @@ import org.apache.sling.models.annotations.Source;
 import org.apache.sling.models.annotations.Via;
 import org.apache.sling.models.spi.DisposalCallback;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.AcceptsNullName;
 import org.apache.sling.models.spi.Injector;
 import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
 import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
@@ -83,23 +83,6 @@ import org.slf4j.LoggerFactory;
 @Component
 public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
-    /**
-     * Comparator which sorts constructors by the number of parameters
-     * in reverse order (most params to least params).
-     */
-    public class ParameterCountComparator implements Comparator<Constructor<?>> {
-
-        @Override
-        public int compare(Constructor<?> o1, Constructor<?> o2) {
-            return compare(o2.getParameterTypes().length, o1.getParameterTypes().length);
-        }
-
-        public int compare(int x, int y) {
-            return (x < y) ? -1 : ((x == y) ? 0 : 1);
-        }
-
-    }
-
     private static class DisposalCallbackRegistryImpl implements DisposalCallbackRegistry {
 
         private List<DisposalCallback> callbacks = new ArrayList<DisposalCallback>();
@@ -125,20 +108,6 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     private ConcurrentMap<java.lang.ref.Reference<Object>, DisposalCallbackRegistryImpl> disposalCallbacks;
 
-    private static class MapBackedInvocationHandler implements InvocationHandler {
-
-        private Map<Method, Object> methods;
-
-        public MapBackedInvocationHandler(Map<Method, Object> methods) {
-            this.methods = methods;
-        }
-
-        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-            return methods.get(method);
-        }
-
-    }
-
     @Override
     public void run() {
         java.lang.ref.Reference<? extends Object> ref = queue.poll();
@@ -169,39 +138,72 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
     private ServiceRegistration jobRegistration;
 
     private ServiceRegistration configPrinterRegistration;
+    
+    // Use threadlocal to count recursive invocations and break recursing if a max. limit is reached (to avoid cyclic dependencies)
+    private static final int MAX_RECURSIVE_INOVCATIONS = 20;
 
-    @SuppressWarnings("unchecked")
-    public <AdapterType> AdapterType getAdapter(Object adaptable, Class<AdapterType> type) {
-        Model modelAnnotation = type.getAnnotation(Model.class);
-        if (modelAnnotation == null) {
-            return null;
+    private static class ThreadInvocationCounter {
+        private int count;
+        public boolean isMaximumReached() {
+            return count >= MAX_RECURSIVE_INOVCATIONS;
         }
-        boolean isAdaptable = false;
-
-        Class<?>[] declaredAdaptable = modelAnnotation.adaptables();
-        for (Class<?> clazz : declaredAdaptable) {
-            if (clazz.isInstance(adaptable)) {
-                isAdaptable = true;
-            }
+        public void increase() {
+            this.count++;
         }
-        if (!isAdaptable) {
-            return null;
+        public void decrease() {
+            this.count--;
         }
+    }
 
-        if (type.isInterface()) {
-            InvocationHandler handler = createInvocationHandler(adaptable, type, modelAnnotation);
-            if (handler != null) {
-                return (AdapterType) Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[] { type }, handler);
-            } else {
+    private static final ThreadLocal<ThreadInvocationCounter> INVOCATION_COUNT_THREADLOCAL = new ThreadLocal<ModelAdapterFactory.ThreadInvocationCounter>() {
+        @Override
+        protected ThreadInvocationCounter initialValue() {
+            return new ThreadInvocationCounter();
+        }
+    };
+
+    @SuppressWarnings("unchecked")
+    public <AdapterType> AdapterType getAdapter(Object adaptable, Class<AdapterType> type) {
+        if (INVOCATION_COUNT_THREADLOCAL.get().isMaximumReached()) {
+            log.error("Adapting {} to {} failed, too much recursive invocations (>={}).",
+                    new Object[] { adaptable, type, MAX_RECURSIVE_INOVCATIONS });
+            return null;
+        };
+        INVOCATION_COUNT_THREADLOCAL.get().increase();
+        try {
+            Model modelAnnotation = type.getAnnotation(Model.class);
+            if (modelAnnotation == null) {
                 return null;
             }
-        } else {
-            try {
-                return createObject(adaptable, type, modelAnnotation);
-            } catch (Exception e) {
-                log.error("unable to create object", e);
+            boolean isAdaptable = false;
+
+            Class<?>[] declaredAdaptable = modelAnnotation.adaptables();
+            for (Class<?> clazz : declaredAdaptable) {
+                if (clazz.isInstance(adaptable)) {
+                    isAdaptable = true;
+                }
+            }
+            if (!isAdaptable) {
                 return null;
             }
+
+            if (type.isInterface()) {
+                InvocationHandler handler = createInvocationHandler(adaptable, type, modelAnnotation);
+                if (handler != null) {
+                    return (AdapterType) Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[] { type }, handler);
+                } else {
+                    return null;
+                }
+            } else {
+                try {
+                    return createObject(adaptable, type, modelAnnotation);
+                } catch (Exception e) {
+                    log.error("unable to create object", e);
+                    return null;
+                }
+            }
+        } finally {
+            INVOCATION_COUNT_THREADLOCAL.get().decrease();
         }
     }
 
@@ -276,14 +278,28 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
             return setMethod((Method) element, methods, value);
         }
     }
+    
+    private static class SetConstructorParameterCallback implements InjectCallback {
+
+        private final List<Object> parameterValues;
 
-    private boolean injectFieldOrMethod(final AnnotatedElement element, final Object adaptable, final Type type,
+        private SetConstructorParameterCallback(List<Object> parameterValues) {
+            this.parameterValues = parameterValues;
+        }
+
+        @Override
+        public boolean inject(AnnotatedElement element, Object value) {
+            return setConstructorParameter((ConstructorParameter)element, parameterValues, value);
+        }
+    }
+
+    private boolean injectElement(final AnnotatedElement element, final Object adaptable, final Type type,
             final Model modelAnnotation, final DisposalCallbackRegistry registry, InjectCallback callback) {
 
         InjectAnnotationProcessor annotationProcessor = null;
         String source = getSource(element);
         boolean wasInjectionSuccessful = false;
-        
+
         // find an appropriate annotation processor
         for (InjectAnnotationProcessorFactory factory : sortedInjectAnnotationProcessorFactories) {
             annotationProcessor = factory.createAnnotationProcessor(adaptable, element);
@@ -292,16 +308,19 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
             }
         }
 
+        String name = getName(element, annotationProcessor);
+        Object injectionAdaptable = getAdaptable(adaptable, element, annotationProcessor);
+
         // find the right injector
         for (Injector injector : sortedInjectors) {
             if (source == null || source.equals(injector.getName())) {
-                String name = getName(element, annotationProcessor);
-                Object injectionAdaptable = getAdaptable(adaptable, element, annotationProcessor);
-                if (injectionAdaptable != null) {
-                    Object value = injector.getValue(injectionAdaptable, name, type, element, registry);
-                    if (callback.inject(element, value)) {
-                        wasInjectionSuccessful = true;
-                        break;
+                if (name != null || injector instanceof AcceptsNullName) {
+                    if (injectionAdaptable != null) {
+                        Object value = injector.getValue(injectionAdaptable, name, type, element, registry);
+                        if (callback.inject(element, value)) {
+                            wasInjectionSuccessful = true;
+                            break;
+                        }
                     }
                 }
             }
@@ -324,12 +343,13 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         SetMethodsCallback callback = new SetMethodsCallback(methods);
         MapBackedInvocationHandler handler = new MapBackedInvocationHandler(methods);
 
-        DisposalCallbackRegistryImpl registry = createAndRegisterCallbackRegistry(handler);
+        DisposalCallbackRegistryImpl registry = new DisposalCallbackRegistryImpl();
+        registerCallbackRegistry(handler, registry);
         Set<Method> requiredMethods = new HashSet<Method>();
 
         for (Method method : injectableMethods) {
             Type returnType = mapPrimitiveClasses(method.getGenericReturnType());
-            if (!injectFieldOrMethod(method, adaptable, returnType, modelAnnotation, registry, callback)) {
+            if (!injectElement(method, adaptable, returnType, modelAnnotation, registry, callback)) {
                 requiredMethods.add(method);
             }
         }
@@ -341,11 +361,9 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         return handler;
     }
 
-    private DisposalCallbackRegistryImpl createAndRegisterCallbackRegistry(Object object) {
+    private void registerCallbackRegistry(Object object, DisposalCallbackRegistryImpl registry) {
         PhantomReference<Object> reference = new PhantomReference<Object>(object, queue);
-        DisposalCallbackRegistryImpl registry = new DisposalCallbackRegistryImpl();
         disposalCallbacks.put(reference, registry);
-        return registry;
     }
 
     private String getSource(AnnotatedElement element) {
@@ -380,60 +398,52 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         return null;
     }
 
-    @SuppressWarnings("unchecked")
     private <AdapterType> AdapterType createObject(Object adaptable, Class<AdapterType> type, Model modelAnnotation)
             throws InstantiationException, InvocationTargetException, IllegalAccessException {
-        Set<Field> injectableFields = collectInjectableFields(type);
+        DisposalCallbackRegistryImpl registry = new DisposalCallbackRegistryImpl();
 
-        Constructor<?>[] constructors = type.getConstructors();
-        if (constructors.length == 0) {
-            log.warn("Model class {} does not have a public constructor.", type.getName());
+        Constructor<AdapterType> constructorToUse = getBestMatchingConstructor(adaptable, type);
+        if (constructorToUse == null) {
+            log.warn("Model class {} does not have a usable constructor", type.getName());
             return null;
         }
 
-        // sort the constructor list in order from most params to least params
-        Arrays.sort(constructors, new ParameterCountComparator());
-
-        Constructor<AdapterType> constructorToUse = null;
-        boolean constructorHasParam = false;
-        for (Constructor<?> constructor : constructors) {
-            final Class<?>[] paramTypes = constructor.getParameterTypes();
-            if (paramTypes.length == 1) {
-                Class<?> paramType = constructor.getParameterTypes()[0];
-                if (paramType.isInstance(adaptable)) {
-                    constructorToUse = (Constructor<AdapterType>) constructor;
-                    constructorHasParam = true;
-                    break;
-                }
-            }
-
-            if (constructor.getParameterTypes().length == 0) {
-                constructorToUse = (Constructor<AdapterType>) constructor;
-                constructorHasParam = false;
-                break;
+        final AdapterType object;
+        if (constructorToUse.getParameterTypes().length == 0) {
+            // no parameters for constructor injection? instantiate it right away
+            object = constructorToUse.newInstance();
+        } else {
+            // instantiate with constructor injection
+            // if this fails, make sure resources that may be claimed by injectors are cleared up again
+            try {
+                object = newInstanceWithConstructorInjection(constructorToUse, adaptable, type, modelAnnotation, registry);
+            } catch (InstantiationException ex) {
+                registry.onDisposed();
+                throw ex;
+            } catch (InvocationTargetException ex) {
+                registry.onDisposed();
+                throw ex;
+            } catch (IllegalAccessException ex) {
+                registry.onDisposed();
+                throw ex;
             }
         }
 
-        if (constructorToUse == null) {
-            log.warn("Model class {} does not have a usable constructor", type.getName());
+        if (object == null) {
+            registry.onDisposed();
             return null;
         }
 
-        final AdapterType object;
-        if (constructorHasParam) {
-            object = constructorToUse.newInstance(adaptable);
-        } else {
-            object = constructorToUse.newInstance();
-        }
-        InjectCallback callback = new SetFieldCallback(object);
+        registerCallbackRegistry(object, registry);
 
-        DisposalCallbackRegistryImpl registry = createAndRegisterCallbackRegistry(object);
+        InjectCallback callback = new SetFieldCallback(object);
 
         Set<Field> requiredFields = new HashSet<Field>();
 
+        Set<Field> injectableFields = collectInjectableFields(type);
         for (Field field : injectableFields) {
             Type fieldType = mapPrimitiveClasses(field.getGenericType());
-            if (!injectFieldOrMethod(field, adaptable, fieldType, modelAnnotation, registry, callback)) {
+            if (!injectElement(field, adaptable, fieldType, modelAnnotation, registry, callback)) {
                 requiredFields.add(field);
             }
         }
@@ -453,6 +463,64 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     }
 
+    /**
+     * Gets best matching constructor for constructor injection - or default constructor if none is found.
+     * @param adaptable Adaptable instance
+     * @param type Model type
+     * @return Constructor or null if none found
+     */
+    @SuppressWarnings("unchecked")
+    private <AdapterType> Constructor<AdapterType> getBestMatchingConstructor(Object adaptable, Class<AdapterType> type) {
+        Constructor<?>[] constructors = type.getConstructors();
+
+        // sort the constructor list in order from most params to least params, and constructors with @Inject annotation first
+        Arrays.sort(constructors, new ParameterCountInjectComparator());
+
+        for (Constructor<?> constructor : constructors) {
+            // first try to find the constructor with most parameters and @Inject annotation
+            if (constructor.isAnnotationPresent(Inject.class)) {
+                return (Constructor<AdapterType>) constructor;
+            }
+            // compatibility mode for sling models implementation <= 1.0.6:
+            // support constructor without @Inject if it has exactly one parameter matching the adaptable class
+            final Class<?>[] paramTypes = constructor.getParameterTypes();
+            if (paramTypes.length == 1) {
+                Class<?> paramType = constructor.getParameterTypes()[0];
+                if (paramType.isInstance(adaptable)) {
+                    return (Constructor<AdapterType>) constructor;
+                }
+            }
+            // if no constructor for injection found use public constructor without any params
+            if (constructor.getParameterTypes().length == 0) {
+                return (Constructor<AdapterType>) constructor;
+            }
+        }
+        return null;
+    }
+
+    private <AdapterType> AdapterType newInstanceWithConstructorInjection(Constructor<AdapterType> constructor, Object adaptable,
+            Class<AdapterType> type, Model modelAnnotation, DisposalCallbackRegistry registry)
+            throws InstantiationException, InvocationTargetException, IllegalAccessException {
+        Set<ConstructorParameter> requiredParameters = new HashSet<ConstructorParameter>();
+        Type[] parameterTypes = constructor.getGenericParameterTypes();
+        List<Object> paramValues = new ArrayList<Object>(Arrays.asList(new Object[parameterTypes.length]));
+        InjectCallback callback = new SetConstructorParameterCallback(paramValues);
+
+        for (int i = 0; i < parameterTypes.length; i++) {
+            Type genericType = mapPrimitiveClasses(parameterTypes[i]);
+            ConstructorParameter constructorParameter = new ConstructorParameter(
+                    constructor.getParameterAnnotations()[i], constructor.getParameterTypes()[i], genericType, i);
+            if (!injectElement(constructorParameter, adaptable, genericType, modelAnnotation, registry, callback)) {
+                requiredParameters.add(constructorParameter);
+            }
+        }
+        if (!requiredParameters.isEmpty()) {
+            log.warn("Required constructor parameters {} on model class {} were not able to be injected.", requiredParameters, type);
+            return null;
+        }
+        return constructor.newInstance(paramValues.toArray(new Object[paramValues.size()]));
+    }
+
     private boolean isOptional(AnnotatedElement point, Model modelAnnotation, InjectAnnotationProcessor annotationProcessor) {
         if (annotationProcessor != null) {
             Boolean isOptional = annotationProcessor.isOptional();
@@ -582,6 +650,9 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
             return getNameFromMethod((Method) element);
         } else if (element instanceof Field) {
             return getNameFromField((Field) element);
+        } else if (element instanceof ConstructorParameter) {
+            // implicit name not supported for constructor parameters - but do not throw exception because class-based injection is still possible
+            return null;
         } else {
             throw new IllegalArgumentException("The given element must be either method or field but is " + element);
         }
@@ -702,6 +773,27 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         }
     }
 
+    private static boolean setConstructorParameter(ConstructorParameter constructorParameter, List<Object> parameterValues, Object value) {
+        if (value != null && constructorParameter.getType() instanceof Class<?>) {
+            Class<?> requestedType = (Class<?>)constructorParameter.getType();
+            if (!isAcceptableType(requestedType, constructorParameter.getGenericType(), value)) {
+                if (value instanceof Adaptable) {
+                    value = ((Adaptable) value).adaptTo(requestedType);
+                    if (value == null) {
+                        return false;
+                    }
+                }
+                else {
+                    return false;
+                }
+            }
+            parameterValues.set(constructorParameter.getParameterIndex(), value);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     private static boolean isAcceptableType(Class<?> type, Type genericType, Object value) {
         if (type.isInstance(value)) {
             if ((type == Collection.class || type == List.class) && genericType instanceof ParameterizedType &&
diff --git a/src/main/java/org/apache/sling/models/impl/ParameterCountInjectComparator.java b/src/main/java/org/apache/sling/models/impl/ParameterCountInjectComparator.java
new file mode 100644
index 0000000..afb8410
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/ParameterCountInjectComparator.java
@@ -0,0 +1,63 @@
+/*
+ * 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.lang.reflect.Constructor;
+import java.util.Comparator;
+
+import javax.inject.Inject;
+
+/**
+ * Comparator which sorts constructors by the number of parameters
+ * in reverse order (most params to least params).
+ * If two constructors have the same number of parameters constructors with
+ * @Inject annotation are sorted first.
+ */
+class ParameterCountInjectComparator implements Comparator<Constructor<?>> {
+
+    @Override
+    public int compare(Constructor<?> o1, Constructor<?> o2) {
+        int result = compareParameterCount(o2.getParameterTypes().length, o1.getParameterTypes().length);
+        if (result==0) {
+            return compareInjectAnnotation(o1, o2);
+        }
+        else {
+            return result;
+        }
+    }
+
+    private int compareParameterCount(int x, int y) {
+        return (x < y) ? -1 : ((x == y) ? 0 : 1);
+    }
+
+    private int compareInjectAnnotation(Constructor<?> o1, Constructor<?> o2) {
+        boolean hasInject1 = o1.isAnnotationPresent(Inject.class);
+        boolean hasInject2 = o2.isAnnotationPresent(Inject.class);
+        if (hasInject1 && !hasInject2) {
+            return -1;
+        }
+        else if (hasInject2 && !hasInject1) {
+            return 1;
+        }
+        else {
+            return 0;
+        }
+    }
+    
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java
index fb85dc0..0d1b4e8 100644
--- a/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java
+++ b/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java
@@ -38,6 +38,7 @@ import org.apache.sling.models.annotations.Filter;
 import org.apache.sling.models.annotations.injectorspecific.OSGiService;
 import org.apache.sling.models.spi.DisposalCallback;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.AcceptsNullName;
 import org.apache.sling.models.spi.Injector;
 import org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor;
 import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
@@ -53,7 +54,7 @@ import org.slf4j.LoggerFactory;
 @Component
 @Service
 @Property(name = Constants.SERVICE_RANKING, intValue = 5000)
-public class OSGiServiceInjector implements Injector, InjectAnnotationProcessorFactory {
+public class OSGiServiceInjector implements Injector, InjectAnnotationProcessorFactory, AcceptsNullName {
 
     private static final Logger log = LoggerFactory.getLogger(OSGiServiceInjector.class);
 
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java
new file mode 100644
index 0000000..5787b46
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java
@@ -0,0 +1,87 @@
+/*
+ * 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.injectors;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.AcceptsNullName;
+import org.apache.sling.models.spi.Injector;
+import org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory;
+import org.osgi.framework.Constants;
+
+/**
+ * Injects the adaptable object itself.
+ */
+@Component
+@Service
+@Property(name = Constants.SERVICE_RANKING, intValue = 100)
+public class SelfInjector implements Injector, InjectAnnotationProcessorFactory, AcceptsNullName {
+
+    @Override
+    public String getName() {
+        return "self";
+    }
+
+    public Object getValue(Object adaptable, String name, Type type, AnnotatedElement element,
+            DisposalCallbackRegistry callbackRegistry) {
+        // if the @Self annotation is present return the adaptable to be inserted directly or to be adapted from
+        if (element.isAnnotationPresent(Self.class)) {
+            return adaptable;
+        }
+        // otherwise apply class-based injection only if class matches or is a superclass
+        else if (type instanceof Class<?>) {
+            Class<?> requestedClass = (Class<?>)type;
+            if (requestedClass.isAssignableFrom(adaptable.getClass())) {
+                return adaptable;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public InjectAnnotationProcessor createAnnotationProcessor(Object adaptable, AnnotatedElement element) {
+        // check if the element has the expected annotation
+        Self annotation = element.getAnnotation(Self.class);
+        if (annotation != null) {
+            return new SelfAnnotationProcessor(annotation);
+        }
+        return null;
+    }
+
+    private static class SelfAnnotationProcessor extends AbstractInjectAnnotationProcessor {
+
+        private final Self annotation;
+
+        public SelfAnnotationProcessor(Self annotation) {
+            this.annotation = annotation;
+        }
+
+        @Override
+        public Boolean isOptional() {
+            return annotation.optional();
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/ConstructorTest.java b/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
index 0f3da57..6720a16 100644
--- a/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
@@ -21,11 +21,14 @@ import static org.mockito.Mockito.*;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
+import org.apache.sling.models.impl.injectors.SelfInjector;
 import org.apache.sling.models.testmodels.classes.InvalidConstructorModel;
 import org.apache.sling.models.testmodels.classes.SuperclassConstructorModel;
 import org.apache.sling.models.testmodels.classes.WithOneConstructorModel;
 import org.apache.sling.models.testmodels.classes.WithThreeConstructorsModel;
 import org.apache.sling.models.testmodels.classes.WithTwoConstructorsModel;
+import org.apache.sling.models.testmodels.classes.constructorinjection.NoNameModel;
+import org.apache.sling.models.testmodels.classes.constructorinjection.WithThreeConstructorsOneInjectModel;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -35,6 +38,7 @@ import org.osgi.framework.BundleContext;
 import org.osgi.service.component.ComponentContext;
 
 @RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
 public class ConstructorTest {
 
     @Mock
@@ -48,15 +52,21 @@ public class ConstructorTest {
     @Mock
     private SlingHttpServletRequest request;
 
+    private static final int INT_VALUE = 42;
+
+    private static final String STRING_VALUE = "myValue";
+
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
 
-        when(request.getAttribute("attribute")).thenReturn(42);
+        when(request.getAttribute("attribute")).thenReturn(INT_VALUE);
+        when(request.getAttribute("attribute2")).thenReturn(STRING_VALUE);
 
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
         factory.bindInjector(new RequestAttributeInjector(), new ServicePropertiesMap(1, 1));
+        factory.bindInjector(new SelfInjector(), new ServicePropertiesMap(2, 2));
     }
 
     @Test
@@ -64,7 +74,7 @@ public class ConstructorTest {
         WithOneConstructorModel model = factory.getAdapter(request, WithOneConstructorModel.class);
         assertNotNull(model);
         assertEquals(request, model.getRequest());
-        assertEquals(42, model.getAttribute());
+        assertEquals(INT_VALUE, model.getAttribute());
     }
 
     @Test
@@ -72,7 +82,7 @@ public class ConstructorTest {
         WithThreeConstructorsModel model = factory.getAdapter(request, WithThreeConstructorsModel.class);
         assertNotNull(model);
         assertEquals(request, model.getRequest());
-        assertEquals(42, model.getAttribute());
+        assertEquals(INT_VALUE, model.getAttribute());
     }
 
     @Test
@@ -80,7 +90,7 @@ public class ConstructorTest {
         WithTwoConstructorsModel model = factory.getAdapter(request, WithTwoConstructorsModel.class);
         assertNotNull(model);
         assertEquals(request, model.getRequest());
-        assertEquals(42, model.getAttribute());
+        assertEquals(INT_VALUE, model.getAttribute());
     }
 
     @Test
@@ -88,7 +98,7 @@ public class ConstructorTest {
         SuperclassConstructorModel model = factory.getAdapter(request, SuperclassConstructorModel.class);
         assertNotNull(model);
         assertEquals(request, model.getRequest());
-        assertEquals(42, model.getAttribute());
+        assertEquals(INT_VALUE, model.getAttribute());
     }
 
     @Test
@@ -97,4 +107,23 @@ public class ConstructorTest {
         assertNull(model);
     }
 
+    /**
+     * Test model object with three constructors, and make sure that one with @Inject is picked for instantiation.
+     * Test mixing of constructor injection and field injection as well.
+     */
+    @Test
+    public void testThreeConstructorsOneInjectInjection() {
+        WithThreeConstructorsOneInjectModel model = factory.getAdapter(request,
+                WithThreeConstructorsOneInjectModel.class);
+        assertNotNull(model);
+        assertNull(model.getRequest());
+        assertEquals(INT_VALUE, model.getAttribute());
+        assertEquals(STRING_VALUE, model.getAttribute2());
+    }
+
+    @Test
+    public void testNoNameModel() {
+        NoNameModel model = factory.getAdapter(request, NoNameModel.class);
+        assertNull(model);
+    }
 }
diff --git a/src/test/java/org/apache/sling/models/impl/DefaultTest.java b/src/test/java/org/apache/sling/models/impl/DefaultTest.java
index aa6de10..01a333f 100644
--- a/src/test/java/org/apache/sling/models/impl/DefaultTest.java
+++ b/src/test/java/org/apache/sling/models/impl/DefaultTest.java
@@ -39,6 +39,7 @@ import org.osgi.framework.BundleContext;
 import org.osgi.service.component.ComponentContext;
 
 @RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
 public class DefaultTest {
 
     @Mock
@@ -58,7 +59,7 @@ public class DefaultTest {
     }
 
     @Test
-    public void testDefaultStringValue() {
+    public void testDefaultStringValueField() {
         ValueMap vm = new ValueMapDecorator(Collections.<String, Object>emptyMap());
 
         Resource res = mock(Resource.class);
@@ -71,7 +72,7 @@ public class DefaultTest {
     }
 
     @Test
-    public void testDefaultStringValueOnInterface() {
+    public void testDefaultStringValueOnInterfaceField() {
         ValueMap vm = new ValueMapDecorator(Collections.<String, Object>singletonMap("first", "first value"));
 
         Resource res = mock(Resource.class);
@@ -85,7 +86,7 @@ public class DefaultTest {
 
 
     @Test
-    public void testDefaultPrimitives() {
+    public void testDefaultPrimitivesField() {
         ValueMap vm = new ValueMapDecorator(Collections.<String, Object>emptyMap());
 
         Resource res = mock(Resource.class);
@@ -103,7 +104,7 @@ public class DefaultTest {
     }
 
     @Test
-    public void testDefaultWrappers() {
+    public void testDefaultWrappersField() {
         ValueMap vm = new ValueMapDecorator(Collections.<String, Object>emptyMap());
 
         Resource res = mock(Resource.class);
@@ -119,4 +120,57 @@ public class DefaultTest {
         assertEquals(Long.valueOf(1L), model.getLongWrapperProperty());
         assertArrayEquals(new Long[] { Long.valueOf(1L), Long.valueOf(1L) }, model.getLongWrapperArrayProperty());
     }
+
+    @Test
+    public void testDefaultStringValueConstructor() {
+        ValueMap vm = new ValueMapDecorator(Collections.<String, Object>emptyMap());
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.DefaultStringModel model
+                = factory.getAdapter(res, org.apache.sling.models.testmodels.classes.constructorinjection.DefaultStringModel.class);
+        assertNotNull(model);
+        assertEquals("firstDefault", model.getFirstProperty());
+        assertEquals(2, model.getSecondProperty().length);
+    }
+
+    @Test
+    public void testDefaultPrimitivesConstructor() {
+        ValueMap vm = new ValueMapDecorator(Collections.<String, Object>emptyMap());
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.DefaultPrimitivesModel model
+                = factory.getAdapter(res, org.apache.sling.models.testmodels.classes.constructorinjection.DefaultPrimitivesModel.class);
+        assertNotNull(model);
+
+        assertEquals(true, model.getBooleanProperty());
+        // we need to wait for JUnit 4.12 for this assertArrayEquals to be working on primitive boolean arrays, https://github.com/junit-team/junit/issues/86!
+        assertTrue(Arrays.equals(new boolean[] { true, true }, model.getBooleanArrayProperty()));
+
+        assertEquals(1L, model.getLongProperty());
+        assertArrayEquals(new long[] { 1L, 1L }, model.getLongArrayProperty());
+    }
+
+    @Test
+    public void testDefaultWrappersConstructor() {
+        ValueMap vm = new ValueMapDecorator(Collections.<String, Object>emptyMap());
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.DefaultWrappersModel model
+                = factory.getAdapter(res, org.apache.sling.models.testmodels.classes.constructorinjection.DefaultWrappersModel.class);
+        assertNotNull(model);
+
+        assertEquals(Boolean.valueOf(true), model.getBooleanWrapperProperty());
+        // we need to wait for JUnit 4.12 for this assertArrayEquals to be working on primitive boolean arrays, https://github.com/junit-team/junit/issues/86!
+        assertTrue(Arrays.equals(new Boolean[] { Boolean.TRUE, Boolean.TRUE }, model.getBooleanWrapperArrayProperty()));
+
+        assertEquals(Long.valueOf(1L), model.getLongWrapperProperty());
+        assertArrayEquals(new Long[] { Long.valueOf(1L), Long.valueOf(1L) }, model.getLongWrapperArrayProperty());
+    }
+
 }
diff --git a/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java b/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
index 8d8fea7..2a82d7d 100644
--- a/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
+++ b/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
@@ -50,6 +50,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
 public class InjectorSpecificAnnotationTest {
 
     @Mock
@@ -110,7 +111,7 @@ public class InjectorSpecificAnnotationTest {
     }
 
     @Test
-    public void testSimpleValueModel() {
+    public void testSimpleValueModelField() {
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("first", "first-value");
         map.put("second", "second-value");
@@ -127,7 +128,7 @@ public class InjectorSpecificAnnotationTest {
     }
 
     @Test
-    public void testOrderForValueAnnotation() {
+    public void testOrderForValueAnnotationField() {
         // make sure that that the correct injection is used
         // make sure that log is adapted from value map
         // and not coming from request attribute
@@ -149,7 +150,7 @@ public class InjectorSpecificAnnotationTest {
     }
 
     @Test
-    public void testOSGiService() throws InvalidSyntaxException {
+    public void testOSGiServiceField() throws InvalidSyntaxException {
         ServiceReference ref = mock(ServiceReference.class);
         Logger log = mock(Logger.class);
         when(bundleContext.getServiceReferences(Logger.class.getName(), null)).thenReturn(
@@ -162,7 +163,7 @@ public class InjectorSpecificAnnotationTest {
     }
 
     @Test
-    public void testScriptVariable() throws InvalidSyntaxException {
+    public void testScriptVariableField() throws InvalidSyntaxException {
         SlingBindings bindings = new SlingBindings();
         SlingScriptHelper helper = mock(SlingScriptHelper.class);
         bindings.setSling(helper);
@@ -174,7 +175,7 @@ public class InjectorSpecificAnnotationTest {
     }
 
     @Test
-    public void testRequestAttribute() throws InvalidSyntaxException {
+    public void testRequestAttributeField() throws InvalidSyntaxException {
         Object attribute = new Object();
         when(request.getAttribute("attribute")).thenReturn(attribute);
 
@@ -184,7 +185,7 @@ public class InjectorSpecificAnnotationTest {
     }
 
     @Test
-    public void testChildResource() {
+    public void testChildResourceField() {
         Resource res = mock(Resource.class);
         Resource child = mock(Resource.class);
         when(res.getChild("child1")).thenReturn(child);
@@ -194,4 +195,97 @@ public class InjectorSpecificAnnotationTest {
         assertNotNull("Could not instanciate model", model);
         assertEquals(child, model.getChildResource());
     }
+
+    @Test
+    public void testSimpleValueModelConstructor() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("first", "first-value");
+        map.put("second", "second-value");
+        ValueMap vm = new ValueMapDecorator(map);
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+        when(request.getResource()).thenReturn(res);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel model
+                = factory.getAdapter(request, org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+        assertNotNull("Could not instanciate model", model);
+        assertEquals("first-value", model.getFirst());
+        assertEquals("second-value", model.getSecond());
+    }
+
+    @Test
+    public void testOrderForValueAnnotationConstructor() {
+        // make sure that that the correct injection is used
+        // make sure that log is adapted from value map
+        // and not coming from request attribute
+        Logger logFromValueMap = LoggerFactory.getLogger(this.getClass());
+
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("first", "first-value");
+        map.put("log", logFromValueMap);
+        ValueMap vm = new ValueMapDecorator(map);
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+        when(request.getResource()).thenReturn(res);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel model
+                = factory.getAdapter(request, org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+        assertNotNull("Could not instanciate model", model);
+        assertEquals("first-value", model.getFirst());
+        assertEquals(logFromValueMap, model.getLog());
+    }
+
+    @Test
+    public void testOSGiServiceConstructor() throws InvalidSyntaxException {
+        ServiceReference ref = mock(ServiceReference.class);
+        Logger log = mock(Logger.class);
+        when(bundleContext.getServiceReferences(Logger.class.getName(), null)).thenReturn(
+                new ServiceReference[] { ref });
+        when(bundleContext.getService(ref)).thenReturn(log);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel model
+                = factory.getAdapter(request, org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+        assertNotNull("Could not instanciate model", model);
+        assertEquals(log, model.getService());
+    }
+
+    @Test
+    public void testScriptVariableConstructor() throws InvalidSyntaxException {
+        SlingBindings bindings = new SlingBindings();
+        SlingScriptHelper helper = mock(SlingScriptHelper.class);
+        bindings.setSling(helper);
+        when(request.getAttribute(SlingBindings.class.getName())).thenReturn(bindings);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel model
+                = factory.getAdapter(request, org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+        assertNotNull("Could not instanciate model", model);
+        assertEquals(helper, model.getHelper());
+    }
+
+    @Test
+    public void testRequestAttributeConstructor() throws InvalidSyntaxException {
+        Object attribute = new Object();
+        when(request.getAttribute("attribute")).thenReturn(attribute);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel model
+                = factory.getAdapter(request, org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+        assertNotNull("Could not instanciate model", model);
+        assertEquals(attribute, model.getRequestAttribute());
+    }
+
+    @Test
+    public void testChildResourceConstructor() {
+        Resource res = mock(Resource.class);
+        Resource child = mock(Resource.class);
+        when(res.getChild("child1")).thenReturn(child);
+        when(request.getResource()).thenReturn(res);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel model
+                = factory.getAdapter(request, org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+        assertNotNull("Could not instanciate model", model);
+        assertEquals(child, model.getChildResource());
+    }
+
 }
diff --git a/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java b/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
index 1058323..df09c52 100644
--- a/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
+++ b/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
@@ -47,6 +47,7 @@ import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
 
 @RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
 public class OSGiInjectionTest {
     private ModelAdapterFactory factory;
 
@@ -75,7 +76,7 @@ public class OSGiInjectionTest {
     }
 
     @Test
-    public void testSimpleOSGiModel() throws Exception {
+    public void testSimpleOSGiModelField() throws Exception {
         ServiceReference ref = mock(ServiceReference.class);
         ServiceInterface service = mock(ServiceInterface.class);
         when(bundleContext.getServiceReferences(ServiceInterface.class.getName(), null)).thenReturn(
@@ -93,7 +94,7 @@ public class OSGiInjectionTest {
     }
 
     @Test
-    public void testRequestOSGiModel() throws Exception {
+    public void testRequestOSGiModelField() throws Exception {
         ServiceInterface service = mock(ServiceInterface.class);
 
         SlingHttpServletRequest request = mock(SlingHttpServletRequest.class);
@@ -114,7 +115,7 @@ public class OSGiInjectionTest {
     }
 
     @Test
-    public void testListOSGiModel() throws Exception {
+    public void testListOSGiModelField() throws Exception {
         ServiceReference ref1 = mock(ServiceReference.class);
         ServiceInterface service1 = mock(ServiceInterface.class);
         when(bundleContext.getService(ref1)).thenReturn(service1);
@@ -138,7 +139,7 @@ public class OSGiInjectionTest {
     }
 
     @Test
-    public void testArrayOSGiModel() throws Exception {
+    public void testArrayOSGiModelField() throws Exception {
         ServiceReference ref1 = mock(ServiceReference.class);
         ServiceInterface service1 = mock(ServiceInterface.class);
         when(bundleContext.getService(ref1)).thenReturn(service1);
@@ -162,7 +163,7 @@ public class OSGiInjectionTest {
     }
 
     @Test
-    public void testOptionalArrayOSGiModel() throws Exception {
+    public void testOptionalArrayOSGiModelField() throws Exception {
 
         Resource res = mock(Resource.class);
 
@@ -174,7 +175,7 @@ public class OSGiInjectionTest {
     }
 
     @Test
-    public void testOptionalListOSGiModel() throws Exception {
+    public void testOptionalListOSGiModelField() throws Exception {
         Resource res = mock(Resource.class);
 
         OptionalListOSGiModel model = factory.getAdapter(res, OptionalListOSGiModel.class);
@@ -185,7 +186,7 @@ public class OSGiInjectionTest {
     }
 
     @Test
-    public void testCollectionOSGiModel() throws Exception {
+    public void testCollectionOSGiModelField() throws Exception {
         ServiceReference ref1 = mock(ServiceReference.class);
         ServiceInterface service1 = mock(ServiceInterface.class);
         when(bundleContext.getService(ref1)).thenReturn(service1);
@@ -210,7 +211,7 @@ public class OSGiInjectionTest {
     }
 
     @Test
-    public void testSetOSGiModel() throws Exception {
+    public void testSetOSGiModelField() throws Exception {
         ServiceReference ref1 = mock(ServiceReference.class);
         ServiceInterface service1 = mock(ServiceInterface.class);
         when(bundleContext.getService(ref1)).thenReturn(service1);
@@ -232,4 +233,49 @@ public class OSGiInjectionTest {
         verify(bundleContext).getBundles();
         verifyNoMoreInteractions(res, bundleContext);
     }
+
+    @Test
+    public void testSimpleOSGiModelConstructor() throws Exception {
+        ServiceReference ref = mock(ServiceReference.class);
+        ServiceInterface service = mock(ServiceInterface.class);
+        when(bundleContext.getServiceReferences(ServiceInterface.class.getName(), null)).thenReturn(
+                new ServiceReference[] { ref });
+        when(bundleContext.getService(ref)).thenReturn(service);
+
+        Resource res = mock(Resource.class);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.SimpleOSGiModel model
+                = factory.getAdapter(res, org.apache.sling.models.testmodels.classes.constructorinjection.SimpleOSGiModel.class);
+        assertNotNull(model);
+        assertNotNull(model.getService());
+        assertEquals(service, model.getService());
+
+        verifyNoMoreInteractions(res);
+    }
+
+    @Test
+    public void testListOSGiModelConstructor() throws Exception {
+        ServiceReference ref1 = mock(ServiceReference.class);
+        ServiceInterface service1 = mock(ServiceInterface.class);
+        when(bundleContext.getService(ref1)).thenReturn(service1);
+        ServiceReference ref2 = mock(ServiceReference.class);
+        ServiceInterface service2 = mock(ServiceInterface.class);
+        when(bundleContext.getService(ref2)).thenReturn(service2);
+
+        when(bundleContext.getServiceReferences(ServiceInterface.class.getName(), null)).thenReturn(
+                new ServiceReference[] { ref1, ref2 });
+
+        Resource res = mock(Resource.class);
+
+        org.apache.sling.models.testmodels.classes.constructorinjection.ListOSGiModel model
+                = factory.getAdapter(res, org.apache.sling.models.testmodels.classes.constructorinjection.ListOSGiModel.class);
+        assertNotNull(model);
+        assertNotNull(model.getServices());
+        assertEquals(2, model.getServices().size());
+        assertEquals(service1, model.getServices().get(0));
+        assertEquals(service2, model.getServices().get(1));
+
+        verifyNoMoreInteractions(res);
+    }
+
 }
diff --git a/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java b/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
index 9f495e3..91dd851 100644
--- a/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
+++ b/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
@@ -33,6 +33,7 @@ import org.osgi.framework.BundleContext;
 import org.osgi.service.component.ComponentContext;
 
 @RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
 public class RequestInjectionTest {
 
     @Mock
@@ -63,10 +64,18 @@ public class RequestInjectionTest {
     }
 
     @Test
-    public void testNamedInjection() {
+    public void testNamedInjectionField() {
         BindingsModel model = factory.getAdapter(request, BindingsModel.class);
         assertNotNull(model.getSling());
         assertEquals(sling, model.getSling());
     }
 
+    @Test
+    public void testNamedInjectionConstructor() {
+        org.apache.sling.models.testmodels.classes.constructorinjection.BindingsModel model
+                = factory.getAdapter(request, org.apache.sling.models.testmodels.classes.constructorinjection.BindingsModel.class);
+        assertNotNull(model.getSling());
+        assertEquals(sling, model.getSling());
+    }
+
 }
diff --git a/src/test/java/org/apache/sling/models/impl/SelfDependencyTest.java b/src/test/java/org/apache/sling/models/impl/SelfDependencyTest.java
new file mode 100644
index 0000000..e0e9bad
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/SelfDependencyTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.impl.injectors.SelfInjector;
+import org.apache.sling.models.testmodels.classes.DirectCyclicSelfDependencyModel;
+import org.apache.sling.models.testmodels.classes.IndirectCyclicSelfDependencyModelA;
+import org.apache.sling.models.testmodels.classes.SelfDependencyModelA;
+import org.apache.sling.models.testmodels.classes.SelfDependencyModelB;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
+public class SelfDependencyTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    private ModelAdapterFactory factory;
+
+    @Mock
+    private SlingHttpServletRequest request;
+
+    @SuppressWarnings("unchecked")
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(request.adaptTo(any(Class.class))).then(new Answer<Object>() {
+            @Override
+            public Object answer(InvocationOnMock invocation) throws Throwable {
+                Class<?> clazz = (Class<?>) invocation.getArguments()[0];
+                return factory.getAdapter(request, clazz);
+            }
+        });
+
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(new SelfInjector(), new ServicePropertiesMap(1, 1));
+    }
+
+    @Test
+    public void testChainedSelfDependency() {
+        SelfDependencyModelA objectA = factory.getAdapter(request, SelfDependencyModelA.class);
+        assertNotNull(objectA);
+        SelfDependencyModelB objectB = objectA.getDependencyB();
+        assertNotNull(objectB);
+        assertSame(request, objectB.getRequest());
+    }
+
+    @Test
+    public void testDirectCyclicSelfDependency() {
+        DirectCyclicSelfDependencyModel object = factory.getAdapter(request, DirectCyclicSelfDependencyModel.class);
+        assertNull(object);
+    }
+
+    @Test
+    public void testInddirectCyclicSelfDependency() {
+        IndirectCyclicSelfDependencyModelA object = factory.getAdapter(request,
+                IndirectCyclicSelfDependencyModelA.class);
+        assertNull(object);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/BindingsInjectorTest.java b/src/test/java/org/apache/sling/models/impl/injectors/BindingsInjectorTest.java
new file mode 100644
index 0000000..fa15446
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/injectors/BindingsInjectorTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.injectors;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import javax.servlet.ServletRequest;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
+public class BindingsInjectorTest {
+
+    private BindingsInjector injector = new BindingsInjector();
+
+    @Mock
+    private ServletRequest request;
+    @Mock
+    private SlingBindings bindings;
+
+    private static final String STRING_PARAM = "param1";
+    private static final String INTEGER_PARAM = "param2";
+    private static final String CLASS_PARAM = "param3";
+    private static final String STRING_VALUE = "myValue";
+    private static final int INTEGER_VALUE = 42;
+    private static final ResourceResolver CLASS_INSTANCE = mock(ResourceResolver.class);
+
+    @Before
+    public void setUp() {
+        when(request.getAttribute(SlingBindings.class.getName())).thenReturn(bindings);
+        when(bindings.get(STRING_PARAM)).thenReturn(STRING_VALUE);
+        when(bindings.get(INTEGER_PARAM)).thenReturn(INTEGER_VALUE);
+        when(bindings.get(CLASS_PARAM)).thenReturn(CLASS_INSTANCE);
+    }
+
+    @Test
+    public void testStringParam() {
+        Object result = injector.getValue(request, STRING_PARAM, String.class, null, null);
+        assertEquals(STRING_VALUE, result);
+    }
+
+    @Test
+    public void testIntegerParam() {
+        Object result = injector.getValue(request, INTEGER_PARAM, Integer.class, null, null);
+        assertEquals(INTEGER_VALUE, result);
+    }
+
+    @Test
+    public void testClassInstance() {
+        Object result = injector.getValue(request, CLASS_PARAM, ResourceResolver.class, null, null);
+        assertSame(CLASS_INSTANCE, result);
+    }
+
+    @Test
+    public void testNonMatchingClassInstance() {
+        Object result = injector.getValue(request, CLASS_PARAM, Resource.class, null, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testNonRequestAdaptable() {
+        Object result = injector.getValue(mock(ResourceResolver.class), STRING_PARAM, String.class, null, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testRequestThatDoesNotContainBindings() {
+        when(request.getAttribute(SlingBindings.class.getName())).thenReturn(null);
+        Object result = injector.getValue(request, STRING_PARAM, String.class, null, null);
+        assertNull(result);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/RequestAttributeInjectorTest.java b/src/test/java/org/apache/sling/models/impl/injectors/RequestAttributeInjectorTest.java
new file mode 100644
index 0000000..75ac1ca
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/injectors/RequestAttributeInjectorTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.injectors;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import javax.servlet.ServletRequest;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
+public class RequestAttributeInjectorTest {
+
+    private RequestAttributeInjector injector = new RequestAttributeInjector();
+    
+    @Mock
+    private ServletRequest request;
+    
+    private static final String STRING_PARAM = "param1";
+    private static final String INTEGER_PARAM = "param2";
+    private static final String CLASS_PARAM = "param3";
+    private static final String STRING_VALUE = "myValue";
+    private static final int INTEGER_VALUE = 42;
+    private static final ResourceResolver CLASS_INSTANCE = mock(ResourceResolver.class);
+    
+    @Before
+    public void setUp() {
+        when(request.getAttribute(STRING_PARAM)).thenReturn(STRING_VALUE);
+        when(request.getAttribute(INTEGER_PARAM)).thenReturn(INTEGER_VALUE);
+        when(request.getAttribute(CLASS_PARAM)).thenReturn(CLASS_INSTANCE);
+    }
+
+    @Test
+    public void testStringParam() {
+        Object result = injector.getValue(request, STRING_PARAM, String.class, null, null);
+        assertEquals(STRING_VALUE, result);
+    }
+
+    @Test
+    public void testIntegerParam() {
+        Object result = injector.getValue(request, INTEGER_PARAM, Integer.class, null, null);
+        assertEquals(INTEGER_VALUE, result);
+    }
+
+    @Test
+    public void testClassInstance() {
+        Object result = injector.getValue(request, CLASS_PARAM, ResourceResolver.class, null, null);
+        assertSame(CLASS_INSTANCE, result);
+    }
+
+    @Test
+    public void testNonMatchingClassInstance() {
+        Object result = injector.getValue(request, CLASS_PARAM, Resource.class, null, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testNonRequestAdaptable() {
+        Object result = injector.getValue(mock(ResourceResolver.class), STRING_PARAM, String.class, null, null);
+        assertNull(result);
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java b/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java
new file mode 100644
index 0000000..3e7251a
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.injectors;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.*;
+
+import java.lang.reflect.AnnotatedElement;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
+public class SelfInjectorTest {
+
+    private SelfInjector injector = new SelfInjector();
+    
+    @Mock
+    private SlingHttpServletRequest request;
+    @Mock
+    private AnnotatedElement annotatedElement;
+
+    @Test
+    public void testMatchingClass() {
+        Object result = injector.getValue(request, "notRelevant", SlingHttpServletRequest.class, annotatedElement, null);
+        assertSame(request, result);
+    }
+
+    @Test
+    public void testMatchingSubClass() {
+        Object result = injector.getValue(request, "notRelevant", HttpServletRequest.class, annotatedElement, null);
+        assertSame(request, result);
+    }
+
+    @Test
+    public void testNotMatchingClass() {
+        Object result = injector.getValue(request, "notRelevant", ResourceResolver.class, annotatedElement, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testWithNullName() {
+        Object result = injector.getValue(request, null, SlingHttpServletRequest.class, annotatedElement, null);
+        assertSame(request, result);
+    }
+
+    @Test
+    public void testMatchingClassWithSelfAnnotation() {
+        when(annotatedElement.isAnnotationPresent(Self.class)).thenReturn(true);
+        Object result = injector.getValue(request, "notRelevant", SlingHttpServletRequest.class, annotatedElement, null);
+        assertSame(request, result);
+    }
+
+    @Test
+    public void testNotMatchingClassWithSelfAnnotation() {
+        when(annotatedElement.isAnnotationPresent(Self.class)).thenReturn(true);
+        Object result = injector.getValue(request, "notRelevant", ResourceResolver.class, annotatedElement, null);
+        assertSame(request, result);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/ValueMapInjectorTest.java b/src/test/java/org/apache/sling/models/impl/injectors/ValueMapInjectorTest.java
new file mode 100644
index 0000000..cf3583a
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/injectors/ValueMapInjectorTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.injectors;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
+public class ValueMapInjectorTest {
+
+    private ValueMapInjector injector = new ValueMapInjector();
+
+    @Mock
+    private ValueMap valueMap;
+
+    private static final String STRING_PARAM = "param1";
+    private static final String INTEGER_PARAM = "param2";
+    private static final String CLASS_PARAM = "param3";
+    private static final String STRING_VALUE = "myValue";
+    private static final int INTEGER_VALUE = 42;
+    private static final ResourceResolver CLASS_INSTANCE = mock(ResourceResolver.class);
+
+    @Before
+    public void setUp() {
+        when(valueMap.get(STRING_PARAM, String.class)).thenReturn(STRING_VALUE);
+        when(valueMap.get(INTEGER_PARAM, Integer.class)).thenReturn(INTEGER_VALUE);
+        when(valueMap.get(CLASS_PARAM, ResourceResolver.class)).thenReturn(CLASS_INSTANCE);
+    }
+
+    @Test
+    public void testStringParam() {
+        Object result = injector.getValue(valueMap, STRING_PARAM, String.class, null, null);
+        assertEquals(STRING_VALUE, result);
+    }
+
+    @Test
+    public void testIntegerParam() {
+        Object result = injector.getValue(valueMap, INTEGER_PARAM, Integer.class, null, null);
+        assertEquals(INTEGER_VALUE, result);
+    }
+
+    @Test
+    public void testClassInstance() {
+        Object result = injector.getValue(valueMap, CLASS_PARAM, ResourceResolver.class, null, null);
+        assertSame(CLASS_INSTANCE, result);
+    }
+
+    @Test
+    public void testNonMatchingClassInstance() {
+        Object result = injector.getValue(valueMap, CLASS_PARAM, Resource.class, null, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testNonValueMapAdaptable() {
+        Object result = injector.getValue(mock(ResourceResolver.class), STRING_PARAM, String.class, null, null);
+        assertNull(result);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/DirectCyclicSelfDependencyModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/DirectCyclicSelfDependencyModel.java
new file mode 100644
index 0000000..c09603b
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/DirectCyclicSelfDependencyModel.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables=SlingHttpServletRequest.class)
+@SuppressWarnings("javadoc")
+public class DirectCyclicSelfDependencyModel {
+
+    @Self
+    private DirectCyclicSelfDependencyModel modelSelf;
+
+    public DirectCyclicSelfDependencyModel getModelSelf() {
+        return modelSelf;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/IndirectCyclicSelfDependencyModelA.java b/src/test/java/org/apache/sling/models/testmodels/classes/IndirectCyclicSelfDependencyModelA.java
new file mode 100644
index 0000000..cd329a5
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/IndirectCyclicSelfDependencyModelA.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables=SlingHttpServletRequest.class)
+@SuppressWarnings("javadoc")
+public class IndirectCyclicSelfDependencyModelA {
+
+    @Self
+    private IndirectCyclicSelfDependencyModelB dependencyB;
+
+    public IndirectCyclicSelfDependencyModelB getDependencyB() {
+        return dependencyB;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/IndirectCyclicSelfDependencyModelB.java b/src/test/java/org/apache/sling/models/testmodels/classes/IndirectCyclicSelfDependencyModelB.java
new file mode 100644
index 0000000..68dfb15
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/IndirectCyclicSelfDependencyModelB.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables=SlingHttpServletRequest.class)
+@SuppressWarnings("javadoc")
+public class IndirectCyclicSelfDependencyModelB {
+
+    @Self
+    private IndirectCyclicSelfDependencyModelA dependencyA;
+
+    public IndirectCyclicSelfDependencyModelA getDependencyA() {
+        return dependencyA;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SelfDependencyModelA.java b/src/test/java/org/apache/sling/models/testmodels/classes/SelfDependencyModelA.java
new file mode 100644
index 0000000..6df4527
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SelfDependencyModelA.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables=SlingHttpServletRequest.class)
+@SuppressWarnings("javadoc")
+public class SelfDependencyModelA {
+
+    @Self
+    private SelfDependencyModelB dependencyB;
+
+    public SelfDependencyModelB getDependencyB() {
+        return dependencyB;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SelfDependencyModelB.java b/src/test/java/org/apache/sling/models/testmodels/classes/SelfDependencyModelB.java
new file mode 100644
index 0000000..6d7757c
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SelfDependencyModelB.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables=SlingHttpServletRequest.class)
+@SuppressWarnings("javadoc")
+public class SelfDependencyModelB {
+
+    @Self
+    private SlingHttpServletRequest request;
+
+    public SlingHttpServletRequest getRequest() {
+        return request;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/BindingsModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/BindingsModel.java
new file mode 100644
index 0000000..595663a
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/BindingsModel.java
@@ -0,0 +1,41 @@
+/*
+ * 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 javax.inject.Named;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+@SuppressWarnings("javadoc")
+public class BindingsModel {
+
+    private final SlingScriptHelper sling;
+
+    @Inject
+    public BindingsModel(@Named("sling") SlingScriptHelper sling) {
+        this.sling = sling;
+    }
+
+    public SlingScriptHelper getSling() {
+        return sling;
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultPrimitivesModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultPrimitivesModel.java
new file mode 100644
index 0000000..6de8e7f
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultPrimitivesModel.java
@@ -0,0 +1,62 @@
+/*
+ * 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.Default;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+@SuppressWarnings("javadoc")
+public class DefaultPrimitivesModel {
+
+    private final boolean booleanProperty;
+    private final boolean[] booleanArrayProperty;
+    private final long longProperty;
+    private final long[] longArrayProperty;
+
+    @Inject
+    public DefaultPrimitivesModel(
+            @Default(booleanValues = true) boolean booleanProperty, 
+            @Default(booleanValues = { true, true }) boolean[] booleanArrayProperty,
+            @Default(longValues = 1L) long longProperty,
+            @Default(longValues = { 1L, 1L }) long[] longArrayProperty
+    ) {
+        this.booleanProperty = booleanProperty;
+        this.booleanArrayProperty = booleanArrayProperty;
+        this.longProperty = longProperty;
+        this.longArrayProperty = longArrayProperty;
+    }
+
+    public boolean getBooleanProperty() {
+        return booleanProperty;
+    }
+
+    public boolean[] getBooleanArrayProperty() {
+        return booleanArrayProperty;
+    }
+
+    public long getLongProperty() {
+        return longProperty;
+    }
+
+    public long[] getLongArrayProperty() {
+        return longArrayProperty;
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultStringModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultStringModel.java
new file mode 100644
index 0000000..7c7accf
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultStringModel.java
@@ -0,0 +1,48 @@
+/*
+ * 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.Default;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+@SuppressWarnings("javadoc")
+public class DefaultStringModel {
+
+    private final String firstProperty;
+    private final String[] secondProperty;
+
+    @Inject
+    public DefaultStringModel(
+            @Default(values = "firstDefault") String firstProperty,
+            @Default(values = { "firstDefault", "secondDefault" }) String[] secondProperty
+    ) {
+        this.firstProperty = firstProperty;
+        this.secondProperty = secondProperty;
+    }
+
+    public String getFirstProperty() {
+        return firstProperty;
+    }
+
+    public String[] getSecondProperty() {
+        return secondProperty;
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultWrappersModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultWrappersModel.java
new file mode 100644
index 0000000..bc50f0d
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultWrappersModel.java
@@ -0,0 +1,63 @@
+/*
+ * 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.Default;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+@SuppressWarnings("javadoc")
+public class DefaultWrappersModel {
+
+    private final Boolean booleanWrapperProperty;
+    private final Boolean[] booleanWrapperArrayProperty;
+    private final Long longWrapperProperty;
+    private final Long[] longWrapperArrayProperty;
+
+    @Inject
+    public DefaultWrappersModel(
+            @Default(booleanValues = true) Boolean booleanWrapperProperty,
+            @Default(booleanValues = { true, true }) Boolean[] booleanWrapperArrayProperty,
+            @Default(longValues = 1L) Long longWrapperProperty,
+            @Default(longValues = { 1L, 1L }) Long[] longWrapperArrayProperty
+    ) {
+        this.booleanWrapperProperty = booleanWrapperProperty;
+        this.booleanWrapperArrayProperty = booleanWrapperArrayProperty;
+        this.longWrapperProperty = longWrapperProperty;
+        this.longWrapperArrayProperty = longWrapperArrayProperty;
+    }
+
+    public Boolean getBooleanWrapperProperty() {
+        return booleanWrapperProperty;
+    }
+
+    public Boolean[] getBooleanWrapperArrayProperty() {
+        return booleanWrapperArrayProperty;
+    }
+
+    public Long getLongWrapperProperty() {
+        return longWrapperProperty;
+    }
+
+    public Long[] getLongWrapperArrayProperty() {
+        return longWrapperArrayProperty;
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/InjectorSpecificAnnotationModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/InjectorSpecificAnnotationModel.java
new file mode 100644
index 0000000..2a6873f
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/InjectorSpecificAnnotationModel.java
@@ -0,0 +1,91 @@
+/*
+ * 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.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.ChildResource;
+import org.apache.sling.models.annotations.injectorspecific.OSGiService;
+import org.apache.sling.models.annotations.injectorspecific.RequestAttribute;
+import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
+import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
+import org.slf4j.Logger;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+@SuppressWarnings("javadoc")
+public class InjectorSpecificAnnotationModel {
+
+    private final String first;
+    private final String secondWithOtherName;
+    private final Logger log;
+    private final SlingScriptHelper helper;
+    private final Object requestAttribute;
+    private final Logger service;
+    private final Resource childResource;
+
+    @Inject
+    public InjectorSpecificAnnotationModel(
+            @ValueMapValue(name = "first", optional = true) String first,
+            @ValueMapValue(name = "second", optional = true) String secondWithOtherName,
+            @ValueMapValue(name = "log", optional = true) Logger log,
+            @ScriptVariable(optional = true, name = "sling") SlingScriptHelper helper,
+            @RequestAttribute(optional = true, name = "attribute") Object requestAttribute,
+            @OSGiService(optional = true) Logger service,
+            @ChildResource(optional = true, name = "child1") Resource childResource
+    ) {
+        this.first = first;
+        this.secondWithOtherName = secondWithOtherName;
+        this.log = log;
+        this.helper = helper;
+        this.requestAttribute = requestAttribute;
+        this.service = service;
+        this.childResource = childResource;
+    }
+
+    public String getFirst() {
+        return first;
+    }
+
+    public String getSecond() {
+        return secondWithOtherName;
+    }
+
+    public Logger getLog() {
+        return log;
+    }
+
+    public Logger getService() {
+        return service;
+    }
+
+    public SlingScriptHelper getHelper() {
+        return helper;
+    }
+
+    public Object getRequestAttribute() {
+        return requestAttribute;
+    }
+
+    public Resource getChildResource() {
+        return childResource;
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/ListOSGiModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/ListOSGiModel.java
new file mode 100644
index 0000000..66e8e2f
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/ListOSGiModel.java
@@ -0,0 +1,42 @@
+/*
+ * 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 java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.testmodels.interfaces.ServiceInterface;
+
+@Model(adaptables = Resource.class)
+@SuppressWarnings("javadoc")
+public class ListOSGiModel {
+
+    private final List<ServiceInterface> services;
+
+    @Inject
+    public ListOSGiModel(List<ServiceInterface> services) {
+        this.services = services;
+    }
+
+    public List<ServiceInterface> getServices() {
+        return services;
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/NoNameModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/NoNameModel.java
new file mode 100644
index 0000000..78e2928
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/NoNameModel.java
@@ -0,0 +1,42 @@
+/*
+ * 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.SlingHttpServletRequest;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+@SuppressWarnings("javadoc")
+public class NoNameModel {
+
+    private final SlingScriptHelper sling;
+
+    @Inject
+    public NoNameModel(SlingScriptHelper sling) {
+        this.sling = sling;
+    }
+
+    public SlingScriptHelper getSling() {
+        return sling;
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/SimpleOSGiModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/SimpleOSGiModel.java
new file mode 100644
index 0000000..d48c2c6
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/SimpleOSGiModel.java
@@ -0,0 +1,40 @@
+/*
+ * 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.testmodels.interfaces.ServiceInterface;
+
+@Model(adaptables = Resource.class)
+@SuppressWarnings("javadoc")
+public class SimpleOSGiModel {
+
+    private final ServiceInterface service;
+
+    @Inject
+    public SimpleOSGiModel(ServiceInterface service) {
+        this.service = service;
+    }
+
+    public ServiceInterface getService() {
+        return service;
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/WithThreeConstructorsOneInjectModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/WithThreeConstructorsOneInjectModel.java
new file mode 100644
index 0000000..2e97072
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/WithThreeConstructorsOneInjectModel.java
@@ -0,0 +1,59 @@
+/*
+ * 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 javax.inject.Named;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+@SuppressWarnings("javadoc")
+public class WithThreeConstructorsOneInjectModel {
+
+    private SlingHttpServletRequest request;
+
+    @Inject
+    private int attribute;
+
+    private String attribute2;
+
+    public WithThreeConstructorsOneInjectModel(SlingHttpServletRequest request) {
+        this.request = request;
+    }
+
+    public WithThreeConstructorsOneInjectModel() {
+    }
+
+    @Inject
+    public WithThreeConstructorsOneInjectModel(@Named("attribute2") String attribute2) {
+        this.attribute2 = attribute2;
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public String getAttribute2() {
+        return attribute2;
+    }
+
+    public SlingHttpServletRequest getRequest() {
+        return request;
+    }
+}
\ No newline at end of file

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

[sling-org-apache-sling-models-impl] 02/24: using next version during release

Posted by ro...@apache.org.
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 71a563226a90e08172d5af0e0c0d737efec2ce26
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Wed Jun 25 17:00:17 2014 +0000

    using next version during release
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1605500 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 5e7b1fc..5ce4aca 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,7 +63,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.models.api</artifactId>
-            <version>1.0.2</version>
+            <version>1.0.3-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

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

[sling-org-apache-sling-models-impl] 24/24: [maven-release-plugin] copy for tag org.apache.sling.models.impl-1.1.0

Posted by ro...@apache.org.
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 f0c3f772108762de213b71de3bda6f59152985b1
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Tue Sep 2 19:14:45 2014 +0000

    [maven-release-plugin]  copy for tag org.apache.sling.models.impl-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.models.impl-1.1.0@1622102 13f79535-47bb-0310-9956-ffa450edef68

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

[sling-org-apache-sling-models-impl] 13/24: SLING-3860 - allowing maximum recursion depth to be configured

Posted by ro...@apache.org.
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 895766f3e999997302d645e7f82cdbfdd5268c5c
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Aug 22 21:39:30 2014 +0000

    SLING-3860 - allowing maximum recursion depth to be configured
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1619937 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/models/impl/ModelAdapterFactory.java     | 52 +++++++++++-----------
 .../sling/models/impl/ThreadInvocationCounter.java | 42 +++++++++++++++++
 .../apache/sling/models/impl/ConstructorTest.java  |  3 ++
 .../sling/models/impl/CustomInjectorTest.java      |  3 ++
 .../org/apache/sling/models/impl/DefaultTest.java  |  3 ++
 .../impl/InjectorSpecificAnnotationTest.java       |  3 ++
 .../sling/models/impl/InvalidAdaptationsTest.java  |  2 +
 .../sling/models/impl/MultipleInjectorTest.java    |  3 ++
 .../sling/models/impl/OSGiInjectionTest.java       |  3 ++
 .../sling/models/impl/OptionalPrimitivesTest.java  |  4 ++
 .../sling/models/impl/PostConstructTest.java       |  3 ++
 .../sling/models/impl/RequestInjectionTest.java    |  3 ++
 .../models/impl/ResourceModelClassesTest.java      |  2 +
 .../models/impl/ResourceModelInterfacesTest.java   |  3 ++
 .../models/impl/ResourcePathInjectionTest.java     |  3 ++
 .../sling/models/impl/SelfDependencyTest.java      |  4 ++
 .../java/org/apache/sling/models/impl/ViaTest.java |  3 ++
 17 files changed, 112 insertions(+), 27 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 1880e66..0f51f66 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -32,6 +32,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -53,11 +54,13 @@ import org.apache.commons.lang.ClassUtils;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.ReferencePolicy;
 import org.apache.sling.api.adapter.Adaptable;
 import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.apache.sling.commons.osgi.ServiceUtil;
 import org.apache.sling.models.annotations.Default;
 import org.apache.sling.models.annotations.DefaultInjectionStrategy;
@@ -80,7 +83,7 @@ import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-@Component
+@Component(metatype = true)
 public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     private static class DisposalCallbackRegistryImpl implements DisposalCallbackRegistry {
@@ -121,6 +124,11 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     private static final Logger log = LoggerFactory.getLogger(ModelAdapterFactory.class);
 
+    private static final int DEFAULT_MAX_RECURSION_DEPTH = 20;
+
+    @Property(label = "Maximum Recursion Depth", description = "Maximum depth adaptation will be attempted.", intValue = DEFAULT_MAX_RECURSION_DEPTH)
+    private static final String PROP_MAX_RECURSION_DEPTH = "max.recursion.depth";
+
     @Reference(name = "injector", referenceInterface = Injector.class,
             cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
     private final Map<Object, Injector> injectors = new TreeMap<Object, Injector>();
@@ -138,38 +146,19 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
     private ServiceRegistration jobRegistration;
 
     private ServiceRegistration configPrinterRegistration;
-    
-    // Use threadlocal to count recursive invocations and break recursing if a max. limit is reached (to avoid cyclic dependencies)
-    private static final int MAX_RECURSIVE_INOVCATIONS = 20;
 
-    private static class ThreadInvocationCounter {
-        private int count;
-        public boolean isMaximumReached() {
-            return count >= MAX_RECURSIVE_INOVCATIONS;
-        }
-        public void increase() {
-            this.count++;
-        }
-        public void decrease() {
-            this.count--;
-        }
-    }
-
-    private static final ThreadLocal<ThreadInvocationCounter> INVOCATION_COUNT_THREADLOCAL = new ThreadLocal<ModelAdapterFactory.ThreadInvocationCounter>() {
-        @Override
-        protected ThreadInvocationCounter initialValue() {
-            return new ThreadInvocationCounter();
-        }
-    };
+    // Use threadlocal to count recursive invocations and break recursing if a max. limit is reached (to avoid cyclic dependencies)
+    private ThreadLocal<ThreadInvocationCounter> invocationCountThreadLocal;
 
     @SuppressWarnings("unchecked")
     public <AdapterType> AdapterType getAdapter(Object adaptable, Class<AdapterType> type) {
-        if (INVOCATION_COUNT_THREADLOCAL.get().isMaximumReached()) {
+        ThreadInvocationCounter threadInvocationCounter = invocationCountThreadLocal.get();
+        if (threadInvocationCounter.isMaximumReached()) {
             log.error("Adapting {} to {} failed, too much recursive invocations (>={}).",
-                    new Object[] { adaptable, type, MAX_RECURSIVE_INOVCATIONS });
+                    new Object[] { adaptable, type, threadInvocationCounter.maxRecursionDepth });
             return null;
         };
-        INVOCATION_COUNT_THREADLOCAL.get().increase();
+        threadInvocationCounter.increase();
         try {
             Model modelAnnotation = type.getAnnotation(Model.class);
             if (modelAnnotation == null) {
@@ -203,7 +192,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
                 }
             }
         } finally {
-            INVOCATION_COUNT_THREADLOCAL.get().decrease();
+            threadInvocationCounter.decrease();
         }
     }
 
@@ -902,6 +891,15 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     @Activate
     protected void activate(final ComponentContext ctx) {
+        Dictionary<?, ?> props = ctx.getProperties();
+        final int maxRecursionDepth = PropertiesUtil.toInteger(props.get(PROP_MAX_RECURSION_DEPTH), DEFAULT_MAX_RECURSION_DEPTH);
+        this.invocationCountThreadLocal = new ThreadLocal<ThreadInvocationCounter>() {
+            @Override
+            protected ThreadInvocationCounter initialValue() {
+                return new ThreadInvocationCounter(maxRecursionDepth);
+            }
+        };
+
         BundleContext bundleContext = ctx.getBundleContext();
         this.queue = new ReferenceQueue<Object>();
         this.disposalCallbacks = new ConcurrentHashMap<java.lang.ref.Reference<Object>, DisposalCallbackRegistryImpl>();
diff --git a/src/main/java/org/apache/sling/models/impl/ThreadInvocationCounter.java b/src/main/java/org/apache/sling/models/impl/ThreadInvocationCounter.java
new file mode 100644
index 0000000..b386aa5
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/ThreadInvocationCounter.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+class ThreadInvocationCounter {
+
+    private int count;
+
+    final int maxRecursionDepth;
+
+    public ThreadInvocationCounter(int maxRecursionDepth) {
+        this.maxRecursionDepth = maxRecursionDepth;
+    }
+
+    public boolean isMaximumReached() {
+        return count >= maxRecursionDepth;
+    }
+
+    public void increase() {
+        this.count++;
+    }
+
+    public void decrease() {
+        this.count--;
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/impl/ConstructorTest.java b/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
index 6720a16..1b46255 100644
--- a/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
@@ -19,6 +19,8 @@ package org.apache.sling.models.impl;
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
+import java.util.Hashtable;
+
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
 import org.apache.sling.models.impl.injectors.SelfInjector;
@@ -59,6 +61,7 @@ public class ConstructorTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
 
         when(request.getAttribute("attribute")).thenReturn(INT_VALUE);
         when(request.getAttribute("attribute2")).thenReturn(STRING_VALUE);
diff --git a/src/test/java/org/apache/sling/models/impl/CustomInjectorTest.java b/src/test/java/org/apache/sling/models/impl/CustomInjectorTest.java
index 046ce00..6179eb1 100644
--- a/src/test/java/org/apache/sling/models/impl/CustomInjectorTest.java
+++ b/src/test/java/org/apache/sling/models/impl/CustomInjectorTest.java
@@ -19,6 +19,8 @@ package org.apache.sling.models.impl;
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
+import java.util.Hashtable;
+
 import javax.inject.Inject;
 
 import org.apache.sling.models.annotations.Model;
@@ -47,6 +49,7 @@ public class CustomInjectorTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
 
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
diff --git a/src/test/java/org/apache/sling/models/impl/DefaultTest.java b/src/test/java/org/apache/sling/models/impl/DefaultTest.java
index 01a333f..9ef3c25 100644
--- a/src/test/java/org/apache/sling/models/impl/DefaultTest.java
+++ b/src/test/java/org/apache/sling/models/impl/DefaultTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.*;
 
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Hashtable;
 
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ValueMap;
@@ -53,6 +54,8 @@ public class DefaultTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
         factory.bindInjector(new ValueMapInjector(), new ServicePropertiesMap(0, 0));
diff --git a/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java b/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
index 2a82d7d..484beaa 100644
--- a/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
+++ b/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.*;
 
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.Map;
 
 import org.apache.sling.api.SlingHttpServletRequest;
@@ -72,6 +73,8 @@ public class InjectorSpecificAnnotationTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
 
diff --git a/src/test/java/org/apache/sling/models/impl/InvalidAdaptationsTest.java b/src/test/java/org/apache/sling/models/impl/InvalidAdaptationsTest.java
index 4c545af..4e99178 100644
--- a/src/test/java/org/apache/sling/models/impl/InvalidAdaptationsTest.java
+++ b/src/test/java/org/apache/sling/models/impl/InvalidAdaptationsTest.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Collections;
+import java.util.Hashtable;
 import java.util.Map;
 
 import org.apache.sling.api.SlingHttpServletRequest;
@@ -51,6 +52,7 @@ public class InvalidAdaptationsTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
 
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
diff --git a/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java b/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java
index 44324c5..640de65 100644
--- a/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java
+++ b/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
 import java.lang.reflect.AnnotatedElement;
+import java.util.Hashtable;
 
 import javax.inject.Inject;
 
@@ -64,6 +65,8 @@ public class MultipleInjectorTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
         bindings = new SlingBindings();
 
         factory = new ModelAdapterFactory();
diff --git a/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java b/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
index df09c52..58b46bf 100644
--- a/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
+++ b/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Matchers.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Dictionary;
+import java.util.Hashtable;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
@@ -65,6 +66,8 @@ public class OSGiInjectionTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
 
diff --git a/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java b/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
index 0fd45c5..06ef24f 100644
--- a/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
+++ b/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
@@ -22,6 +22,8 @@ import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.util.Hashtable;
+
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.models.impl.injectors.ChildResourceInjector;
@@ -51,6 +53,8 @@ public class OptionalPrimitivesTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
         factory.bindInjector(new ValueMapInjector(), new ServicePropertiesMap(2, 2));
diff --git a/src/test/java/org/apache/sling/models/impl/PostConstructTest.java b/src/test/java/org/apache/sling/models/impl/PostConstructTest.java
index 7f54f12..8e6aa75 100644
--- a/src/test/java/org/apache/sling/models/impl/PostConstructTest.java
+++ b/src/test/java/org/apache/sling/models/impl/PostConstructTest.java
@@ -19,6 +19,8 @@ package org.apache.sling.models.impl;
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
+import java.util.Hashtable;
+
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.models.testmodels.classes.SubClass;
 import org.junit.Before;
@@ -41,6 +43,7 @@ public class PostConstructTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
     }
 
     @Test
diff --git a/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java b/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
index 91dd851..4fae168 100644
--- a/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
+++ b/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
@@ -19,6 +19,8 @@ package org.apache.sling.models.impl;
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
+import java.util.Hashtable;
+
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.scripting.SlingBindings;
 import org.apache.sling.api.scripting.SlingScriptHelper;
@@ -53,6 +55,7 @@ public class RequestInjectionTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
 
         SlingBindings bindings = new SlingBindings();
         bindings.setSling(sling);
diff --git a/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java b/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
index 3f020a9..625e5a0 100644
--- a/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.*;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.Map;
 
 import org.apache.commons.lang.RandomStringUtils;
@@ -64,6 +65,7 @@ public class ResourceModelClassesTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
 
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
diff --git a/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java b/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
index 6999525..0696ff5 100644
--- a/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.*;
 
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.Map;
 
 import org.apache.commons.lang.RandomStringUtils;
@@ -59,6 +60,8 @@ public class ResourceModelInterfacesTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
         factory.bindInjector(new ValueMapInjector(), new ServicePropertiesMap(2, 2));
diff --git a/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java b/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
index 8280584..ee0cea8 100644
--- a/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
 import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.Map;
 
 import org.apache.sling.api.resource.Resource;
@@ -78,6 +79,8 @@ public class ResourcePathInjectionTest {
         ValueMap properties = new ValueMapDecorator(map);
 
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
         when(adaptable.getResourceResolver()).thenReturn(resourceResolver);
         when(adaptable.adaptTo(ValueMap.class)).thenReturn(properties);
 
diff --git a/src/test/java/org/apache/sling/models/impl/SelfDependencyTest.java b/src/test/java/org/apache/sling/models/impl/SelfDependencyTest.java
index e0e9bad..c2811f9 100644
--- a/src/test/java/org/apache/sling/models/impl/SelfDependencyTest.java
+++ b/src/test/java/org/apache/sling/models/impl/SelfDependencyTest.java
@@ -22,6 +22,8 @@ import static org.junit.Assert.assertSame;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.when;
 
+import java.util.Hashtable;
+
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.models.impl.injectors.SelfInjector;
 import org.apache.sling.models.testmodels.classes.DirectCyclicSelfDependencyModel;
@@ -57,6 +59,8 @@ public class SelfDependencyTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
         when(request.adaptTo(any(Class.class))).then(new Answer<Object>() {
             @Override
             public Object answer(InvocationOnMock invocation) throws Throwable {
diff --git a/src/test/java/org/apache/sling/models/impl/ViaTest.java b/src/test/java/org/apache/sling/models/impl/ViaTest.java
index 822e07c..a1c9af4 100644
--- a/src/test/java/org/apache/sling/models/impl/ViaTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ViaTest.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Collections;
+import java.util.Hashtable;
 
 import org.apache.commons.lang.RandomStringUtils;
 import org.apache.sling.api.SlingHttpServletRequest;
@@ -56,6 +57,8 @@ public class ViaTest {
     @Before
     public void setup() {
         when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
         when(request.getResource()).thenReturn(resource);
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);

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

[sling-org-apache-sling-models-impl] 10/24: fixing error in Sling Models test code - service ranking must be an integer to be effective

Posted by ro...@apache.org.
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 ad90196c15b9c3d7a4e45e5cfc5d78d0405db384
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Aug 22 14:18:41 2014 +0000

    fixing error in Sling Models test code - service ranking must be an integer to be effective
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1619818 13f79535-47bb-0310-9956-ffa450edef68
---
 .../java/org/apache/sling/models/impl/MultipleInjectorTest.java     | 6 +++---
 .../java/org/apache/sling/models/impl/ServicePropertiesMap.java     | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java b/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java
index 4e7c331..44324c5 100644
--- a/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java
+++ b/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java
@@ -68,9 +68,9 @@ public class MultipleInjectorTest {
 
         factory = new ModelAdapterFactory();
         factory.activate(componentCtx);
-        factory.bindInjector(bindingsInjector, new ServicePropertiesMap(2, 2));
-        factory.bindInjector(attributesInjector, new ServicePropertiesMap(1, 1));
-        factory.bindInjectAnnotationProcessorFactory(bindingsInjector, new ServicePropertiesMap(2, 2));
+        factory.bindInjector(bindingsInjector, new ServicePropertiesMap(1, 1));
+        factory.bindInjector(attributesInjector, new ServicePropertiesMap(2, 2));
+        factory.bindInjectAnnotationProcessorFactory(bindingsInjector, new ServicePropertiesMap(1, 1));
 
         when(request.getAttribute(SlingBindings.class.getName())).thenReturn(bindings);
     }
diff --git a/src/test/java/org/apache/sling/models/impl/ServicePropertiesMap.java b/src/test/java/org/apache/sling/models/impl/ServicePropertiesMap.java
index 884f61e..d424e5c 100644
--- a/src/test/java/org/apache/sling/models/impl/ServicePropertiesMap.java
+++ b/src/test/java/org/apache/sling/models/impl/ServicePropertiesMap.java
@@ -23,7 +23,7 @@ import org.osgi.framework.Constants;
 @SuppressWarnings("serial")
 public class ServicePropertiesMap extends HashMap<String, Object> {
     
-    public ServicePropertiesMap(long serviceId, long serviceRanking) {
+    public ServicePropertiesMap(long serviceId, int serviceRanking) {
         super();
         put(Constants.SERVICE_ID, serviceId);
         put(Constants.SERVICE_RANKING, serviceRanking);

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

[sling-org-apache-sling-models-impl] 12/24: SLING-3877 - adding a resource path injector. also did some minor refactoring to avoid code duplication between injectors.

Posted by ro...@apache.org.
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 a6b32c144322c49ff20c34af0111ef985339f556
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Aug 22 15:50:07 2014 +0000

    SLING-3877 - adding a resource path injector. also did some minor refactoring to avoid code duplication between injectors.
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1619848 13f79535-47bb-0310-9956-ffa450edef68
---
 .../models/impl/injectors/AbstractInjector.java    |  53 ++++++++++
 .../impl/injectors/ResourcePathInjector.java       | 117 +++++++++++++++++++++
 .../impl/injectors/ResourceResolverInjector.java   |  10 +-
 .../models/impl/injectors/ValueMapInjector.java    |  16 +--
 .../models/impl/ResourcePathInjectionTest.java     | 107 +++++++++++++++++++
 .../testmodels/classes/ResourcePathModel.java      |  62 +++++++++++
 6 files changed, 343 insertions(+), 22 deletions(-)

diff --git a/src/main/java/org/apache/sling/models/impl/injectors/AbstractInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/AbstractInjector.java
new file mode 100644
index 0000000..a472d14
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/AbstractInjector.java
@@ -0,0 +1,53 @@
+/*
+ * 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.injectors;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.adapter.Adaptable;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+
+/**
+ * Abstract base class for injectors to consolidate common functionality.
+ */
+abstract class AbstractInjector {
+
+    protected ResourceResolver getResourceResolver(Object adaptable) {
+        ResourceResolver resolver = null;
+        if (adaptable instanceof Resource) {
+            resolver = ((Resource) adaptable).getResourceResolver();
+        } else if (adaptable instanceof SlingHttpServletRequest) {
+            resolver = ((SlingHttpServletRequest) adaptable).getResourceResolver();
+        }
+        return resolver;
+    }
+
+    protected ValueMap getValueMap(Object adaptable) {
+        if (adaptable instanceof ValueMap) {
+            return (ValueMap) adaptable;
+        } else if (adaptable instanceof Adaptable) {
+            ValueMap map = ((Adaptable) adaptable).adaptTo(ValueMap.class);
+            return map;
+        } else {
+            return null;
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java
new file mode 100644
index 0000000..3bc08b9
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java
@@ -0,0 +1,117 @@
+/*
+ * 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.injectors;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.models.annotations.Path;
+import org.apache.sling.models.annotations.injectorspecific.ResourcePath;
+import org.apache.sling.models.spi.AcceptsNullName;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+import org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory;
+import org.osgi.framework.Constants;
+
+@Component
+@Service
+@Property(name = Constants.SERVICE_RANKING, intValue = 2500)
+public class ResourcePathInjector extends AbstractInjector implements Injector, AcceptsNullName,
+        InjectAnnotationProcessorFactory {
+
+    @Override
+    public String getName() {
+        return "resource-path";
+    }
+
+    @Override
+    public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element,
+            DisposalCallbackRegistry callbackRegistry) {
+        String resourcePath = null;
+        Path pathAnnotation = element.getAnnotation(Path.class);
+        if (pathAnnotation != null) {
+            resourcePath = pathAnnotation.value();
+        } else {
+            ResourcePath resourcePathAnnotation = element.getAnnotation(ResourcePath.class);
+            if (resourcePathAnnotation != null) {
+                resourcePath = resourcePathAnnotation.path();
+                if (resourcePath.isEmpty()) {
+                    resourcePath = null;
+                }
+            }
+
+            if (resourcePath == null && name != null) {
+                // try to get from value map
+                ValueMap map = getValueMap(adaptable);
+                resourcePath = map.get(name, String.class);
+            }
+        }
+
+        if (resourcePath != null) {
+            ResourceResolver resolver = getResourceResolver(adaptable);
+            if (resolver != null) {
+                return resolver.getResource(resourcePath);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public InjectAnnotationProcessor createAnnotationProcessor(Object adaptable, AnnotatedElement element) {
+        // check if the element has the expected annotation
+        ResourcePath annotation = element.getAnnotation(ResourcePath.class);
+        if (annotation != null) {
+            return new ResourcePathAnnotationProcessor(annotation, adaptable);
+        }
+        return null;
+    }
+
+    private static class ResourcePathAnnotationProcessor extends AbstractInjectAnnotationProcessor {
+
+        private final ResourcePath annotation;
+
+        public ResourcePathAnnotationProcessor(ResourcePath annotation, Object adaptable) {
+            this.annotation = annotation;
+        }
+
+        @Override
+        public String getName() {
+            // since null is not allowed as default value in annotations, the empty string means, the default should be
+            // used!
+            if (annotation.name().isEmpty()) {
+                return null;
+            }
+            return annotation.name();
+        }
+
+        @Override
+        public Boolean isOptional() {
+            return annotation.optional();
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/ResourceResolverInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/ResourceResolverInjector.java
index a84bd89..58c992e 100644
--- a/src/main/java/org/apache/sling/models/impl/injectors/ResourceResolverInjector.java
+++ b/src/main/java/org/apache/sling/models/impl/injectors/ResourceResolverInjector.java
@@ -24,8 +24,6 @@ import java.lang.reflect.Type;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.resource.Resource;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
 import org.apache.sling.models.spi.Injector;
 import org.osgi.framework.Constants;
@@ -33,7 +31,7 @@ import org.osgi.framework.Constants;
 @Component
 @Service
 @Property(name = Constants.SERVICE_RANKING, intValue = 900)
-public class ResourceResolverInjector implements Injector {
+public class ResourceResolverInjector extends AbstractInjector implements Injector {
 
     private static final String NAME_RESOURCE_RESOLVER = "resourceResolver";
 
@@ -46,11 +44,7 @@ public class ResourceResolverInjector implements Injector {
     public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element,
             DisposalCallbackRegistry callbackRegistry) {
         if (NAME_RESOURCE_RESOLVER.equals(name)) {
-            if (adaptable instanceof Resource) {
-                return ((Resource) adaptable).getResourceResolver();
-            } else if (adaptable instanceof SlingHttpServletRequest) {
-                return ((SlingHttpServletRequest) adaptable).getResourceResolver();
-            }
+            return getResourceResolver(adaptable);
         }
         return null;
     }
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 9c4a123..bda12b6 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
@@ -30,7 +30,6 @@ import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.adapter.Adaptable;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
@@ -45,7 +44,7 @@ import org.slf4j.LoggerFactory;
 @Component
 @Service
 @Property(name = Constants.SERVICE_RANKING, intValue = 2000)
-public class ValueMapInjector implements Injector, InjectAnnotationProcessorFactory {
+public class ValueMapInjector extends AbstractInjector implements Injector, InjectAnnotationProcessorFactory {
 
     private static final Logger log = LoggerFactory.getLogger(ValueMapInjector.class);
 
@@ -56,7 +55,7 @@ public class ValueMapInjector implements Injector, InjectAnnotationProcessorFact
 
     public Object getValue(Object adaptable, String name, Type type, AnnotatedElement element,
             DisposalCallbackRegistry callbackRegistry) {
-        ValueMap map = getMap(adaptable);
+        ValueMap map = getValueMap(adaptable);
         if (map == null) {
             return null;
         } else if (type instanceof Class<?>) {
@@ -112,17 +111,6 @@ public class ValueMapInjector implements Injector, InjectAnnotationProcessorFact
         }
     }
 
-    private ValueMap getMap(Object adaptable) {
-        if (adaptable instanceof ValueMap) {
-            return (ValueMap) adaptable;
-        } else if (adaptable instanceof Adaptable) {
-            ValueMap map = ((Adaptable) adaptable).adaptTo(ValueMap.class);
-            return map;
-        } else {
-            return null;
-        }
-    }
-
     private Object unwrapArray(Object wrapperArray, Class<?> primitiveType) {
         int length = Array.getLength(wrapperArray);
         Object primitiveArray = Array.newInstance(primitiveType, length);
diff --git a/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java b/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
new file mode 100644
index 0000000..8280584
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.*;
+import static org.mockito.Mockito.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.models.impl.injectors.ResourcePathInjector;
+import org.apache.sling.models.impl.injectors.SelfInjector;
+import org.apache.sling.models.impl.injectors.ValueMapInjector;
+import org.apache.sling.models.testmodels.classes.ResourcePathModel;
+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;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ResourcePathInjectionTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    private ModelAdapterFactory factory;
+
+    @Mock
+    private Resource adaptable;
+
+    @Mock
+    private Resource byPathResource;
+
+    @Mock
+    private Resource byPathResource2;
+
+    @Mock
+    private Resource byPropertyValueResource;
+
+    @Mock
+    private Resource byPropertyValueResource2;
+
+    @Mock
+    private ResourceResolver resourceResolver;
+
+    @Before
+    public void setup() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("propertyContainingAPath", "/some/other/path");
+        map.put("anotherPropertyContainingAPath", "/some/other/path2");
+
+        ValueMap properties = new ValueMapDecorator(map);
+
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(adaptable.getResourceResolver()).thenReturn(resourceResolver);
+        when(adaptable.adaptTo(ValueMap.class)).thenReturn(properties);
+
+        when(resourceResolver.getResource("/some/path")).thenReturn(byPathResource);
+        when(resourceResolver.getResource("/some/path2")).thenReturn(byPathResource2);
+        when(resourceResolver.getResource("/some/other/path")).thenReturn(byPropertyValueResource);
+        when(resourceResolver.getResource("/some/other/path2")).thenReturn(byPropertyValueResource2);
+
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(new SelfInjector(), new ServicePropertiesMap(1, Integer.MAX_VALUE));
+        factory.bindInjector(new ValueMapInjector(), new ServicePropertiesMap(2, 2000));
+        factory.bindInjector(new ResourcePathInjector(), new ServicePropertiesMap(3, 2500));
+        factory.bindInjectAnnotationProcessorFactory(new ResourcePathInjector(), new ServicePropertiesMap(3, 2500));
+    }
+
+    @Test
+    public void testPathInjection() {
+        ResourcePathModel model = factory.getAdapter(adaptable, ResourcePathModel.class);
+        assertNotNull(model);
+        assertEquals(byPathResource, model.getFromPath());
+        assertEquals(byPropertyValueResource, model.getByDerefProperty());
+        assertEquals(byPathResource2, model.getFromPath2());
+        assertEquals(byPropertyValueResource2, model.getByDerefProperty2());
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java
new file mode 100644
index 0000000..d18d4fe
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java
@@ -0,0 +1,62 @@
+/*
+ * 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 javax.inject.Named;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Path;
+import org.apache.sling.models.annotations.injectorspecific.ResourcePath;
+
+@Model(adaptables = Resource.class)
+public class ResourcePathModel {
+
+    @Inject
+    @Path("/some/path")
+    private Resource fromPath;
+
+    @Inject
+    @Named("propertyContainingAPath")
+    private Resource derefProperty;
+
+    @ResourcePath(path = "/some/path2")
+    private Resource fromPath2;
+
+    @ResourcePath(name = "anotherPropertyContainingAPath")
+    private Resource derefProperty2;
+
+    public Resource getFromPath() {
+        return fromPath;
+    }
+
+    public Resource getByDerefProperty() {
+        return derefProperty;
+    }
+
+    public Resource getFromPath2() {
+        return fromPath2;
+    }
+
+    public Resource getByDerefProperty2() {
+        return derefProperty2;
+    }
+
+}

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

[sling-org-apache-sling-models-impl] 16/24: SLING-3879 - fixing NPE in PathInjector. Thanks Stefan for the patch!

Posted by ro...@apache.org.
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 b5304a41d88d009265c5f40afbdac9654a21a610
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Mon Aug 25 11:44:46 2014 +0000

    SLING-3879 - fixing NPE in PathInjector. Thanks Stefan for the patch!
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1620296 13f79535-47bb-0310-9956-ffa450edef68
---
 .../impl/injectors/ResourcePathInjector.java       |  4 +++-
 .../models/impl/ResourcePathInjectionTest.java     | 23 ++++++++++++++++++++++
 ...odel.java => ResourcePathAllOptionalModel.java} | 12 +++++++----
 .../testmodels/classes/ResourcePathModel.java      |  3 ++-
 4 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java
index 3bc08b9..2dbfecf 100644
--- a/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java
+++ b/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java
@@ -66,7 +66,9 @@ public class ResourcePathInjector extends AbstractInjector implements Injector,
             if (resourcePath == null && name != null) {
                 // try to get from value map
                 ValueMap map = getValueMap(adaptable);
-                resourcePath = map.get(name, String.class);
+                if (map != null) {
+                    resourcePath = map.get(name, String.class);
+                }
             }
         }
 
diff --git a/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java b/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
index ee0cea8..b9d4805 100644
--- a/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
@@ -25,6 +25,7 @@ import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
 
+import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ValueMap;
@@ -32,6 +33,7 @@ import org.apache.sling.api.wrappers.ValueMapDecorator;
 import org.apache.sling.models.impl.injectors.ResourcePathInjector;
 import org.apache.sling.models.impl.injectors.SelfInjector;
 import org.apache.sling.models.impl.injectors.ValueMapInjector;
+import org.apache.sling.models.testmodels.classes.ResourcePathAllOptionalModel;
 import org.apache.sling.models.testmodels.classes.ResourcePathModel;
 import org.junit.Before;
 import org.junit.Test;
@@ -107,4 +109,25 @@ public class ResourcePathInjectionTest {
         assertEquals(byPropertyValueResource2, model.getByDerefProperty2());
     }
 
+    @Test
+    public void testPathInjectionWithNonResourceAdaptable() {
+        SlingHttpServletRequest nonResourceAdaptable = mock(SlingHttpServletRequest.class);
+        ResourcePathModel model = factory.getAdapter(nonResourceAdaptable, ResourcePathModel.class);
+        // should be null because mandatory fields could not be injected
+        assertNull(model);
+    }
+
+    @Test
+    public void testOptionalPathInjectionWithNonResourceAdaptable() {
+        SlingHttpServletRequest nonResourceAdaptable = mock(SlingHttpServletRequest.class);
+        ResourcePathAllOptionalModel model = factory.getAdapter(nonResourceAdaptable, ResourcePathAllOptionalModel.class);
+        // should not be null because resource paths fields are optional
+        assertNotNull(model);
+        // but the field itself are null
+        assertNull(model.getFromPath());
+        assertNull(model.getByDerefProperty());
+        assertNull(model.getFromPath2());
+        assertNull(model.getByDerefProperty2());
+   }
+
 }
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathAllOptionalModel.java
similarity index 81%
copy from src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java
copy to src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathAllOptionalModel.java
index d18d4fe..d3e97cb 100644
--- a/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathAllOptionalModel.java
@@ -21,26 +21,30 @@ package org.apache.sling.models.testmodels.classes;
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Optional;
 import org.apache.sling.models.annotations.Path;
 import org.apache.sling.models.annotations.injectorspecific.ResourcePath;
 
-@Model(adaptables = Resource.class)
-public class ResourcePathModel {
+@Model(adaptables = {Resource.class, SlingHttpServletRequest.class})
+public class ResourcePathAllOptionalModel {
 
     @Inject
     @Path("/some/path")
+    @Optional
     private Resource fromPath;
 
     @Inject
     @Named("propertyContainingAPath")
+    @Optional
     private Resource derefProperty;
 
-    @ResourcePath(path = "/some/path2")
+    @ResourcePath(path = "/some/path2", optional=true)
     private Resource fromPath2;
 
-    @ResourcePath(name = "anotherPropertyContainingAPath")
+    @ResourcePath(name = "anotherPropertyContainingAPath", optional=true)
     private Resource derefProperty2;
 
     public Resource getFromPath() {
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java
index d18d4fe..ec23150 100644
--- a/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java
@@ -21,12 +21,13 @@ package org.apache.sling.models.testmodels.classes;
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.models.annotations.Model;
 import org.apache.sling.models.annotations.Path;
 import org.apache.sling.models.annotations.injectorspecific.ResourcePath;
 
-@Model(adaptables = Resource.class)
+@Model(adaptables = {Resource.class, SlingHttpServletRequest.class})
 public class ResourcePathModel {
 
     @Inject

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

[sling-org-apache-sling-models-impl] 15/24: SLING-3715 - adding sling object injector. Thanks to Stefan for the patch!

Posted by ro...@apache.org.
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 ead97d031c7def96ca0836cf9ecba2dff72d3d05
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Sun Aug 24 19:09:39 2014 +0000

    SLING-3715 - adding sling object injector. Thanks to Stefan for the patch!
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1620175 13f79535-47bb-0310-9956-ffa450edef68
---
 .../models/impl/injectors/SlingObjectInjector.java | 196 +++++++++++++++++++++
 .../injectors/SlingObjectInjectorRequestTest.java  | 120 +++++++++++++
 .../SlingObjectInjectorResourceResolverTest.java   |  87 +++++++++
 .../injectors/SlingObjectInjectorResourceTest.java | 102 +++++++++++
 4 files changed, 505 insertions(+)

diff --git a/src/main/java/org/apache/sling/models/impl/injectors/SlingObjectInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/SlingObjectInjector.java
new file mode 100644
index 0000000..79e081b
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/SlingObjectInjector.java
@@ -0,0 +1,196 @@
+/*
+ * 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.injectors;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.models.annotations.injectorspecific.SlingObject;
+import org.apache.sling.models.spi.AcceptsNullName;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+import org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory;
+import org.osgi.framework.Constants;
+
+/**
+ * Injects common Sling objects that can be derived from either a SlingHttpServletRequest, a ResourceResolver or a
+ * Resource.
+ * The injection is class-based.
+ * <p>
+ * Supports the following objects:
+ * <table>
+ * <tr>
+ * <th style="text-align:left">Class</th>
+ * <th style="text-align:left">Description</th>
+ * <th style="text-align:center">Request</th>
+ * <th style="text-align:center">ResourceResolver</th>
+ * <th style="text-align:center">Resource</th>
+ * </tr>
+ * <tr style="background-color:#eee">
+ * <td>{@link ResourceResolver}</td>
+ * <td>Resource resolver</td>
+ * <td style="text-align:center">X</td>
+ * <td style="text-align:center">X</td>
+ * <td style="text-align:center">X</td>
+ * </tr>
+ * <tr>
+ * <td>{@link Resource}</td>
+ * <td>Resource</td>
+ * <td style="text-align:center">X</td>
+ * <td></td>
+ * <td style="text-align:center">X</td>
+ * </tr>
+ * <tr style="background-color:#eee">
+ * <td>{@link SlingHttpServletRequest}</td>
+ * <td>Sling request</td>
+ * <td style="text-align:center">X</td>
+ * <td></td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td>{@link SlingHttpServletResponse}</td>
+ * <td>Sling response</td>
+ * <td style="text-align:center">X</td>
+ * <td></td>
+ * <td></td>
+ * </tr>
+ * <tr style="background-color:#eee">
+ * <td>{@link SlingScriptHelper}</td>
+ * <td>Sling script helper</td>
+ * <td style="text-align:center">X</td>
+ * <td></td>
+ * <td></td>
+ * </tr>
+ * </table>
+ */
+@Component
+@Service
+@Property(name = Constants.SERVICE_RANKING, intValue = Integer.MAX_VALUE)
+public final class SlingObjectInjector implements Injector, InjectAnnotationProcessorFactory, AcceptsNullName {
+
+    /**
+     * Injector name
+     */
+    public static final String NAME = "sling-object";
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public Object getValue(final Object adaptable, final String name, final Type type, final AnnotatedElement element,
+            final DisposalCallbackRegistry callbackRegistry) {
+
+        // only class types are supported
+        if (!(type instanceof Class<?>)) {
+            return null;
+        }
+        Class<?> requestedClass = (Class<?>) type;
+
+        // validate input
+        if (adaptable instanceof SlingHttpServletRequest) {
+            SlingHttpServletRequest request = (SlingHttpServletRequest) adaptable;
+            if (requestedClass.equals(ResourceResolver.class)) {
+                return request.getResourceResolver();
+            }
+            if (requestedClass.equals(Resource.class) && element.isAnnotationPresent(SlingObject.class)) {
+                return request.getResource();
+            }
+            if (requestedClass.equals(SlingHttpServletRequest.class) || requestedClass.equals(HttpServletRequest.class)) {
+                return request;
+            }
+            if (requestedClass.equals(SlingHttpServletResponse.class)
+                    || requestedClass.equals(HttpServletResponse.class)) {
+                return getSlingHttpServletResponse(request);
+            }
+            if (requestedClass.equals(SlingScriptHelper.class)) {
+                return getSlingScriptHelper(request);
+            }
+        } else if (adaptable instanceof ResourceResolver) {
+            ResourceResolver resourceResolver = (ResourceResolver) adaptable;
+            if (requestedClass.equals(ResourceResolver.class)) {
+                return resourceResolver;
+            }
+        } else if (adaptable instanceof Resource) {
+            Resource resource = (Resource) adaptable;
+            if (requestedClass.equals(ResourceResolver.class)) {
+                return resource.getResourceResolver();
+            }
+            if (requestedClass.equals(Resource.class) && element.isAnnotationPresent(SlingObject.class)) {
+                return resource;
+            }
+        }
+
+        return null;
+    }
+
+    private SlingScriptHelper getSlingScriptHelper(final SlingHttpServletRequest request) {
+        SlingBindings bindings = (SlingBindings) request.getAttribute(SlingBindings.class.getName());
+        if (bindings != null) {
+            return bindings.getSling();
+        }
+        return null;
+    }
+
+    private SlingHttpServletResponse getSlingHttpServletResponse(final SlingHttpServletRequest request) {
+        SlingScriptHelper scriptHelper = getSlingScriptHelper(request);
+        if (scriptHelper != null) {
+            return scriptHelper.getResponse();
+        }
+        return null;
+    }
+
+    @Override
+    public InjectAnnotationProcessor createAnnotationProcessor(final Object adaptable, final AnnotatedElement element) {
+        // check if the element has the expected annotation
+        SlingObject annotation = element.getAnnotation(SlingObject.class);
+        if (annotation != null) {
+            return new SlingObjectAnnotationProcessor(annotation);
+        }
+        return null;
+    }
+
+    private static class SlingObjectAnnotationProcessor extends AbstractInjectAnnotationProcessor {
+
+        private final SlingObject annotation;
+
+        public SlingObjectAnnotationProcessor(final SlingObject annotation) {
+            this.annotation = annotation;
+        }
+
+        @Override
+        public Boolean isOptional() {
+            return this.annotation.optional();
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/SlingObjectInjectorRequestTest.java b/src/test/java/org/apache/sling/models/impl/injectors/SlingObjectInjectorRequestTest.java
new file mode 100644
index 0000000..89e72fd
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/injectors/SlingObjectInjectorRequestTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.injectors;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.lang.reflect.AnnotatedElement;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.models.annotations.injectorspecific.SlingObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
+public class SlingObjectInjectorRequestTest {
+
+    private final SlingObjectInjector injector = new SlingObjectInjector();
+
+    @Mock
+    private AnnotatedElement annotatedElement;
+    @Mock
+    private SlingHttpServletRequest request;
+    @Mock
+    private SlingHttpServletResponse response;
+    @Mock
+    private SlingScriptHelper scriptHelper;
+    @Mock
+    private ResourceResolver resourceResolver;
+    @Mock
+    private Resource resource;
+
+    @Before
+    public void setUp() {
+        SlingBindings bindings = new SlingBindings();
+        bindings.put(SlingBindings.SLING, this.scriptHelper);
+        when(this.request.getResourceResolver()).thenReturn(this.resourceResolver);
+        when(this.request.getResource()).thenReturn(this.resource);
+        when(this.request.getAttribute(SlingBindings.class.getName())).thenReturn(bindings);
+        when(this.scriptHelper.getResponse()).thenReturn(this.response);
+    }
+
+    @Test
+    public void testResourceResolver() {
+        Object result = this.injector.getValue(this.request, null, ResourceResolver.class, this.annotatedElement, null);
+        assertSame(this.resourceResolver, result);
+    }
+
+    @Test
+    public void testResource() {
+        Object result = this.injector.getValue(this.request, null, Resource.class, this.annotatedElement, null);
+        assertNull(result);
+
+        when(annotatedElement.isAnnotationPresent(SlingObject.class)).thenReturn(true);
+        result = this.injector.getValue(this.request, null, Resource.class, this.annotatedElement, null);
+        assertSame(resource, result);
+    }
+
+    @Test
+    public void testRequest() {
+        Object result = this.injector.getValue(this.request, null, SlingHttpServletRequest.class,
+                this.annotatedElement, null);
+        assertSame(this.request, result);
+
+        result = this.injector.getValue(this.request, null, HttpServletRequest.class, this.annotatedElement, null);
+        assertSame(this.request, result);
+    }
+
+    @Test
+    public void testResponse() {
+        Object result = this.injector.getValue(this.request, null, SlingHttpServletResponse.class,
+                this.annotatedElement, null);
+        assertSame(this.response, result);
+
+        result = this.injector.getValue(this.request, null, HttpServletResponse.class, this.annotatedElement, null);
+        assertSame(this.response, result);
+    }
+
+    @Test
+    public void testScriptHelper() {
+        Object result = this.injector
+                .getValue(this.request, null, SlingScriptHelper.class, this.annotatedElement, null);
+        assertSame(this.scriptHelper, result);
+    }
+
+    @Test
+    public void testInvalid() {
+        Object result = this.injector.getValue(this, null, SlingScriptHelper.class, this.annotatedElement, null);
+        assertNull(result);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/SlingObjectInjectorResourceResolverTest.java b/src/test/java/org/apache/sling/models/impl/injectors/SlingObjectInjectorResourceResolverTest.java
new file mode 100644
index 0000000..c9338fa
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/injectors/SlingObjectInjectorResourceResolverTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.injectors;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.lang.reflect.AnnotatedElement;
+
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
+public class SlingObjectInjectorResourceResolverTest {
+
+    private final SlingObjectInjector injector = new SlingObjectInjector();
+
+    @Mock
+    private AnnotatedElement annotatedElement;
+    @Mock
+    private ResourceResolver resourceResolver;
+
+    @Test
+    public void testResourceResolver() {
+        Object result = this.injector.getValue(this.resourceResolver, null, ResourceResolver.class,
+                this.annotatedElement, null);
+        assertSame(this.resourceResolver, result);
+    }
+
+    @Test
+    public void testResource() {
+        Object result = this.injector
+                .getValue(this.resourceResolver, null, Resource.class, this.annotatedElement, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testRequest() {
+        Object result = this.injector.getValue(this.resourceResolver, null, SlingHttpServletResponse.class,
+                this.annotatedElement, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testResponse() {
+        Object result = this.injector.getValue(this.resourceResolver, null, SlingHttpServletResponse.class,
+                this.annotatedElement, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testScriptHelper() {
+        Object result = this.injector.getValue(this.resourceResolver, null, SlingScriptHelper.class,
+                this.annotatedElement, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testInvalid() {
+        Object result = this.injector.getValue(this, null, SlingScriptHelper.class, this.annotatedElement, null);
+        assertNull(result);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/SlingObjectInjectorResourceTest.java b/src/test/java/org/apache/sling/models/impl/injectors/SlingObjectInjectorResourceTest.java
new file mode 100644
index 0000000..7ffb698
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/injectors/SlingObjectInjectorResourceTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.injectors;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.AnnotatedElement;
+
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.models.annotations.injectorspecific.SlingObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
+public class SlingObjectInjectorResourceTest {
+
+    private final SlingObjectInjector injector = new SlingObjectInjector();
+
+    @Mock
+    private AnnotatedElement annotatedElement;
+
+    @Mock
+    private ResourceResolver resourceResolver;
+
+    @Mock
+    private Resource resource;
+
+    @Before
+    public void setUp() {
+        when(this.resource.getResourceResolver()).thenReturn(this.resourceResolver);
+    }
+
+    @Test
+    public void testResourceResolver() {
+        Object result = this.injector
+                .getValue(this.resource, null, ResourceResolver.class, this.annotatedElement, null);
+        assertSame(this.resourceResolver, result);
+    }
+
+    @Test
+    public void testResource() {
+        Object result = this.injector.getValue(this.resource, null, Resource.class, this.annotatedElement, null);
+        assertNull(result);
+
+        when(annotatedElement.isAnnotationPresent(SlingObject.class)).thenReturn(true);
+        result = this.injector.getValue(this.resource, null, Resource.class, this.annotatedElement, null);
+        assertSame(resource, result);
+    }
+
+    @Test
+    public void testRequest() {
+        Object result = this.injector.getValue(this.resource, null, SlingHttpServletResponse.class,
+                this.annotatedElement, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testResponse() {
+        Object result = this.injector.getValue(this.resource, null, SlingHttpServletResponse.class,
+                this.annotatedElement, null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testScriptHelper() {
+        Object result = this.injector.getValue(this.resource, null, SlingScriptHelper.class, this.annotatedElement,
+                null);
+        assertNull(result);
+    }
+
+    @Test
+    public void testInvalid() {
+        Object result = this.injector.getValue(this, null, SlingScriptHelper.class, this.annotatedElement, null);
+        assertNull(result);
+    }
+
+}

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

[sling-org-apache-sling-models-impl] 04/24: Updated to parent version 20

Posted by ro...@apache.org.
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 415473150cd7e917902730be9bd988a7dad1abce
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Fri Aug 1 19:16:26 2014 +0000

    Updated to parent version 20
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1615208 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 2ad22da..94c9d3c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
-        <version>19</version>
+        <version>20</version>
         <relativePath>../../../../parent/pom.xml</relativePath>
     </parent>
     <groupId>org.apache.sling</groupId>

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

[sling-org-apache-sling-models-impl] 20/24: SLING-3897 - fixing synchronization block error

Posted by ro...@apache.org.
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 db87d4023721277d654daeca5ff579db4e5cc240
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Aug 29 11:41:59 2014 +0000

    SLING-3897 - fixing synchronization block error
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1621289 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java | 4 ++--
 1 file changed, 2 insertions(+), 2 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 6ae52c4..a749875 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -949,14 +949,14 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
     }
 
     protected void bindInjectAnnotationProcessorFactory(final InjectAnnotationProcessorFactory injector, final Map<String, Object> props) {
-        synchronized (injectors) {
+        synchronized (injectAnnotationProcessorFactories) {
             injectAnnotationProcessorFactories.put(ServiceUtil.getComparableForServiceRanking(props), injector);
             sortedInjectAnnotationProcessorFactories = injectAnnotationProcessorFactories.values().toArray(new InjectAnnotationProcessorFactory[injectAnnotationProcessorFactories.size()]);
         }
     }
 
     protected void unbindInjectAnnotationProcessorFactory(final InjectAnnotationProcessorFactory injector, final Map<String, Object> props) {
-        synchronized (injectors) {
+        synchronized (injectAnnotationProcessorFactories) {
             injectAnnotationProcessorFactories.remove(ServiceUtil.getComparableForServiceRanking(props));
             sortedInjectAnnotationProcessorFactories = injectAnnotationProcessorFactories.values().toArray(new InjectAnnotationProcessorFactory[injectAnnotationProcessorFactories.size()]);
         }

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

[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!

Posted by ro...@apache.org.
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>.

[sling-org-apache-sling-models-impl] 23/24: [maven-release-plugin] prepare release org.apache.sling.models.impl-1.1.0

Posted by ro...@apache.org.
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 2f179b1cb2bf3df97bcca7ab2558c3e3d69ba372
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Tue Sep 2 19:14:41 2014 +0000

    [maven-release-plugin] prepare release org.apache.sling.models.impl-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1622101 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 9591f4f..054e108 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,16 +28,16 @@
     <groupId>org.apache.sling</groupId>
     <artifactId>org.apache.sling.models.impl</artifactId>
     <packaging>bundle</packaging>
-    <version>1.0.7-SNAPSHOT</version>
+    <version>1.1.0</version>
     <name>Apache Sling Models Implementation</name>
     <description>Apache Sling Models Implementation</description>
     <properties>
         <sling.java.version>6</sling.java.version>
     </properties>
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl</connection>
-        <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.models.impl-1.1.0</connection>
+        <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.models.impl-1.1.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.models.impl-1.1.0</url>
     </scm>
     <build>
         <plugins>

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

[sling-org-apache-sling-models-impl] 09/24: SLING-3869 - fixing branding issues with Sling Models. Thanks to Stefan Seifert for the patch!

Posted by ro...@apache.org.
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 9c6fb1eddb3a759945ab83fe87eed2c66b7bdb51
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Thu Aug 21 20:46:36 2014 +0000

    SLING-3869 - fixing branding issues with Sling Models. Thanks to Stefan Seifert for the patch!
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1619575 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 426fb1d..37f20bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,8 +29,8 @@
     <artifactId>org.apache.sling.models.impl</artifactId>
     <packaging>bundle</packaging>
     <version>1.0.7-SNAPSHOT</version>
-    <name>Sling Models Implementation</name>
-    <description>Sling Models Implementation</description>
+    <name>Apache Sling Models Implementation</name>
+    <description>Apache Sling Models Implementation</description>
     <properties>
         <sling.java.version>6</sling.java.version>
     </properties>

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

[sling-org-apache-sling-models-impl] 19/24: SLING-3897 - fixing copy&paste error in unbind method. Thanks to Stefan for the patch!

Posted by ro...@apache.org.
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 8fd239ec6fa8e8458197ede3062da77a3785ddaf
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Aug 29 11:32:05 2014 +0000

    SLING-3897 - fixing copy&paste error in unbind method. Thanks to Stefan for the patch!
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1621286 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 7d00ba8..6ae52c4 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -958,7 +958,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
     protected void unbindInjectAnnotationProcessorFactory(final InjectAnnotationProcessorFactory injector, final Map<String, Object> props) {
         synchronized (injectors) {
             injectAnnotationProcessorFactories.remove(ServiceUtil.getComparableForServiceRanking(props));
-            sortedInjectAnnotationProcessorFactories = injectors.values().toArray(new InjectAnnotationProcessorFactory[injectAnnotationProcessorFactories.size()]);
+            sortedInjectAnnotationProcessorFactories = injectAnnotationProcessorFactories.values().toArray(new InjectAnnotationProcessorFactory[injectAnnotationProcessorFactories.size()]);
         }
     }
 

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

[sling-org-apache-sling-models-impl] 06/24: SLING-3861 - adding condition option for @Model annotation

Posted by ro...@apache.org.
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 50603754d94388ef9141859fa683b0738a1c8e46
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Wed Aug 20 16:02:38 2014 +0000

    SLING-3861 - adding condition option for @Model annotation
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1619134 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/models/impl/ModelPackageBundleListener.java   | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java b/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
index f15ba38..9e9c908 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
@@ -40,6 +40,11 @@ public class ModelPackageBundleListener implements BundleTrackerCustomizer {
 
     private static final String HEADER = "Sling-Model-Packages";
 
+    /**
+     * Service registration property for the adapter condition.
+     */
+    private static final String PROP_ADAPTER_CONDITION = "adapter.condition";
+
     private static final Logger log = LoggerFactory.getLogger(ModelPackageBundleListener.class);
     
     private final BundleContext bundleContext;
@@ -87,6 +92,11 @@ public class ModelPackageBundleListener implements BundleTrackerCustomizer {
                             Dictionary<String, Object> registrationProps = new Hashtable<String, Object>();
                             registrationProps.put(AdapterFactory.ADAPTER_CLASSES, className);
                             registrationProps.put(AdapterFactory.ADAPTABLE_CLASSES, classNames);
+
+                            String condition = annotation.condition();
+                            if (StringUtils.isNotBlank(condition)) {
+                                registrationProps.put(PROP_ADAPTER_CONDITION, condition);
+                            }
                             ServiceRegistration reg = bundleContext.registerService(AdapterFactory.SERVICE_NAME,
                                     factory, registrationProps);
                             regs.add(reg);

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

[sling-org-apache-sling-models-impl] 21/24: SLING-3886 - adding support for adapter indirection where the adapting target is a superclass or implemented interface of the implementation class. Thanks to Stefan for the patch!

Posted by ro...@apache.org.
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 d3879008bbd614fb565821121cb7ae196dc36b2a
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Aug 29 18:53:41 2014 +0000

    SLING-3886 - adding support for adapter indirection where the adapting target is a superclass or implemented interface of the implementation class. Thanks to Stefan for the patch!
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1621361 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/models/impl/AdapterImplementations.java  | 120 ++++++++++
 .../models/impl/FirstImplementationPicker.java     |  45 ++++
 .../sling/models/impl/ModelAdapterFactory.java     |  38 +++-
 .../models/impl/ModelConfigurationPrinter.java     |  22 +-
 .../models/impl/ModelPackageBundleListener.java    |  97 ++++++--
 .../models/impl/AdapterImplementationsTest.java    | 125 ++++++++++
 .../sling/models/impl/ImplementsExtendsTest.java   | 253 +++++++++++++++++++++
 .../implpicker/FirstImplementationPickerTest.java  |  52 +++++
 .../implextend/EvenSimplerPropertyModel.java       |  14 ++
 .../implextend/ExtendsClassPropertyModel.java      |  34 +++
 .../ImplementsInterfacePropertyModel.java          |  55 +++++
 .../ImplementsInterfacePropertyModel2.java         |  54 +++++
 .../InvalidImplementsInterfacePropertyModel.java   |  54 +++++
 .../implextend/InvalidSampleServiceInterface.java  |  31 +++
 .../classes/implextend/SampleServiceInterface.java |  31 +++
 .../classes/implextend/SimplePropertyModel.java    |  47 ++++
 16 files changed, 1048 insertions(+), 24 deletions(-)

diff --git a/src/main/java/org/apache/sling/models/impl/AdapterImplementations.java b/src/main/java/org/apache/sling/models/impl/AdapterImplementations.java
new file mode 100644
index 0000000..2ee3a91
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/AdapterImplementations.java
@@ -0,0 +1,120 @@
+/*
+ * 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.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+
+import org.apache.sling.models.spi.ImplementationPicker;
+
+/**
+ * Collects alternative adapter implementations that may be defined in a @Model.adapters attribute.
+ * If multiple models implement the same adapter they are all collected and can be chose via a ImplementationPicker.
+ * The implementation is thread-safe.
+ */
+final class AdapterImplementations {
+    
+    private final ConcurrentMap<String,ConcurrentNavigableMap<String,Class<?>>> adapterImplementations
+            = new ConcurrentHashMap<String,ConcurrentNavigableMap<String,Class<?>>>();
+
+    private volatile ImplementationPicker[] sortedImplementationPickers = new ImplementationPicker[0];
+
+    public void setImplementationPickers(Collection<ImplementationPicker> implementationPickers) {
+        this.sortedImplementationPickers = implementationPickers.toArray(new ImplementationPicker[implementationPickers.size()]);
+    }
+
+    public ImplementationPicker[] getImplementationPickers() {
+        return this.sortedImplementationPickers;
+    }
+
+    /**
+     * Add implementation mapping for the given adapter type.
+     * @param adapterType Adapter type
+     * @param implType Implementation type
+     */
+    public void add(Class<?> adapterType, Class<?> implType) {
+        // although we already use a ConcurrentMap synchronize explicitly because we apply non-atomic operations on it
+        synchronized (adapterImplementations) {
+            String key = adapterType.getName();
+            ConcurrentNavigableMap<String,Class<?>> implementations = adapterImplementations.get(key);
+            if (implementations == null) {
+                // to have a consistent ordering independent of bundle loading use a ConcurrentSkipListMap that sorts by class name
+                implementations = new ConcurrentSkipListMap<String,Class<?>>();
+                adapterImplementations.put(key, implementations);
+            }
+            implementations.put(implType.getName(), implType);
+        }
+    }
+    
+    /**
+     * Remove implementation mapping for the given adapter type.
+     * @param adapterTypeName Adapter type name
+     * @param implTypeName Implementation type name
+     */
+    public void remove(String adapterTypeName, String implTypeName) {
+        // although we already use a ConcurrentMap synchronize explicitly because we apply non-atomic operations on it
+        synchronized (adapterImplementations) {
+            String key = adapterTypeName;
+            ConcurrentNavigableMap<String,Class<?>> implementations = adapterImplementations.get(key);
+            if (implementations!=null) {
+                implementations.remove(implTypeName);
+                if (implementations.isEmpty()) {
+                    adapterImplementations.remove(key);
+                }
+            }
+        }
+    }
+
+    /**
+     * Remove all implementation mappings.
+     */
+    public void removeAll() {
+        adapterImplementations.clear();
+    }
+
+    /**
+     * Lookup the best-matching implementation for the given adapter type by enquiring the {@link ImplementationPicker} services.
+     * @param adapterType Adapter type
+     * @param adaptable Adaptable for reference
+     * @return Implementation type or null if none detected
+     */
+    public Class<?> lookup(Class<?> adapterType, Object adaptable) {
+        String key = adapterType.getName();
+
+        ConcurrentNavigableMap<String,Class<?>> implementations = adapterImplementations.get(key);
+        if (implementations==null || implementations.isEmpty()) {
+            return null;
+        }
+        Collection<Class<?>> implementationsCollection = implementations.values();
+        Class<?>[] implementationsArray = implementationsCollection.toArray(new Class<?>[implementationsCollection.size()]);
+
+        for (ImplementationPicker picker : this.sortedImplementationPickers) {
+            Class<?> implementation = picker.pick(adapterType, implementationsArray, adaptable);
+            if (implementation != null) {
+                return implementation;
+            }
+        }
+
+        return null;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/models/impl/FirstImplementationPicker.java b/src/main/java/org/apache/sling/models/impl/FirstImplementationPicker.java
new file mode 100644
index 0000000..230ba2c
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/FirstImplementationPicker.java
@@ -0,0 +1,45 @@
+/*
+ * 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 org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.models.spi.ImplementationPicker;
+import org.osgi.framework.Constants;
+
+/**
+ * Picks first implementation.
+ * This is the default implementation which is not very intelligent because it just picks
+ * the first implementation from the list that is alphabetically ordered by class name.
+ * But at least it gives a consistent behavior.
+ * It's service ranking is set to the highest value to allow more intelligent implementations to step in.
+ */
+@Component
+@Service
+@Property(name = Constants.SERVICE_RANKING, intValue = Integer.MAX_VALUE)
+public class FirstImplementationPicker implements ImplementationPicker {
+
+    @Override
+    public Class<?> pick(Class<?> adapterType, Class<?>[] implementationsTypes, Object adaptable) {
+        // implementations is never null or empty
+        return implementationsTypes[0];
+    }
+
+}
\ No newline at end of file
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 a749875..41b2c87 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -69,9 +69,10 @@ 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.AcceptsNullName;
 import org.apache.sling.models.spi.DisposalCallback;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
-import org.apache.sling.models.spi.AcceptsNullName;
+import org.apache.sling.models.spi.ImplementationPicker;
 import org.apache.sling.models.spi.Injector;
 import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
 import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
@@ -141,7 +142,13 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     private volatile InjectAnnotationProcessorFactory[] sortedInjectAnnotationProcessorFactories = new InjectAnnotationProcessorFactory[0];
 
-    private ModelPackageBundleListener listener;
+    @Reference(name = "implementationPicker", referenceInterface = ImplementationPicker.class,
+            cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
+    private final Map<Object, ImplementationPicker> implementationPickers = new TreeMap<Object, ImplementationPicker>();
+
+    ModelPackageBundleListener listener;
+    
+    final AdapterImplementations adapterImplementations = new AdapterImplementations();
 
     private ServiceRegistration jobRegistration;
 
@@ -160,6 +167,12 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         };
         threadInvocationCounter.increase();
         try {
+            // check if a different implementation class was registered for this adapter type
+            Class<?> implementationType = this.adapterImplementations.lookup(type, adaptable);
+            if (implementationType != null) {
+                type = (Class<AdapterType>) implementationType;
+            }
+
             Model modelAnnotation = type.getAnnotation(Model.class);
             if (modelAnnotation == null) {
                 return null;
@@ -908,7 +921,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
         this.jobRegistration = bundleContext.registerService(Runnable.class.getName(), this, properties);
 
-        this.listener = new ModelPackageBundleListener(ctx.getBundleContext(), this);
+        this.listener = new ModelPackageBundleListener(ctx.getBundleContext(), this, this.adapterImplementations);
 
         Hashtable<Object, Object> printerProps = new Hashtable<Object, Object>();
         printerProps.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
@@ -924,6 +937,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
     @Deactivate
     protected void deactivate() {
         this.listener.unregisterAll();
+        this.adapterImplementations.removeAll();
         if (jobRegistration != null) {
             jobRegistration.unregister();
             jobRegistration = null;
@@ -962,6 +976,20 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         }
     }
 
+    protected void bindImplementationPicker(final ImplementationPicker implementationPicker, final Map<String, Object> props) {
+        synchronized (implementationPickers) {
+            implementationPickers.put(ServiceUtil.getComparableForServiceRanking(props), implementationPicker);
+            this.adapterImplementations.setImplementationPickers(implementationPickers.values());
+        }
+    }
+
+    protected void unbindImplementationPicker(final ImplementationPicker implementationPicker, final Map<String, Object> props) {
+        synchronized (implementationPickers) {
+            implementationPickers.remove(ServiceUtil.getComparableForServiceRanking(props));
+            this.adapterImplementations.setImplementationPickers(implementationPickers.values());
+        }
+    }
+
     Injector[] getInjectors() {
         return sortedInjectors;
     }
@@ -970,4 +998,8 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         return sortedInjectAnnotationProcessorFactories;
     }
 
+    ImplementationPicker[] getImplementationPickers() {
+        return adapterImplementations.getImplementationPickers();
+    }
+
 }
diff --git a/src/main/java/org/apache/sling/models/impl/ModelConfigurationPrinter.java b/src/main/java/org/apache/sling/models/impl/ModelConfigurationPrinter.java
index 67e754b..97ef951 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelConfigurationPrinter.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelConfigurationPrinter.java
@@ -18,6 +18,7 @@ package org.apache.sling.models.impl;
 
 import java.io.PrintWriter;
 
+import org.apache.sling.models.spi.ImplementationPicker;
 import org.apache.sling.models.spi.Injector;
 import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory;
 
@@ -30,9 +31,11 @@ public class ModelConfigurationPrinter {
     }
 
     public void printConfiguration(PrintWriter printWriter) {
+        
+        // injectors
         printWriter.println("Sling Models Injectors:");
         Injector[] injectors = modelAdapterFactory.getInjectors();
-        if (injectors == null) {
+        if (injectors == null || injectors.length == 0) {
             printWriter.println("none");
         } else {
             for (Injector injector : injectors) {
@@ -41,9 +44,11 @@ public class ModelConfigurationPrinter {
             }
         }
         printWriter.println();
+        
+        // inject annotations processor factories
         printWriter.println("Sling Models Inject Annotation Processor Factories:");
         InjectAnnotationProcessorFactory[] factories = modelAdapterFactory.getInjectAnnotationProcessorFactories();
-        if (factories == null) {
+        if (factories == null || factories.length == 0) {
             printWriter.println("none");
         } else {
             for (InjectAnnotationProcessorFactory factory : factories) {
@@ -51,6 +56,19 @@ public class ModelConfigurationPrinter {
                 printWriter.println();
             }
         }
+        printWriter.println();
+        
+        // implementation pickers
+        printWriter.println("Sling Models Implementation Pickers:");
+        ImplementationPicker[] pickers = modelAdapterFactory.getImplementationPickers();
+        if (pickers == null || pickers.length == 0) {
+            printWriter.println("none");
+        } else {
+            for (ImplementationPicker picker : pickers) {
+                printWriter.printf("%s", picker.getClass().getName());
+                printWriter.println();
+            }
+        }
     }
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java b/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
index 9e9c908..f249fb8 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
@@ -30,6 +30,7 @@ import org.apache.sling.models.annotations.Model;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.util.tracker.BundleTracker;
 import org.osgi.util.tracker.BundleTrackerCustomizer;
@@ -38,24 +39,34 @@ import org.slf4j.LoggerFactory;
 
 public class ModelPackageBundleListener implements BundleTrackerCustomizer {
 
-    private static final String HEADER = "Sling-Model-Packages";
-
+    static final String HEADER = "Sling-Model-Packages";
+    
     /**
      * Service registration property for the adapter condition.
      */
     private static final String PROP_ADAPTER_CONDITION = "adapter.condition";
 
+    /**
+     * The model implementation class that initiated the service registration.
+     */
+    private static final String PROP_IMPLEMENTATION_CLASS = "models.adapter.implementationClass";
+
     private static final Logger log = LoggerFactory.getLogger(ModelPackageBundleListener.class);
-    
+
     private final BundleContext bundleContext;
 
     private final BundleTracker bundleTracker;
 
     private final AdapterFactory factory;
     
-    public ModelPackageBundleListener(BundleContext bundleContext, AdapterFactory factory) {
+    private final AdapterImplementations adapterImplementations;
+    
+    public ModelPackageBundleListener(BundleContext bundleContext,
+            AdapterFactory factory,
+            AdapterImplementations adapterImplementations) {
         this.bundleContext = bundleContext;
         this.factory = factory;
+        this.adapterImplementations = adapterImplementations;
         this.bundleTracker = new BundleTracker(bundleContext, Bundle.ACTIVE, this);
         this.bundleTracker.open();
     }
@@ -84,22 +95,25 @@ public class ModelPackageBundleListener implements BundleTrackerCustomizer {
                     URL url = classUrls.nextElement();
                     String className = toClassName(url);
                     try {
-                        Class<?> clazz = bundle.loadClass(className);
-                        Model annotation = clazz.getAnnotation(Model.class);
+                        Class<?> implType = bundle.loadClass(className);
+                        Model annotation = implType.getAnnotation(Model.class);
                         if (annotation != null) {
-                            Class<?>[] adaptables = annotation.adaptables();
-                            String[] classNames = toStringArray(adaptables);
-                            Dictionary<String, Object> registrationProps = new Hashtable<String, Object>();
-                            registrationProps.put(AdapterFactory.ADAPTER_CLASSES, className);
-                            registrationProps.put(AdapterFactory.ADAPTABLE_CLASSES, classNames);
-
-                            String condition = annotation.condition();
-                            if (StringUtils.isNotBlank(condition)) {
-                                registrationProps.put(PROP_ADAPTER_CONDITION, condition);
+                            
+                            // get list of adapters from annotation - if not given use annotated class itself
+                            Class<?>[] adapterTypes = annotation.adapters();
+                            if (adapterTypes.length == 0) {
+                                adapterTypes = new Class<?>[] { implType };
+                            }
+                            // register adapter only if given adapters are valid
+                            if (validateAdapterClasses(implType, adapterTypes)) {
+                                for (Class<?> adapterType : adapterTypes) {
+                                    if (adapterType != implType) {
+                                        adapterImplementations.add(adapterType, implType);
+                                    }
+                                }
+                                ServiceRegistration reg = registerAdapterFactory(adapterTypes, annotation.adaptables(), implType, annotation.condition());
+                                regs.add(reg);
                             }
-                            ServiceRegistration reg = bundleContext.registerService(AdapterFactory.SERVICE_NAME,
-                                    factory, registrationProps);
-                            regs.add(reg);
                         }
                     } catch (ClassNotFoundException e) {
                         log.warn("Unable to load class", e);
@@ -119,6 +133,12 @@ public class ModelPackageBundleListener implements BundleTrackerCustomizer {
     public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
         if (object instanceof ServiceRegistration[]) {
             for (ServiceRegistration reg : (ServiceRegistration[]) object) {
+                ServiceReference ref = reg.getReference();
+                String[] adapterTypeNames = PropertiesUtil.toStringArray(ref.getProperty(AdapterFactory.ADAPTER_CLASSES));
+                String implTypeName = PropertiesUtil.toString(ref.getProperty(PROP_IMPLEMENTATION_CLASS), null);
+                for (String adapterTypeName : adapterTypeNames) {
+                    adapterImplementations.remove(adapterTypeName, implTypeName);
+                }
                 reg.unregister();
             }
         }
@@ -142,5 +162,44 @@ public class ModelPackageBundleListener implements BundleTrackerCustomizer {
         }
         return arr;
     }
-
+    
+    /**
+     * Validate list of adapter classes. Make sure all given are either the annotated class itself,
+     * or an interface or superclass of it.
+     * A warning is written if this it not the case, and false is returned.
+     * @param clazz Annotated class
+     * @param adapterClasses Adapter classes
+     * @return true if validation was successful
+     */
+    private boolean validateAdapterClasses(Class<?> clazz, Class<?>[] adapterClasses) {
+        for (Class<?> adapterClass : adapterClasses) {
+            if (!adapterClass.isAssignableFrom(clazz)) {
+                log.warn("Unable to register model class {} because adapter class {} is not valid.",
+                        clazz.getName(), adapterClass.getName());
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * Registers an adapter factory for a annotated sling models class.
+     * @param adapterTypes Adapter (either the class itself, or interface or superclass of it)
+     * @param adaptableTypes Classes to adapt from
+     * @param implType Type of the implementation class
+     * @param condition Condition (optional)
+     * @return Service registration
+     */
+    private ServiceRegistration registerAdapterFactory(Class<?>[] adapterTypes, Class<?>[] adaptableTypes, Class<?> implType, String condition) {
+        Dictionary<String, Object> registrationProps = new Hashtable<String, Object>();
+        registrationProps.put(AdapterFactory.ADAPTER_CLASSES, toStringArray(adapterTypes));
+        registrationProps.put(AdapterFactory.ADAPTABLE_CLASSES, toStringArray(adaptableTypes));
+        registrationProps.put(PROP_IMPLEMENTATION_CLASS, implType.getName());
+
+        if (StringUtils.isNotBlank(condition)) {
+            registrationProps.put(PROP_ADAPTER_CONDITION, condition);
+        }
+        return bundleContext.registerService(AdapterFactory.SERVICE_NAME, factory, registrationProps);
+    }
+    
 }
diff --git a/src/test/java/org/apache/sling/models/impl/AdapterImplementationsTest.java b/src/test/java/org/apache/sling/models/impl/AdapterImplementationsTest.java
new file mode 100644
index 0000000..3dfebfa
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/AdapterImplementationsTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.assertNull;
+
+import java.util.Arrays;
+
+import org.apache.sling.models.spi.ImplementationPicker;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AdapterImplementationsTest {
+
+    private static final Class<?> SAMPLE_ADAPTER = Comparable.class;
+    private static final Object SAMPLE_ADAPTABLE = new Object();    
+
+    private AdapterImplementations underTest;
+    
+    @Before
+    public void setUp() {
+        underTest = new AdapterImplementations();
+        underTest.setImplementationPickers(Arrays.asList(new ImplementationPicker[] {
+            new FirstImplementationPicker()
+        }));
+    }
+    
+    @Test
+    public void testNoMapping() {
+        assertNull(underTest.lookup(SAMPLE_ADAPTER, SAMPLE_ADAPTABLE));
+        
+        // make sure this raises no exception
+        underTest.remove(SAMPLE_ADAPTER.getName(), String.class.getName());
+    }
+    
+    @Test
+    public void testSingleMapping() {
+        underTest.add(SAMPLE_ADAPTER, String.class);
+        
+        assertEquals(String.class, underTest.lookup(SAMPLE_ADAPTER, SAMPLE_ADAPTABLE));
+        
+        underTest.remove(SAMPLE_ADAPTER.getName(), String.class.getName());
+
+        assertNull(underTest.lookup(SAMPLE_ADAPTER, SAMPLE_ADAPTABLE));
+    }
+
+    @Test
+    public void testMultipleMappings() {
+        underTest.add(SAMPLE_ADAPTER, String.class);
+        underTest.add(SAMPLE_ADAPTER, Integer.class);
+        underTest.add(SAMPLE_ADAPTER, Long.class);
+        
+        assertEquals(Integer.class, underTest.lookup(SAMPLE_ADAPTER, SAMPLE_ADAPTABLE));
+        
+        underTest.remove(SAMPLE_ADAPTER.getName(), Integer.class.getName());
+
+        assertEquals(Long.class, underTest.lookup(SAMPLE_ADAPTER, SAMPLE_ADAPTABLE));
+
+        underTest.remove(SAMPLE_ADAPTER.getName(), Long.class.getName());
+        underTest.remove(SAMPLE_ADAPTER.getName(), String.class.getName());
+        
+        assertNull(underTest.lookup(SAMPLE_ADAPTER, SAMPLE_ADAPTABLE));
+    }
+    
+    @Test
+    public void testRemoveAll() {
+        underTest.add(SAMPLE_ADAPTER, String.class);
+        underTest.add(SAMPLE_ADAPTER, Integer.class);
+        underTest.add(SAMPLE_ADAPTER, Long.class);
+        
+        underTest.removeAll();
+        
+        assertNull(underTest.lookup(SAMPLE_ADAPTER, SAMPLE_ADAPTABLE));
+    }
+    
+    @Test
+    public void testMultipleImplementationPickers() {
+        underTest.setImplementationPickers(Arrays.asList(
+            new NoneImplementationPicker(),
+            new LastImplementationPicker(),
+            new FirstImplementationPicker()
+        ));
+
+        underTest.add(SAMPLE_ADAPTER, String.class);
+        underTest.add(SAMPLE_ADAPTER, Integer.class);
+        underTest.add(SAMPLE_ADAPTER, Long.class);
+        
+        assertEquals(String.class, underTest.lookup(SAMPLE_ADAPTER, SAMPLE_ADAPTABLE));
+    }
+    
+    static final class NoneImplementationPicker implements ImplementationPicker {
+        @Override
+        public Class<?> pick(Class<?> adapterType, Class<?>[] implementationsTypes, Object adaptable) {
+            return null;
+        }        
+    }
+    
+    static final class LastImplementationPicker implements ImplementationPicker {
+        @Override
+        public Class<?> pick(Class<?> adapterType, Class<?>[] implementationsTypes, Object adaptable) {
+            return implementationsTypes[implementationsTypes.length - 1];
+        }        
+    }
+    
+}
diff --git a/src/test/java/org/apache/sling/models/impl/ImplementsExtendsTest.java b/src/test/java/org/apache/sling/models/impl/ImplementsExtendsTest.java
new file mode 100644
index 0000000..afea6b0
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ImplementsExtendsTest.java
@@ -0,0 +1,253 @@
+/*
+ * 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.junit.Assert.assertNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Vector;
+
+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.apache.sling.models.spi.ImplementationPicker;
+import org.apache.sling.models.testmodels.classes.implextend.EvenSimplerPropertyModel;
+import org.apache.sling.models.testmodels.classes.implextend.ExtendsClassPropertyModel;
+import org.apache.sling.models.testmodels.classes.implextend.ImplementsInterfacePropertyModel;
+import org.apache.sling.models.testmodels.classes.implextend.ImplementsInterfacePropertyModel2;
+import org.apache.sling.models.testmodels.classes.implextend.InvalidImplementsInterfacePropertyModel;
+import org.apache.sling.models.testmodels.classes.implextend.InvalidSampleServiceInterface;
+import org.apache.sling.models.testmodels.classes.implextend.SampleServiceInterface;
+import org.apache.sling.models.testmodels.classes.implextend.SimplePropertyModel;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ImplementsExtendsTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    @Mock
+    private Bundle bundle;
+
+    @Mock
+    private BundleEvent bundleEvent;
+
+    private ModelAdapterFactory factory;
+
+    private ServiceRegistration[] registeredAdapterFactories;
+
+    private ImplementationPicker firstImplementationPicker = new FirstImplementationPicker();
+
+    private ServicePropertiesMap firstImplementationPickerProps = new ServicePropertiesMap(3, Integer.MAX_VALUE);
+
+    @SuppressWarnings("unchecked")
+    @Before
+    public void setup() throws ClassNotFoundException, MalformedURLException {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+        when(bundleContext.registerService(anyString(), anyObject(), any(Dictionary.class))).then(new Answer<ServiceRegistration>() {
+            @Override
+            public ServiceRegistration answer(InvocationOnMock invocation) throws Throwable {
+                final Dictionary<String, Object> props = (Dictionary<String, Object>)invocation.getArguments()[2];
+                ServiceRegistration reg = mock(ServiceRegistration.class);
+                ServiceReference ref = mock(ServiceReference.class);
+                when(reg.getReference()).thenReturn(ref);
+                when(ref.getProperty(anyString())).thenAnswer(new Answer<Object>() {
+                    @Override
+                    public Object answer(InvocationOnMock invocation) throws Throwable {
+                        String key = (String)invocation.getArguments()[0];
+                        return props.get(key);
+                    }
+                });
+                return reg;
+            }
+        });
+
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(new ValueMapInjector(), new ServicePropertiesMap(2, 2));
+        factory.bindImplementationPicker(firstImplementationPicker, firstImplementationPickerProps);
+
+        // simulate bundle add for ModelPackageBundleListener
+        Dictionary<String, String> headers = new Hashtable<String,String>();
+        headers.put(ModelPackageBundleListener.HEADER, "org.apache.sling.models.testmodels.classes.implextend");
+        when(bundle.getHeaders()).thenReturn(headers);
+
+        Vector<URL> classUrls = new Vector<URL>();
+        classUrls.add(getClassUrl(ExtendsClassPropertyModel.class));
+        classUrls.add(getClassUrl(ImplementsInterfacePropertyModel.class));
+        classUrls.add(getClassUrl(ImplementsInterfacePropertyModel2.class));
+        classUrls.add(getClassUrl(InvalidImplementsInterfacePropertyModel.class));
+        classUrls.add(getClassUrl(InvalidSampleServiceInterface.class));
+        classUrls.add(getClassUrl(SampleServiceInterface.class));
+        classUrls.add(getClassUrl(SimplePropertyModel.class));
+        when(bundle.findEntries(anyString(), anyString(), anyBoolean())).thenReturn(classUrls.elements());
+
+        when(bundle.loadClass(anyString())).then(new Answer<Class<?>>() {
+            @Override
+            public Class<?> answer(InvocationOnMock invocation) throws ClassNotFoundException {
+                String className = (String)invocation.getArguments()[0];
+                return ImplementsExtendsTest.this.getClass().getClassLoader().loadClass(className);
+            }
+        });
+
+        registeredAdapterFactories = (ServiceRegistration[])factory.listener.addingBundle(bundle, bundleEvent);
+    }
+
+    private URL getClassUrl(Class<?> clazz) throws MalformedURLException {
+        String path = "file:/" + clazz.getName().replace('.', '/') + ".class";
+        return new URL(path);
+    }
+
+    @After
+    public void tearDown() {
+        // simulate bundle remove for ModelPackageBundleListener
+        factory.listener.removedBundle(bundle, bundleEvent, registeredAdapterFactories);
+        
+        // make sure adaption is not longer possible: implementation class mapping is removed
+        Resource res = getMockResourceWithProps();
+        SampleServiceInterface model = factory.getAdapter(res, SampleServiceInterface.class);
+        assertNull(model);
+    }
+
+    /**
+     * Try to adapt to interface, with an different implementation class that has the @Model annotation
+     */
+    @Test
+    public void testImplementsInterfaceModel() {
+        Resource res = getMockResourceWithProps();
+        SampleServiceInterface model = factory.getAdapter(res, SampleServiceInterface.class);
+        assertNotNull(model);
+        assertEquals(ImplementsInterfacePropertyModel.class, model.getClass());
+        assertEquals("first-value|null|third-value", model.getAllProperties());
+    }
+
+    /**
+     * Try to adapt in a case where there is no picker available.
+     * This causes the extend adaptation to fail, but the case where the
+     * class is the adapter still works.
+     */
+    @Test
+    public void testImplementsNoPicker() {
+        factory.unbindImplementationPicker(firstImplementationPicker, firstImplementationPickerProps);
+
+        Resource res = getMockResourceWithProps();
+        SampleServiceInterface model = factory.getAdapter(res, SampleServiceInterface.class);
+        assertNull(model);
+
+        model = factory.getAdapter(res, ImplementsInterfacePropertyModel.class);
+        assertNotNull(model);
+        assertEquals("first-value|null|third-value", model.getAllProperties());
+    }
+
+    /**
+     * Ensure that the implementation class itself cannot be adapted to if it is not part of the "adapter" property in the annotation.
+     */
+    /*
+    -- disabled because this cannot work in unit test where the adapterFactory is called directly
+    -- it is enabled in integration tests
+    @Test
+    public void testImplementsInterfaceModel_ImplClassNotMapped() {
+        Resource res = getMockResourceWithProps();
+        ImplementsInterfacePropertyModel model = factory.getAdapter(res, ImplementsInterfacePropertyModel.class);
+        assertNull(model);
+    }
+    */
+
+    /**
+     * Test implementation class with a mapping that is not valid (an interface that is not implemented).
+     */
+    @Test
+    public void testInvalidImplementsInterfaceModel() {
+        Resource res = getMockResourceWithProps();
+        InvalidSampleServiceInterface model = factory.getAdapter(res, InvalidSampleServiceInterface.class);
+        assertNull(model);
+    }
+
+    /**
+     * Test to adapt to a superclass of the implementation class with the appropriate mapping in the @Model annotation.
+     */
+    @Test
+    public void testExtendsClassModel() {
+        Resource res = getMockResourceWithProps();
+
+        SimplePropertyModel model = factory.getAdapter(res, SimplePropertyModel.class);
+        assertNotNull(model);
+        assertEquals("!first-value|null|third-value!", model.getAllProperties());
+
+        EvenSimplerPropertyModel simplerModel = factory.getAdapter(res, EvenSimplerPropertyModel.class);
+        assertNotNull(simplerModel);
+        assertEquals("first-value", model.getFirst());
+    }
+
+    /**
+     * Try to adapt to interface, with an different implementation class that has the @Model annotation
+     */
+    @Test
+    public void testImplementsInterfaceModelWithPickLastImplementationPicker() {
+        factory.bindImplementationPicker(new AdapterImplementationsTest.LastImplementationPicker(), new ServicePropertiesMap(3, 1));
+
+        Resource res = getMockResourceWithProps();
+        SampleServiceInterface model = factory.getAdapter(res, SampleServiceInterface.class);
+        assertNotNull(model);
+        assertEquals(ImplementsInterfacePropertyModel2.class, model.getClass());
+        assertEquals("first-value|null|third-value", model.getAllProperties());
+    }
+
+    private Resource getMockResourceWithProps() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("first", "first-value");
+        map.put("third", "third-value");
+        ValueMap vm = new ValueMapDecorator(map);
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+        return res;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/implpicker/FirstImplementationPickerTest.java b/src/test/java/org/apache/sling/models/impl/implpicker/FirstImplementationPickerTest.java
new file mode 100644
index 0000000..1bc8cfb
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/implpicker/FirstImplementationPickerTest.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.impl.implpicker;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.sling.models.impl.FirstImplementationPicker;
+import org.apache.sling.models.spi.ImplementationPicker;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FirstImplementationPickerTest {
+
+    private static final Class<?> SAMPLE_ADAPTER = Comparable.class;
+    private static final Object SAMPLE_ADAPTABLE = new Object();
+
+    private ImplementationPicker underTest;
+
+    @Before
+    public void setUp() {
+        underTest = new FirstImplementationPicker();
+    }
+
+    @Test
+    public void testPickOneImplementation() {
+        Class<?>[] implementations = new Class<?>[] { String.class };
+        assertEquals(String.class, underTest.pick(SAMPLE_ADAPTER, implementations, SAMPLE_ADAPTABLE));
+    }
+
+    @Test
+    public void testPickMultipleImplementations() {
+        Class<?>[] implementations = new Class<?>[] { Integer.class, Long.class, String.class };
+        assertEquals(Integer.class, underTest.pick(SAMPLE_ADAPTER, implementations, SAMPLE_ADAPTABLE));
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/implextend/EvenSimplerPropertyModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/EvenSimplerPropertyModel.java
new file mode 100644
index 0000000..d1ea125
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/EvenSimplerPropertyModel.java
@@ -0,0 +1,14 @@
+package org.apache.sling.models.testmodels.classes.implextend;
+
+import javax.inject.Inject;
+
+public class EvenSimplerPropertyModel {
+
+    @Inject
+    private String first;
+
+    public String getFirst() {
+        return first;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/implextend/ExtendsClassPropertyModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/ExtendsClassPropertyModel.java
new file mode 100644
index 0000000..6ab6d26
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/ExtendsClassPropertyModel.java
@@ -0,0 +1,34 @@
+/*
+ * 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.implextend;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+/**
+ * This is an example for a model that can not be adapted itself, but only 
+ * to a superclass it extends. This superclass is defined as "adapters".
+ */
+@Model(adaptables = Resource.class, adapters = { SimplePropertyModel.class, EvenSimplerPropertyModel.class })
+public class ExtendsClassPropertyModel extends SimplePropertyModel {
+
+    @Override
+    public String getAllProperties() {
+        return "!" + super.getAllProperties() + "!";
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/implextend/ImplementsInterfacePropertyModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/ImplementsInterfacePropertyModel.java
new file mode 100644
index 0000000..a4d5d5f
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/ImplementsInterfacePropertyModel.java
@@ -0,0 +1,55 @@
+/*
+ * 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.implextend;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Optional;
+
+/**
+ * This is an example for a model that can not be adapted itself, but only 
+ * to an interface it implements. This interfaces is defined as "adapters".
+ */
+@Model(adaptables = Resource.class, adapters = { SampleServiceInterface.class, ImplementsInterfacePropertyModel.class })
+public class ImplementsInterfacePropertyModel implements SampleServiceInterface {
+
+    @Inject
+    private String first;
+
+    @Inject
+    @Optional
+    private String second;
+
+    @Inject
+    @Named("third")
+    private String thirdProperty;
+
+    @Override
+    public String getAllProperties() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(first)
+            .append("|")
+            .append(second)
+            .append("|")
+            .append(thirdProperty);
+        return sb.toString();
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/implextend/ImplementsInterfacePropertyModel2.java b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/ImplementsInterfacePropertyModel2.java
new file mode 100644
index 0000000..a4df61c
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/ImplementsInterfacePropertyModel2.java
@@ -0,0 +1,54 @@
+/*
+ * 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.implextend;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Optional;
+
+/**
+ * Additional model class that implements the same interface as {@link ImplementsInterfacePropertyModel}.
+ */
+@Model(adaptables = Resource.class, adapters = SampleServiceInterface.class)
+public class ImplementsInterfacePropertyModel2 implements SampleServiceInterface {
+
+    @Inject
+    private String first;
+
+    @Inject
+    @Optional
+    private String second;
+
+    @Inject
+    @Named("third")
+    private String thirdProperty;
+
+    @Override
+    public String getAllProperties() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(first)
+            .append("|")
+            .append(second)
+            .append("|")
+            .append(thirdProperty);
+        return sb.toString();
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/implextend/InvalidImplementsInterfacePropertyModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/InvalidImplementsInterfacePropertyModel.java
new file mode 100644
index 0000000..980b9b4
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/InvalidImplementsInterfacePropertyModel.java
@@ -0,0 +1,54 @@
+/*
+ * 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.implextend;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Optional;
+
+/**
+ * This model defines an invalid adapters property containing an interface it does not implement.
+ */
+@Model(adaptables = Resource.class, adapters = InvalidSampleServiceInterface.class)
+public class InvalidImplementsInterfacePropertyModel implements SampleServiceInterface {
+
+    @Inject
+    private String first;
+
+    @Inject
+    @Optional
+    private String second;
+
+    @Inject
+    @Named("third")
+    private String thirdProperty;
+
+    @Override
+    public String getAllProperties() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(first)
+            .append("|")
+            .append(second)
+            .append("|")
+            .append(thirdProperty);
+        return sb.toString();
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/implextend/InvalidSampleServiceInterface.java b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/InvalidSampleServiceInterface.java
new file mode 100644
index 0000000..38ab451
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/InvalidSampleServiceInterface.java
@@ -0,0 +1,31 @@
+/*
+ * 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.implextend;
+
+/**
+ * Example "service" interface to which sling models can adapt.
+ */
+public interface InvalidSampleServiceInterface {
+
+    /**
+     * @return concanated string with all properties
+     */
+    String getAllProperties();
+    
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/implextend/SampleServiceInterface.java b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/SampleServiceInterface.java
new file mode 100644
index 0000000..753c802
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/SampleServiceInterface.java
@@ -0,0 +1,31 @@
+/*
+ * 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.implextend;
+
+/**
+ * Example "service" interface to which sling models can adapt.
+ */
+public interface SampleServiceInterface {
+
+    /**
+     * @return concatenated string with all properties
+     */
+    String getAllProperties();
+    
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/implextend/SimplePropertyModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/SimplePropertyModel.java
new file mode 100644
index 0000000..7ab8c5f
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/implextend/SimplePropertyModel.java
@@ -0,0 +1,47 @@
+/*
+ * 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.implextend;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.sling.models.annotations.Optional;
+
+/**
+ * Base class without @Model annotation.
+ */
+public class SimplePropertyModel extends EvenSimplerPropertyModel {
+
+    @Inject
+    @Optional
+    private String second;
+
+    @Inject
+    @Named("third")
+    private String thirdProperty;
+
+    public String getAllProperties() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getFirst())
+            .append("|")
+            .append(second)
+            .append("|")
+            .append(thirdProperty);
+        return sb.toString();
+    }
+
+}
\ No newline at end of file

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

[sling-org-apache-sling-models-impl] 22/24: release prep

Posted by ro...@apache.org.
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 f3b034c3f9d4141244e3b0ac11fff7268f0dc0b9
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Tue Sep 2 19:12:54 2014 +0000

    release prep
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1622097 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 37f20bd..9591f4f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,7 +63,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.models.api</artifactId>
-            <version>1.0.3-SNAPSHOT</version>
+            <version>1.1.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

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

[sling-org-apache-sling-models-impl] 11/24: SLING-3876 - ensuring that class-based self injection only happens on the first constructor parameter. Otherwise the @Self annotation is necessary. Also changing the ranking so that other injectors have the opportunity to inject to the first constructor parameter before.

Posted by ro...@apache.org.
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 025b2aee6ca7f9b11680a9fe48285854aa4ddac5
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Aug 22 15:49:57 2014 +0000

    SLING-3876 - ensuring that class-based self injection only happens on the first constructor parameter. Otherwise the @Self annotation is necessary. Also changing the ranking so that other injectors have the opportunity to inject to the first constructor parameter before.
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1619847 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/models/impl/ConstructorParameter.java    |  2 +-
 .../sling/models/impl/injectors/SelfInjector.java  | 15 +++++---
 .../models/impl/injectors/SelfInjectorTest.java    | 43 ++++++++++++++++------
 3 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java b/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java
index eab70ae..efd4693 100644
--- a/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java
+++ b/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java
@@ -27,7 +27,7 @@ import java.lang.reflect.Type;
  * AnnotatedElement. This class acts as a facade to ease
  * compatibility with field and method injection.
  */
-class ConstructorParameter implements AnnotatedElement {
+public class ConstructorParameter implements AnnotatedElement {
 
     private final Annotation[] annotations;
     private final Class<?> type;
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java
index 5787b46..9e06b35 100644
--- a/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java
+++ b/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java
@@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.apache.sling.models.impl.ConstructorParameter;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
 import org.apache.sling.models.spi.AcceptsNullName;
 import org.apache.sling.models.spi.Injector;
@@ -36,7 +37,7 @@ import org.osgi.framework.Constants;
  */
 @Component
 @Service
-@Property(name = Constants.SERVICE_RANKING, intValue = 100)
+@Property(name = Constants.SERVICE_RANKING, intValue = Integer.MAX_VALUE)
 public class SelfInjector implements Injector, InjectAnnotationProcessorFactory, AcceptsNullName {
 
     @Override
@@ -49,11 +50,13 @@ public class SelfInjector implements Injector, InjectAnnotationProcessorFactory,
         // if the @Self annotation is present return the adaptable to be inserted directly or to be adapted from
         if (element.isAnnotationPresent(Self.class)) {
             return adaptable;
-        }
-        // otherwise apply class-based injection only if class matches or is a superclass
-        else if (type instanceof Class<?>) {
-            Class<?> requestedClass = (Class<?>)type;
-            if (requestedClass.isAssignableFrom(adaptable.getClass())) {
+        } else {
+            // special handling for the first constructor parameter
+            // apply class-based injection only if class matches or is a superclass
+            if (element instanceof ConstructorParameter &&
+                    ((ConstructorParameter)element).getParameterIndex() == 0 &&
+                    type instanceof Class<?> &&
+                    ((Class<?>)type).isAssignableFrom(adaptable.getClass())) {
                 return adaptable;
             }
         }
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java b/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java
index 3e7251a..146a8b7 100644
--- a/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java
+++ b/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java
@@ -18,8 +18,7 @@
  */
 package org.apache.sling.models.impl.injectors;
 
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
 import java.lang.reflect.AnnotatedElement;
@@ -29,6 +28,8 @@ import javax.servlet.http.HttpServletRequest;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.apache.sling.models.impl.ConstructorParameter;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -39,40 +40,58 @@ import org.mockito.runners.MockitoJUnitRunner;
 public class SelfInjectorTest {
 
     private SelfInjector injector = new SelfInjector();
-    
+
     @Mock
     private SlingHttpServletRequest request;
+
     @Mock
     private AnnotatedElement annotatedElement;
+    
+    @Mock
+    private ConstructorParameter firstConstructorParameter;
+    
+    @Mock
+    private ConstructorParameter secondConstructorParameter;
+    
+    @Before
+    public void setup() {
+        when(firstConstructorParameter.getParameterIndex()).thenReturn(0);
+        when(secondConstructorParameter.getParameterIndex()).thenReturn(1);
+    }
 
     @Test
     public void testMatchingClass() {
-        Object result = injector.getValue(request, "notRelevant", SlingHttpServletRequest.class, annotatedElement, null);
-        assertSame(request, result);
+        assertSame(request, injector.getValue(request, "notRelevant", SlingHttpServletRequest.class, firstConstructorParameter, null));
+        assertNull(injector.getValue(request, "notRelevant", SlingHttpServletRequest.class, secondConstructorParameter, null));
+        assertNull(injector.getValue(request, "notRelevant", SlingHttpServletRequest.class, annotatedElement, null));
     }
 
     @Test
     public void testMatchingSubClass() {
-        Object result = injector.getValue(request, "notRelevant", HttpServletRequest.class, annotatedElement, null);
-        assertSame(request, result);
+        assertSame(request, injector.getValue(request, "notRelevant", HttpServletRequest.class, firstConstructorParameter, null));
+        assertNull(injector.getValue(request, "notRelevant", HttpServletRequest.class, secondConstructorParameter, null));
+        assertNull(injector.getValue(request, "notRelevant", HttpServletRequest.class, annotatedElement, null));
     }
 
     @Test
     public void testNotMatchingClass() {
-        Object result = injector.getValue(request, "notRelevant", ResourceResolver.class, annotatedElement, null);
-        assertNull(result);
+        assertNull(injector.getValue(request, "notRelevant", ResourceResolver.class, firstConstructorParameter, null));
+        assertNull(injector.getValue(request, "notRelevant", ResourceResolver.class, secondConstructorParameter, null));
+        assertNull(injector.getValue(request, "notRelevant", ResourceResolver.class, annotatedElement, null));
     }
 
     @Test
     public void testWithNullName() {
-        Object result = injector.getValue(request, null, SlingHttpServletRequest.class, annotatedElement, null);
-        assertSame(request, result);
+        assertSame(request, injector.getValue(request, null, SlingHttpServletRequest.class, firstConstructorParameter, null));
+        assertNull(injector.getValue(request, null, SlingHttpServletRequest.class, secondConstructorParameter, null));
+        assertNull(injector.getValue(request, null, SlingHttpServletRequest.class, annotatedElement, null));
     }
 
     @Test
     public void testMatchingClassWithSelfAnnotation() {
         when(annotatedElement.isAnnotationPresent(Self.class)).thenReturn(true);
-        Object result = injector.getValue(request, "notRelevant", SlingHttpServletRequest.class, annotatedElement, null);
+        Object result = injector
+                .getValue(request, "notRelevant", SlingHttpServletRequest.class, annotatedElement, null);
         assertSame(request, result);
     }
 

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

[sling-org-apache-sling-models-impl] 08/24: SLING-3863 - correcting behavior where optional methods and constructor parameters were injected with non-null wrapper classes.

Posted by ro...@apache.org.
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 fd0324df4dae97d2becea26c48a6074d4b2d8835
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Wed Aug 20 19:42:00 2014 +0000

    SLING-3863 - correcting behavior where optional methods and constructor parameters were injected with non-null wrapper classes.
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1619212 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/models/impl/ModelAdapterFactory.java     | 42 ++++++--------
 .../sling/models/impl/OptionalPrimitivesTest.java  | 41 +++++++++++++-
 .../classes/OptionalPrimitivesModel.java           | 66 ++++++++++++++++++++--
 .../OptionalPrimitivesModel.java                   | 60 +++++++++++++++++++-
 .../interfaces/OptionalPrimitivesModel.java        | 36 ++++++++++--
 5 files changed, 206 insertions(+), 39 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 a81cc31..1880e66 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -249,8 +249,6 @@ 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 {
@@ -265,11 +263,6 @@ 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 {
@@ -284,13 +277,8 @@ 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 {
 
         private final List<Object> parameterValues;
@@ -303,15 +291,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,
-            final Model modelAnnotation, final DisposalCallbackRegistry registry, InjectCallback callback) {
+            final boolean injectPrimitiveInitialValue, final Model modelAnnotation, final DisposalCallbackRegistry registry,
+            final InjectCallback callback) {
 
         InjectAnnotationProcessor annotationProcessor = null;
         String source = getSource(element);
@@ -350,7 +334,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         // if default is not set, check if mandatory
         if (!wasInjectionSuccessful) {
             if (isOptional(element, modelAnnotation, annotationProcessor)) {
-                if (callback.shouldInjectPrimitiveInitValue()) {
+                if (injectPrimitiveInitialValue) {
                     injectPrimitiveInitialValue(element, type, callback);
                 }
             } else {
@@ -372,8 +356,13 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         Set<Method> requiredMethods = new HashSet<Method>();
 
         for (Method method : injectableMethods) {
-            Type returnType = mapPrimitiveClasses(method.getGenericReturnType());
-            if (!injectElement(method, adaptable, returnType, modelAnnotation, registry, callback)) {
+            Type genericReturnType = method.getGenericReturnType();
+            Type returnType = mapPrimitiveClasses(genericReturnType);
+            boolean isPrimitive = false;
+            if (returnType != genericReturnType) {
+                isPrimitive = true;
+            }
+            if (!injectElement(method, adaptable, returnType, isPrimitive, modelAnnotation, registry, callback)) {
                 requiredMethods.add(method);
             }
         }
@@ -467,7 +456,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         Set<Field> injectableFields = collectInjectableFields(type);
         for (Field field : injectableFields) {
             Type fieldType = mapPrimitiveClasses(field.getGenericType());
-            if (!injectElement(field, adaptable, fieldType, modelAnnotation, registry, callback)) {
+            if (!injectElement(field, adaptable, fieldType, false, modelAnnotation, registry, callback)) {
                 requiredFields.add(field);
             }
         }
@@ -532,9 +521,14 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
         for (int i = 0; i < parameterTypes.length; i++) {
             Type genericType = mapPrimitiveClasses(parameterTypes[i]);
+
+            boolean isPrimitive = false;
+            if (parameterTypes[i] != genericType) {
+                isPrimitive = true;
+            }
             ConstructorParameter constructorParameter = new ConstructorParameter(
                     constructor.getParameterAnnotations()[i], constructor.getParameterTypes()[i], genericType, i);
-            if (!injectElement(constructorParameter, adaptable, genericType, modelAnnotation, registry, callback)) {
+            if (!injectElement(constructorParameter, adaptable, genericType, isPrimitive, modelAnnotation, registry, callback)) {
                 requiredParameters.add(constructorParameter);
             }
         }
diff --git a/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java b/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
index 7e7637a..0fd45c5 100644
--- a/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
+++ b/src/test/java/org/apache/sling/models/impl/OptionalPrimitivesTest.java
@@ -18,6 +18,7 @@ package org.apache.sling.models.impl;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -66,6 +67,8 @@ public class OptionalPrimitivesTest {
         org.apache.sling.models.testmodels.classes.OptionalPrimitivesModel model
                 = factory.getAdapter(res, org.apache.sling.models.testmodels.classes.OptionalPrimitivesModel.class);
         assertNotNull(model);
+
+        // make sure primitives are initialized with initial value
         assertEquals(0, model.getByteValue());
         assertEquals(0, model.getShortValue());
         assertEquals(0, model.getIntValue());
@@ -74,7 +77,17 @@ public class OptionalPrimitivesTest {
         assertEquals(0.0d, model.getDoubleValue(), 0.00001d);
         assertEquals('\u0000', model.getCharValue());
         assertEquals(false, model.getBooleanValue());
-    }
+
+        // make sure object wrapper of primitives are null
+        assertNull(model.getByteObjectValue());
+        assertNull(model.getShortObjectValue());
+        assertNull(model.getIntObjectValue());
+        assertNull(model.getLongObjectValue());
+        assertNull(model.getFloatObjectValue());
+        assertNull(model.getDoubleObjectValue());
+        assertNull(model.getCharObjectValue());
+        assertNull(model.getBooleanObjectValue());
+}
 
     @Test
     public void testConstructorInjection() {
@@ -86,6 +99,8 @@ public class OptionalPrimitivesTest {
         org.apache.sling.models.testmodels.classes.constructorinjection.OptionalPrimitivesModel model
                 = factory.getAdapter(res, org.apache.sling.models.testmodels.classes.constructorinjection.OptionalPrimitivesModel.class);
         assertNotNull(model);
+
+        // make sure primitives are initialized with initial value
         assertEquals(0, model.getByteValue());
         assertEquals(0, model.getShortValue());
         assertEquals(0, model.getIntValue());
@@ -94,7 +109,17 @@ public class OptionalPrimitivesTest {
         assertEquals(0.0d, model.getDoubleValue(), 0.00001d);
         assertEquals('\u0000', model.getCharValue());
         assertEquals(false, model.getBooleanValue());
-    }
+
+        // make sure object wrapper of primitives are null
+        assertNull(model.getByteObjectValue());
+        assertNull(model.getShortObjectValue());
+        assertNull(model.getIntObjectValue());
+        assertNull(model.getLongObjectValue());
+        assertNull(model.getFloatObjectValue());
+        assertNull(model.getDoubleObjectValue());
+        assertNull(model.getCharObjectValue());
+        assertNull(model.getBooleanObjectValue());
+}
 
     @Test
     public void testFieldInjectionInterface() {
@@ -106,6 +131,8 @@ public class OptionalPrimitivesTest {
         org.apache.sling.models.testmodels.interfaces.OptionalPrimitivesModel model
                 = factory.getAdapter(res, org.apache.sling.models.testmodels.interfaces.OptionalPrimitivesModel.class);
         assertNotNull(model);
+
+        // make sure primitives are initialized with initial value
         assertEquals(0, model.getByteValue());
         assertEquals(0, model.getShortValue());
         assertEquals(0, model.getIntValue());
@@ -114,6 +141,16 @@ public class OptionalPrimitivesTest {
         assertEquals(0.0d, model.getDoubleValue(), 0.00001d);
         assertEquals('\u0000', model.getCharValue());
         assertEquals(false, model.getBooleanValue());
+
+        // make sure object wrapper of primitives are null
+        assertNull(model.getByteObjectValue());
+        assertNull(model.getShortObjectValue());
+        assertNull(model.getIntObjectValue());
+        assertNull(model.getLongObjectValue());
+        assertNull(model.getFloatObjectValue());
+        assertNull(model.getDoubleObjectValue());
+        assertNull(model.getCharObjectValue());
+        assertNull(model.getBooleanObjectValue());
     }
 
 }
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
index f97afa9..2f9aad2 100644
--- a/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/OptionalPrimitivesModel.java
@@ -33,22 +33,46 @@ public class OptionalPrimitivesModel {
 
     @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;
 
+    @Inject @Optional
+    private Byte byteObjectValue;
+
+    @Inject @Optional
+    private Short shortObjectValue;
+
+    @Inject @Optional
+    private Integer intObjectValue;
+
+    @Inject @Optional
+    private Long longObjectValue;
+
+    @Inject @Optional
+    private Float floatObjectValue;
+
+    @Inject @Optional
+    private Double doubleObjectValue;
+
+    @Inject @Optional
+    private Character charObjectValue;
+
+    @Inject @Optional
+    private Boolean booleanObjectValue;
+
     public byte getByteValue() {
         return this.byteValue;
     }
@@ -81,4 +105,36 @@ public class OptionalPrimitivesModel {
         return this.booleanValue;
     }
 
+    public Byte getByteObjectValue() {
+        return this.byteObjectValue;
+    }
+
+    public Short getShortObjectValue() {
+        return this.shortObjectValue;
+    }
+
+    public Integer getIntObjectValue() {
+        return this.intObjectValue;
+    }
+
+    public Long getLongObjectValue() {
+        return this.longObjectValue;
+    }
+
+    public Float getFloatObjectValue() {
+        return this.floatObjectValue;
+    }
+
+    public Double getDoubleObjectValue() {
+        return this.doubleObjectValue;
+    }
+
+    public Character getCharObjectValue() {
+        return this.charObjectValue;
+    }
+
+    public Boolean getBooleanObjectValue() {
+        return this.booleanObjectValue;
+    }
+
 }
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
index c6f51c2..e465fc4 100644
--- 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
@@ -33,7 +33,15 @@ public class OptionalPrimitivesModel {
     private final double doubleValue;
     private final char charValue;
     private final boolean booleanValue;
-    
+    private final Byte byteObjectValue;
+    private final Short shortObjectValue;
+    private final Integer intObjectValue;
+    private final Long longObjectValue;
+    private final Float floatObjectValue;
+    private final Double doubleObjectValue;
+    private final Character charObjectValue;
+    private final Boolean booleanObjectValue;
+
     @Inject
     public OptionalPrimitivesModel(
             @Optional byte byteValue,
@@ -43,7 +51,15 @@ public class OptionalPrimitivesModel {
             @Optional float floatValue,
             @Optional double doubleValue,
             @Optional char charValue,
-            @Optional boolean booleanValue) {
+            @Optional boolean booleanValue,
+            @Optional Byte byteObjectValue,
+            @Optional Short shortObjectValue,
+            @Optional Integer intObjectValue,
+            @Optional Long longObjectValue,
+            @Optional Float floatObjectValue,
+            @Optional Double doubleObjectValue,
+            @Optional Character charObjectValue,
+            @Optional Boolean booleanObjectValue) {
         this.byteValue = byteValue;
         this.shortValue = shortValue;
         this.intValue = intValue;
@@ -52,6 +68,14 @@ public class OptionalPrimitivesModel {
         this.doubleValue = doubleValue;
         this.charValue = charValue;
         this.booleanValue = booleanValue;
+        this.byteObjectValue = byteObjectValue;
+        this.shortObjectValue = shortObjectValue;
+        this.intObjectValue = intObjectValue;
+        this.longObjectValue = longObjectValue;
+        this.floatObjectValue = floatObjectValue;
+        this.doubleObjectValue = doubleObjectValue;
+        this.charObjectValue = charObjectValue;
+        this.booleanObjectValue = booleanObjectValue;
     }
 
     public byte getByteValue() {
@@ -86,4 +110,36 @@ public class OptionalPrimitivesModel {
         return this.booleanValue;
     }
     
+    public Byte getByteObjectValue() {
+        return this.byteObjectValue;
+    }
+
+    public Short getShortObjectValue() {
+        return this.shortObjectValue;
+    }
+
+    public Integer getIntObjectValue() {
+        return this.intObjectValue;
+    }
+
+    public Long getLongObjectValue() {
+        return this.longObjectValue;
+    }
+
+    public Float getFloatObjectValue() {
+        return this.floatObjectValue;
+    }
+
+    public Double getDoubleObjectValue() {
+        return this.doubleObjectValue;
+    }
+
+    public Character getCharObjectValue() {
+        return this.charObjectValue;
+    }
+
+    public Boolean getBooleanObjectValue() {
+        return this.booleanObjectValue;
+    }
+    
 }
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
index 8f8ed54..1a07c18 100644
--- a/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java
+++ b/src/test/java/org/apache/sling/models/testmodels/interfaces/OptionalPrimitivesModel.java
@@ -33,20 +33,44 @@ public interface OptionalPrimitivesModel {
 
     @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();
-    
+
+    @Inject @Optional
+    public Byte getByteObjectValue();
+
+    @Inject @Optional
+    public Short getShortObjectValue();
+
+    @Inject @Optional
+    public Integer getIntObjectValue();
+
+    @Inject @Optional
+    public Long getLongObjectValue();
+
+    @Inject @Optional
+    public Float getFloatObjectValue();
+
+    @Inject @Optional
+    public Double getDoubleObjectValue();
+
+    @Inject @Optional
+    public Character getCharObjectValue();
+
+    @Inject @Optional
+    public Boolean getBooleanObjectValue();
+
 }

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

[sling-org-apache-sling-models-impl] 03/24: SLING-3703 - referencing older version of commons osgi

Posted by ro...@apache.org.
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 60a094f2d992a6ee7f4bcc498d4e6244db5a5569
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jul 25 12:33:05 2014 +0000

    SLING-3703 - referencing older version of commons osgi
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1613413 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 5ce4aca..2ad22da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,7 +63,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.models.api</artifactId>
-            <version>1.0.3-SNAPSHOT</version>
+            <version>1.0.2</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -123,7 +123,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.osgi</artifactId>
-            <version>2.2.0</version>
+            <version>2.1.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

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

[sling-org-apache-sling-models-impl] 18/24: SLING-3895 - supporting list adaptation for method and constructor injection

Posted by ro...@apache.org.
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 9a66a4b9b9f5b21b390cdbb0d2274fb87397eeb8
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Thu Aug 28 23:41:16 2014 +0000

    SLING-3895 - supporting list adaptation for method and constructor injection
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1621231 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/models/impl/ModelAdapterFactory.java     |  81 +++++++-------
 .../models/impl/ResourceModelClassesTest.java      |   9 +-
 .../models/impl/ResourceModelConstructorTest.java  | 119 +++++++++++++++++++++
 .../models/impl/ResourceModelInterfacesTest.java   |  46 ++++++--
 .../classes/constructorinjection/ParentModel.java  |  58 ++++++++++
 .../models/testmodels/interfaces/ParentModel.java  |   9 ++
 6 files changed, 266 insertions(+), 56 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 0f51f66..7d00ba8 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -759,32 +759,10 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     private static boolean setField(Field field, Object createdObject, Object value) {
         if (value != null) {
-            if (!isAcceptableType(field.getType(), field.getGenericType(), value)) {
-                Class<?> declaredType = field.getType();
-                Type genericType = field.getGenericType();
-                if (value instanceof Adaptable) {
-                    value = ((Adaptable) value).adaptTo(field.getType());
-                    if (value == null) {
-                        return false;
-                    }
-                } else if (genericType instanceof ParameterizedType) {
-                    ParameterizedType type = (ParameterizedType) genericType;
-                    Class<?> collectionType = (Class<?>) declaredType;
-                    if (value instanceof Collection &&
-                            (collectionType.equals(Collection.class) || collectionType.equals(List.class)) &&
-                            type.getActualTypeArguments().length == 1) {
-                        List<Object> result = new ArrayList<Object>();
-                        for (Object valueObject : (Collection<?>) value) {
-                            if (valueObject instanceof Adaptable) {
-                                Object adapted = ((Adaptable) valueObject).adaptTo((Class<?>) type.getActualTypeArguments()[0]);
-                                if (adapted != null) {
-                                    result.add(adapted);
-                                }
-                            }
-                        }
-                        value = result;
-                    }
-                }
+            value = adaptIfNecessary(value, field.getType(), field.getGenericType());
+            // value may now be null due to the adaptation done above
+            if (value == null) {
+                return false;
             }
             boolean accessible = field.isAccessible();
             try {
@@ -808,11 +786,10 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     private static boolean setMethod(Method method, Map<Method, Object> methods, Object value) {
         if (value != null) {
-            if (!isAcceptableType(method.getReturnType(), method.getGenericReturnType(), value) && value instanceof Adaptable) {
-                value = ((Adaptable) value).adaptTo(method.getReturnType());
-                if (value == null) {
-                    return false;
-                }
+            value = adaptIfNecessary(value, method.getReturnType(), method.getGenericReturnType());
+            // value may now be null due to the adaptation done above
+            if (value == null) {
+                return false;
             }
             methods.put(method, value);
             return true;
@@ -823,17 +800,10 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     private static boolean setConstructorParameter(ConstructorParameter constructorParameter, List<Object> parameterValues, Object value) {
         if (value != null && constructorParameter.getType() instanceof Class<?>) {
-            Class<?> requestedType = (Class<?>)constructorParameter.getType();
-            if (!isAcceptableType(requestedType, constructorParameter.getGenericType(), value)) {
-                if (value instanceof Adaptable) {
-                    value = ((Adaptable) value).adaptTo(requestedType);
-                    if (value == null) {
-                        return false;
-                    }
-                }
-                else {
-                    return false;
-                }
+            value = adaptIfNecessary(value, (Class<?>) constructorParameter.getType(), constructorParameter.getGenericType());
+            // value may now be null due to the adaptation done above
+            if (value == null) {
+                return false;
             }
             parameterValues.set(constructorParameter.getParameterIndex(), value);
             return true;
@@ -842,6 +812,33 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         }
     }
 
+    private static Object adaptIfNecessary(Object value, Class<?> type, Type genericType) {
+        if (!isAcceptableType(type, genericType, value)) {
+            Class<?> declaredType = type;
+            if (value instanceof Adaptable) {
+                value = ((Adaptable) value).adaptTo(type);
+            } else if (genericType instanceof ParameterizedType) {
+                ParameterizedType parameterizedType = (ParameterizedType) genericType;
+                Class<?> collectionType = (Class<?>) declaredType;
+                if (value instanceof Collection &&
+                        (collectionType.equals(Collection.class) || collectionType.equals(List.class)) &&
+                        parameterizedType.getActualTypeArguments().length == 1) {
+                    List<Object> result = new ArrayList<Object>();
+                    for (Object valueObject : (Collection<?>) value) {
+                        if (valueObject instanceof Adaptable) {
+                            Object adapted = ((Adaptable) valueObject).adaptTo((Class<?>) parameterizedType.getActualTypeArguments()[0]);
+                            if (adapted != null) {
+                                result.add(adapted);
+                            }
+                        }
+                    }
+                    value = result;
+                }
+            }
+        }
+        return value;
+    }
+
     private static boolean isAcceptableType(Class<?> type, Type genericType, Object value) {
         if (type.isInstance(value)) {
             if ((type == Collection.class || type == List.class) && genericType instanceof ParameterizedType &&
diff --git a/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java b/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
index 625e5a0..888017b 100644
--- a/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
@@ -259,7 +259,7 @@ public class ResourceModelClassesTest {
 
         final Resource firstChild = mock(Resource.class);
         when(firstChild.adaptTo(ValueMap.class)).thenReturn(firstMap);
-        when(firstChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildMap());
+        when(firstChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildModel());
 
         Object firstGrandChildValue = RandomStringUtils.randomAlphabetic(10);
         ValueMap firstGrandChildMap = new ValueMapDecorator(Collections.singletonMap("property", firstGrandChildValue));
@@ -268,11 +268,11 @@ public class ResourceModelClassesTest {
 
         final Resource firstGrandChild = mock(Resource.class);
         when(firstGrandChild.adaptTo(ValueMap.class)).thenReturn(firstGrandChildMap);
-        when(firstGrandChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildMap());
+        when(firstGrandChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildModel());
 
         final Resource secondGrandChild = mock(Resource.class);
         when(secondGrandChild.adaptTo(ValueMap.class)).thenReturn(secondGrandChildMap);
-        when(secondGrandChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildMap());
+        when(secondGrandChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildModel());
 
         Resource secondChild = mock(Resource.class);
         when(secondChild.listChildren()).thenReturn(Arrays.asList(firstGrandChild, secondGrandChild).iterator());
@@ -294,9 +294,10 @@ public class ResourceModelClassesTest {
         assertEquals(2, model.getGrandChildren().size());
         assertEquals(firstGrandChildValue, model.getGrandChildren().get(0).getProperty());
         assertEquals(secondGrandChildValue, model.getGrandChildren().get(1).getProperty());
+        assertEquals(0, model.getEmptyGrandChildren().size());
     }
 
-    private class AdaptToChildMap implements Answer<ChildModel> {
+    private class AdaptToChildModel implements Answer<ChildModel> {
 
         @Override
         public ChildModel answer(InvocationOnMock invocation) throws Throwable {
diff --git a/src/test/java/org/apache/sling/models/impl/ResourceModelConstructorTest.java b/src/test/java/org/apache/sling/models/impl/ResourceModelConstructorTest.java
new file mode 100644
index 0000000..cc553b8
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ResourceModelConstructorTest.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.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Hashtable;
+
+import org.apache.commons.lang.RandomStringUtils;
+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.ChildResourceInjector;
+import org.apache.sling.models.impl.injectors.ValueMapInjector;
+import org.apache.sling.models.testmodels.classes.ChildModel;
+import org.apache.sling.models.testmodels.classes.constructorinjection.ParentModel;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ResourceModelConstructorTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    private ModelAdapterFactory factory;
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(componentCtx.getProperties()).thenReturn(new Hashtable<String, Object>());
+
+        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 testChildModel() {
+        Object firstValue = RandomStringUtils.randomAlphabetic(10);
+        ValueMap firstMap = new ValueMapDecorator(Collections.singletonMap("property", firstValue));
+
+        final Resource firstChild = mock(Resource.class);
+        when(firstChild.adaptTo(ValueMap.class)).thenReturn(firstMap);
+        when(firstChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildModel());
+
+        Object firstGrandChildValue = RandomStringUtils.randomAlphabetic(10);
+        ValueMap firstGrandChildMap = new ValueMapDecorator(Collections.singletonMap("property", firstGrandChildValue));
+        Object secondGrandChildValue = RandomStringUtils.randomAlphabetic(10);
+        ValueMap secondGrandChildMap = new ValueMapDecorator(Collections.singletonMap("property", secondGrandChildValue));
+
+        final Resource firstGrandChild = mock(Resource.class);
+        when(firstGrandChild.adaptTo(ValueMap.class)).thenReturn(firstGrandChildMap);
+        when(firstGrandChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildModel());
+
+        final Resource secondGrandChild = mock(Resource.class);
+        when(secondGrandChild.adaptTo(ValueMap.class)).thenReturn(secondGrandChildMap);
+        when(secondGrandChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildModel());
+
+        Resource secondChild = mock(Resource.class);
+        when(secondChild.listChildren()).thenReturn(Arrays.asList(firstGrandChild, secondGrandChild).iterator());
+
+        Resource emptyChild = mock(Resource.class);
+        when(emptyChild.listChildren()).thenReturn(Collections.<Resource>emptySet().iterator());
+
+        Resource res = mock(Resource.class);
+        when(res.getChild("firstChild")).thenReturn(firstChild);
+        when(res.getChild("secondChild")).thenReturn(secondChild);
+        when(res.getChild("emptyChild")).thenReturn(emptyChild);
+
+        ParentModel model = factory.getAdapter(res, ParentModel.class);
+        assertNotNull(model);
+
+        ChildModel childModel = model.getFirstChild();
+        assertNotNull(childModel);
+        assertEquals(firstValue, childModel.getProperty());
+        assertEquals(2, model.getGrandChildren().size());
+        assertEquals(firstGrandChildValue, model.getGrandChildren().get(0).getProperty());
+        assertEquals(secondGrandChildValue, model.getGrandChildren().get(1).getProperty());
+        assertEquals(0, model.getEmptyGrandChildren().size());
+    }
+
+    private class AdaptToChildModel implements Answer<ChildModel> {
+
+        @Override
+        public ChildModel answer(InvocationOnMock invocation) throws Throwable {
+            return factory.getAdapter(invocation.getMock(), ChildModel.class);
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java b/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
index 0696ff5..2e278e1 100644
--- a/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
+++ b/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
@@ -19,6 +19,7 @@ package org.apache.sling.models.impl;
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Hashtable;
@@ -102,7 +103,7 @@ public class ResourceModelInterfacesTest {
 
         verify(vm).get("required", String.class);
     }
-    
+
     @Test
     public void testChildResource() {
         Resource child = mock(Resource.class);
@@ -136,19 +137,33 @@ public class ResourceModelInterfacesTest {
         Map<String, Object> props = Collections.singletonMap("property", value);
         ValueMap map = new ValueMapDecorator(props);
 
-        final Resource child = mock(Resource.class);
-        when(child.adaptTo(ValueMap.class)).thenReturn(map);
-        when(child.adaptTo(ChildModel.class)).thenAnswer(new Answer<ChildModel>() {
+        final Resource firstChild = mock(Resource.class);
+        when(firstChild.adaptTo(ValueMap.class)).thenReturn(map);
+        when(firstChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildModel());
+
+        Object firstGrandChildValue = RandomStringUtils.randomAlphabetic(10);
+        ValueMap firstGrandChildMap = new ValueMapDecorator(Collections.singletonMap("property", firstGrandChildValue));
+        Object secondGrandChildValue = RandomStringUtils.randomAlphabetic(10);
+        ValueMap secondGrandChildMap = new ValueMapDecorator(Collections.singletonMap("property", secondGrandChildValue));
+
+        final Resource firstGrandChild = mock(Resource.class);
+        when(firstGrandChild.adaptTo(ValueMap.class)).thenReturn(firstGrandChildMap);
+        when(firstGrandChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildModel());
 
-            @Override
-            public ChildModel answer(InvocationOnMock invocation) throws Throwable {
-                return factory.getAdapter(child, ChildModel.class);
-            }
+        final Resource secondGrandChild = mock(Resource.class);
+        when(secondGrandChild.adaptTo(ValueMap.class)).thenReturn(secondGrandChildMap);
+        when(secondGrandChild.adaptTo(ChildModel.class)).thenAnswer(new AdaptToChildModel());
 
-        });
+        Resource secondChild = mock(Resource.class);
+        when(secondChild.listChildren()).thenReturn(Arrays.asList(firstGrandChild, secondGrandChild).iterator());
+
+        Resource emptyChild = mock(Resource.class);
+        when(emptyChild.listChildren()).thenReturn(Collections.<Resource>emptySet().iterator());
 
         Resource res = mock(Resource.class);
-        when(res.getChild("firstChild")).thenReturn(child);
+        when(res.getChild("firstChild")).thenReturn(firstChild);
+        when(res.getChild("secondChild")).thenReturn(secondChild);
+        when(res.getChild("emptyChild")).thenReturn(emptyChild);
 
         ParentModel model = factory.getAdapter(res, ParentModel.class);
         assertNotNull(model);
@@ -156,7 +171,18 @@ public class ResourceModelInterfacesTest {
         ChildModel childModel = model.getFirstChild();
         assertNotNull(childModel);
         assertEquals(value, childModel.getProperty());
+        assertEquals(2, model.getGrandChildren().size());
+        assertEquals(firstGrandChildValue, model.getGrandChildren().get(0).getProperty());
+        assertEquals(secondGrandChildValue, model.getGrandChildren().get(1).getProperty());
+        assertEquals(0, model.getEmptyGrandChildren().size());
     }
 
+    private class AdaptToChildModel implements Answer<ChildModel> {
+
+        @Override
+        public ChildModel answer(InvocationOnMock invocation) throws Throwable {
+            return factory.getAdapter(invocation.getMock(), ChildModel.class);
+        }
+    }
 
 }
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/ParentModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/ParentModel.java
new file mode 100644
index 0000000..7c30148
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/ParentModel.java
@@ -0,0 +1,58 @@
+/*
+ * 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 java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.testmodels.classes.ChildModel;
+
+@Model(adaptables = Resource.class)
+public class ParentModel {
+
+    @Inject
+    public ParentModel(@Named("firstChild") ChildModel firstChild, @Named("secondChild") List<ChildModel> grandChildren,
+            @Named("emptyChild") List<ChildModel> emptyGrandChildren) {
+        this.firstChild = firstChild;
+        this.grandChildren = grandChildren;
+        this.emptyGrandChildren = emptyGrandChildren;
+    }
+
+    private ChildModel firstChild;
+
+    private List<ChildModel> grandChildren;
+
+    private List<ChildModel> emptyGrandChildren;
+
+    public ChildModel getFirstChild() {
+        return firstChild;
+    }
+
+    public List<ChildModel> getGrandChildren() {
+        return grandChildren;
+    }
+
+    public List<ChildModel> getEmptyGrandChildren() {
+        return emptyGrandChildren;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/interfaces/ParentModel.java b/src/test/java/org/apache/sling/models/testmodels/interfaces/ParentModel.java
index 5dceeb5..90c6c65 100644
--- a/src/test/java/org/apache/sling/models/testmodels/interfaces/ParentModel.java
+++ b/src/test/java/org/apache/sling/models/testmodels/interfaces/ParentModel.java
@@ -16,7 +16,10 @@
  */
 package org.apache.sling.models.testmodels.interfaces;
 
+import java.util.List;
+
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.models.annotations.Model;
@@ -26,4 +29,10 @@ public interface ParentModel {
 
     @Inject
     public ChildModel getFirstChild();
+    
+    @Inject @Named("secondChild")
+    public List<ChildModel> getGrandChildren();
+
+    @Inject @Named("emptyChild")
+    public List<ChildModel> getEmptyGrandChildren();
 }

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

[sling-org-apache-sling-models-impl] 17/24: SLING-3894 - removing duplicate type checks in Request and SlingBindings injectors

Posted by ro...@apache.org.
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 3041e7990573cb418cb9e6286f0c45e67360497f
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Thu Aug 28 23:00:37 2014 +0000

    SLING-3894 - removing duplicate type checks in Request and SlingBindings injectors
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1621224 13f79535-47bb-0310-9956-ffa450edef68
---
 .../models/impl/injectors/BindingsInjector.java    |  7 +-----
 .../impl/injectors/RequestAttributeInjector.java   | 26 +---------------------
 .../impl/injectors/BindingsInjectorTest.java       |  7 ------
 .../injectors/RequestAttributeInjectorTest.java    |  7 ------
 4 files changed, 2 insertions(+), 45 deletions(-)

diff --git a/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java
index e2140e2..d816162 100644
--- a/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java
+++ b/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java
@@ -48,12 +48,7 @@ public class BindingsInjector implements Injector, InjectAnnotationProcessorFact
     }
 
     private static Object getValue(SlingBindings bindings, String name, Class<?> type) {
-        Object value = bindings.get(name);
-        if (type.isInstance(value)) {
-            return value;
-        } else {
-            return null;
-        }
+        return bindings.get(name);
     }
 
     public Object getValue(Object adaptable, String name, Type type, AnnotatedElement element,
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/RequestAttributeInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/RequestAttributeInjector.java
index 081bcbf..685e587 100644
--- a/src/main/java/org/apache/sling/models/impl/injectors/RequestAttributeInjector.java
+++ b/src/main/java/org/apache/sling/models/impl/injectors/RequestAttributeInjector.java
@@ -17,7 +17,6 @@
 package org.apache.sling.models.impl.injectors;
 
 import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 
 import javax.servlet.ServletRequest;
@@ -53,30 +52,7 @@ public class RequestAttributeInjector implements Injector, InjectAnnotationProce
         if (!(adaptable instanceof ServletRequest)) {
             return null;
         } else {
-            Object attribute = ((ServletRequest) adaptable).getAttribute(name);
-            if (attribute != null) {
-                if (declaredType instanceof Class<?>) {
-                    Class<?> clazz = (Class<?>) declaredType;
-                    if (clazz.isInstance(attribute)) {
-                        return attribute;
-                    } else {
-                        return null;
-                    }
-                } else if (declaredType instanceof ParameterizedType) {
-                    ParameterizedType parameterizedType = (ParameterizedType) declaredType;
-                    Type rawType = parameterizedType.getRawType();
-                    if (rawType instanceof Class<?>) {
-                        Class<?> clazz = (Class<?>) rawType;
-                        if (clazz.isInstance(attribute)) {
-                            return attribute;
-                        } else {
-                            return null;
-                        }
-                    }
-                }
-                log.debug("RequestAttributeInjector doesn't support type {}, type class {}.", declaredType, declaredType.getClass());
-            }
-            return null;
+            return ((ServletRequest) adaptable).getAttribute(name);
         }
     }
 
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/BindingsInjectorTest.java b/src/test/java/org/apache/sling/models/impl/injectors/BindingsInjectorTest.java
index fa15446..6d0cc66 100644
--- a/src/test/java/org/apache/sling/models/impl/injectors/BindingsInjectorTest.java
+++ b/src/test/java/org/apache/sling/models/impl/injectors/BindingsInjectorTest.java
@@ -23,7 +23,6 @@ import static org.mockito.Mockito.*;
 
 import javax.servlet.ServletRequest;
 
-import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.scripting.SlingBindings;
 import org.junit.Before;
@@ -77,12 +76,6 @@ public class BindingsInjectorTest {
     }
 
     @Test
-    public void testNonMatchingClassInstance() {
-        Object result = injector.getValue(request, CLASS_PARAM, Resource.class, null, null);
-        assertNull(result);
-    }
-
-    @Test
     public void testNonRequestAdaptable() {
         Object result = injector.getValue(mock(ResourceResolver.class), STRING_PARAM, String.class, null, null);
         assertNull(result);
diff --git a/src/test/java/org/apache/sling/models/impl/injectors/RequestAttributeInjectorTest.java b/src/test/java/org/apache/sling/models/impl/injectors/RequestAttributeInjectorTest.java
index 75ac1ca..3176243 100644
--- a/src/test/java/org/apache/sling/models/impl/injectors/RequestAttributeInjectorTest.java
+++ b/src/test/java/org/apache/sling/models/impl/injectors/RequestAttributeInjectorTest.java
@@ -23,7 +23,6 @@ import static org.mockito.Mockito.*;
 
 import javax.servlet.ServletRequest;
 
-import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.junit.Before;
 import org.junit.Test;
@@ -73,12 +72,6 @@ public class RequestAttributeInjectorTest {
     }
 
     @Test
-    public void testNonMatchingClassInstance() {
-        Object result = injector.getValue(request, CLASS_PARAM, Resource.class, null, null);
-        assertNull(result);
-    }
-
-    @Test
     public void testNonRequestAdaptable() {
         Object result = injector.getValue(mock(ResourceResolver.class), STRING_PARAM, String.class, null, null);
         assertNull(result);

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