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:54:42 UTC

[sling-org-apache-sling-models-impl] annotated tag org.apache.sling.models.impl-1.0.0 created (now 8f5d18b)

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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git.


      at 8f5d18b  (tag)
 tagging 41e32f4ab69b1fc9601b5474e7fbe27683e771f2 (commit)
      by Justin Edelson
      on Fri Jan 31 04:30:06 2014 +0000

- Log -----------------------------------------------------------------
org.apache.sling.models.impl-1.0.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 41e32f4  [maven-release-plugin]  copy for tag org.apache.sling.models.impl-1.0.0

The 10 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] 09/10: [maven-release-plugin] prepare release org.apache.sling.models.impl-1.0.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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit 5f168bcbc0d0217946df0170502efe6a3386c970
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jan 31 04:30:03 2014 +0000

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

diff --git a/pom.xml b/pom.xml
index 932673a..1e99449 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>0.0.1-SNAPSHOT</version>
+    <version>1.0.0</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/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.0.0</connection>
+        <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.models.impl-1.0.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.models.impl-1.0.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] 06/10: SLING-3357 - allow a model class to have a single argument constructor which takes the adaptable as a parameter.

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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit e9a5ebd8f6acc142a2849c6d1f58c605b2d38731
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jan 31 04:07:05 2014 +0000

    SLING-3357 - allow a model class to have a single argument constructor which takes the adaptable as a parameter.
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1563049 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/models/impl/ModelAdapterFactory.java     |  61 +++++++++++-
 .../apache/sling/models/impl/ConstructorTest.java  | 104 +++++++++++++++++++++
 .../classes/InvalidConstructorModel.java           |  44 +++++++++
 .../classes/SuperclassConstructorModel.java        |  47 ++++++++++
 .../classes/WithOneConstructorModel.java           |  43 +++++++++
 .../classes/WithThreeConstructorsModel.java        |  58 ++++++++++++
 .../classes/WithTwoConstructorsModel.java          |  46 +++++++++
 7 files changed, 401 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 92fc791..7d29234 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -20,13 +20,17 @@ import java.lang.annotation.Annotation;
 import java.lang.ref.PhantomReference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -70,6 +74,19 @@ 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 Integer.compare(o2.getParameterTypes().length, o1.getParameterTypes().length);
+        }
+
+    }
+
     private static class DisposalCallbackRegistryImpl implements DisposalCallbackRegistry {
 
         private List<DisposalCallback> callbacks = new ArrayList<DisposalCallback>();
@@ -282,11 +299,51 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         return null;
     }
 
+    @SuppressWarnings("unchecked")
     private <AdapterType> AdapterType createObject(Object adaptable, Class<AdapterType> type)
-            throws InstantiationException, IllegalAccessException {
+            throws InstantiationException, InvocationTargetException, IllegalAccessException {
         Set<Field> injectableFields = collectInjectableFields(type);
 
-        AdapterType object = type.newInstance();
+        Constructor<?>[] constructors = type.getConstructors();
+        if (constructors.length == 0) {
+            log.warn("Model class {} does not have a public 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;
+            }
+        }
+
+        if (constructorToUse == null) {
+            log.warn("Model class {} does not have a usable constructor", type.getName());
+            return null;
+        }
+
+        final AdapterType object;
+        if (constructorHasParam) {
+            object = constructorToUse.newInstance(adaptable);
+        } else {
+            object = constructorToUse.newInstance();
+        }
 
         DisposalCallbackRegistryImpl registry = createAndRegisterCallbackRegistry(object);
 
diff --git a/src/test/java/org/apache/sling/models/impl/ConstructorTest.java b/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
new file mode 100644
index 0000000..130818d
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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 org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
+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.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.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ConstructorTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    private ModelAdapterFactory factory;
+
+    @Mock
+    private SlingHttpServletRequest request;
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+
+        when(request.getAttribute("attribute")).thenReturn(42);
+
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(new RequestAttributeInjector(),
+                Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 0L));
+    }
+
+    @Test
+    public void testConstructorInjection() {
+        WithOneConstructorModel model = factory.getAdapter(request, WithOneConstructorModel.class);
+        assertNotNull(model);
+        assertEquals(request, model.getRequest());
+        assertEquals(42, model.getAttribute());
+    }
+
+    @Test
+    public void testThreeConstructorsInjection() {
+        WithThreeConstructorsModel model = factory.getAdapter(request, WithThreeConstructorsModel.class);
+        assertNotNull(model);
+        assertEquals(request, model.getRequest());
+        assertEquals(42, model.getAttribute());
+    }
+
+    @Test
+    public void testTwoConstructorsInjection() {
+        WithTwoConstructorsModel model = factory.getAdapter(request, WithTwoConstructorsModel.class);
+        assertNotNull(model);
+        assertEquals(request, model.getRequest());
+        assertEquals(42, model.getAttribute());
+    }
+
+    @Test
+    public void testSuperclassConstructorsInjection() {
+        SuperclassConstructorModel model = factory.getAdapter(request, SuperclassConstructorModel.class);
+        assertNotNull(model);
+        assertEquals(request, model.getRequest());
+        assertEquals(42, model.getAttribute());
+    }
+
+    @Test
+    public void testInvalidConstructorInjector() {
+        InvalidConstructorModel model = factory.getAdapter(request, InvalidConstructorModel.class);
+        assertNull(model);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java
new file mode 100644
index 0000000..bf032b6
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java
@@ -0,0 +1,44 @@
+/*
+ * 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.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class InvalidConstructorModel {
+
+    private HttpServletResponse response;
+
+    @Inject
+    private int attribute;
+
+    public InvalidConstructorModel(HttpServletResponse response) {
+        this.response = response;
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public HttpServletResponse getResponse() {
+        return response;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java
new file mode 100644
index 0000000..c764fc7
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.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;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class SuperclassConstructorModel {
+
+    private HttpServletRequest request;
+
+    @Inject
+    private int attribute;
+
+    public SuperclassConstructorModel(HttpServletRequest request) {
+        this.request = request;
+    }
+
+    public SuperclassConstructorModel() {
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public HttpServletRequest getRequest() {
+        return request;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java
new file mode 100644
index 0000000..c16b980
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java
@@ -0,0 +1,43 @@
+/*
+ * 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.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class WithOneConstructorModel {
+
+    private final SlingHttpServletRequest request;
+
+    @Inject
+    private int attribute;
+
+    public WithOneConstructorModel(SlingHttpServletRequest request) {
+        this.request = request;
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public SlingHttpServletRequest getRequest() {
+        return request;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java
new file mode 100644
index 0000000..d701341
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.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;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class WithThreeConstructorsModel {
+
+    private SlingHttpServletRequest request;
+    
+    private SlingHttpServletResponse response;
+
+    @Inject
+    private int attribute;
+
+    public WithThreeConstructorsModel(SlingHttpServletRequest request, SlingHttpServletResponse response) {
+        this.request = request;
+        this.response = response;
+    }
+
+    public WithThreeConstructorsModel(SlingHttpServletRequest request) {
+        this.request = request;
+    }
+
+    public WithThreeConstructorsModel() {
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public SlingHttpServletRequest getRequest() {
+        return request;
+    }
+    
+    public SlingHttpServletResponse getResponse() {
+        return response;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java
new file mode 100644
index 0000000..edadf24
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java
@@ -0,0 +1,46 @@
+/*
+ * 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.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class WithTwoConstructorsModel {
+
+    private SlingHttpServletRequest request;
+
+    @Inject
+    private int attribute;
+
+    public WithTwoConstructorsModel(SlingHttpServletRequest request) {
+        this.request = request;
+    }
+
+    public WithTwoConstructorsModel() {
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public SlingHttpServletRequest getRequest() {
+        return request;
+    }
+}

-- 
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/10: using release version

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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit d19376097dddca2ae018e55c400573bf83adbf24
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jan 31 04:24:57 2014 +0000

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

diff --git a/pom.xml b/pom.xml
index 079b51c..932673a 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>0.0.1-SNAPSHOT</version>
+            <version>1.0.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] 01/10: SLING-3313 - adding initial version of Sling Models (nee YAMF)

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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit 58786a9c52601c84b140b31cbe5a8f4cc196ed02
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Wed Jan 22 17:36:40 2014 +0000

    SLING-3313 - adding initial version of Sling Models (nee YAMF)
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1560437 13f79535-47bb-0310-9956-ffa450edef68
---
 README.txt                                         |  24 +
 pom.xml                                            | 142 +++++
 .../sling/models/impl/ModelAdapterFactory.java     | 615 +++++++++++++++++++++
 .../models/impl/ModelPackageBundleListener.java    | 130 +++++
 .../models/impl/injectors/BindingsInjector.java    |  75 +++
 .../impl/injectors/ChildResourceInjector.java      |  46 ++
 .../models/impl/injectors/OSGiServiceInjector.java | 194 +++++++
 .../impl/injectors/RequestAttributeInjector.java   |  60 ++
 .../models/impl/injectors/ValueMapInjector.java    |  65 +++
 .../org/apache/sling/models/impl/DefaultTest.java  |  70 +++
 .../sling/models/impl/MultipleInjectorTest.java    | 128 +++++
 .../sling/models/impl/OSGiInjectionTest.java       | 209 +++++++
 .../sling/models/impl/PostConstructTest.java       |  57 ++
 .../sling/models/impl/RequestInjectionTest.java    |  76 +++
 .../models/impl/ResourceModelClassesTest.java      | 163 ++++++
 .../models/impl/ResourceModelInterfacesTest.java   |  96 ++++
 .../java/org/apache/sling/models/impl/ViaTest.java |  78 +++
 .../models/testmodels/classes/ArrayOSGiModel.java  |  35 ++
 .../models/testmodels/classes/BindingsModel.java   |  37 ++
 .../models/testmodels/classes/ChildModel.java      |  33 ++
 .../testmodels/classes/CollectionOSGiModel.java    |  37 ++
 .../testmodels/classes/DefaultStringModel.java     |  43 ++
 .../models/testmodels/classes/ListOSGiModel.java   |  37 ++
 .../testmodels/classes/RequestOSGiModel.java       |  35 ++
 .../classes/ResourceModelWithRequiredField.java    |  34 ++
 .../models/testmodels/classes/SetOSGiModel.java    |  37 ++
 .../models/testmodels/classes/SimpleOSGiModel.java |  35 ++
 .../testmodels/classes/SimplePropertyModel.java    |  71 +++
 .../sling/models/testmodels/classes/SubClass.java  |  43 ++
 .../models/testmodels/classes/SuperClass.java      |  34 ++
 .../sling/models/testmodels/classes/ViaModel.java  |  36 ++
 .../testmodels/interfaces/ChildResourceModel.java  |  30 +
 .../testmodels/interfaces/ChildValueMapModel.java  |  31 ++
 .../models/testmodels/interfaces/ParentModel.java  |  30 +
 .../interfaces/ResourceModelWithRequiredField.java |  30 +
 .../testmodels/interfaces/ServiceInterface.java    |  21 +
 .../testmodels/interfaces/SimplePropertyModel.java |  43 ++
 37 files changed, 2960 insertions(+)

diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..657f1c7
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,24 @@
+Apache Sling Models Implementation
+
+Getting Started
+===============
+
+This component uses a Maven 2 (http://maven.apache.org/) build
+environment. It requires a Java 5 JDK (or higher) and Maven (http://maven.apache.org/)
+2.0.7 or later. We recommend to use the latest Maven version.
+
+If you have Maven 2 installed, you can compile and
+package the jar using the following command:
+
+    mvn package
+
+See the Maven 2 documentation for other build features.
+
+The latest source code for this component is available in the
+Subversion (http://subversion.tigris.org/) source repository of
+the Apache Software Foundation. If you have Subversion installed,
+you can checkout the latest source using the following command:
+
+    svn checkout http://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/settings
+
+See the Subversion documentation for other source control features.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..079b51c
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>18</version>
+        <relativePath>../../../../parent/pom.xml</relativePath>
+    </parent>
+    <groupId>org.apache.sling</groupId>
+    <artifactId>org.apache.sling.models.impl</artifactId>
+    <packaging>bundle</packaging>
+    <version>0.0.1-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/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>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Embed-Dependency>
+                            *;scope=compile,
+                            org.osgi.compendium;inline="org/osgi/util/tracker/*"</Embed-Dependency>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.models.api</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <version>4.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.inject</groupId>
+            <artifactId>javax.inject</artifactId>
+            <version>1</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>2.5</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.8.3</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
new file mode 100644
index 0000000..39bce98
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -0,0 +1,615 @@
+/*
+ * 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.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.commons.beanutils.PropertyUtils;
+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.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.ServiceUtil;
+import org.apache.sling.models.annotations.Default;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Optional;
+import org.apache.sling.models.annotations.Via;
+import org.apache.sling.models.annotations.Source;
+import org.apache.sling.models.spi.DisposalCallback;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+public class ModelAdapterFactory implements AdapterFactory, Runnable {
+
+    public static class DisposalCallbackRegistryImpl implements DisposalCallbackRegistry {
+
+        private List<DisposalCallback> callbacks = new ArrayList<DisposalCallback>();
+
+        @Override
+        public void addDisposalCallback(DisposalCallback callback) {
+            callbacks.add(callback);
+        }
+
+        private void lock() {
+            callbacks = Collections.unmodifiableList(callbacks);
+        }
+
+        private void onDisposed() {
+            for (DisposalCallback callback : callbacks) {
+                callback.onDisposed();
+            }
+        }
+
+    }
+
+    private ReferenceQueue<Object> queue;
+
+    private ConcurrentMap<java.lang.ref.Reference<Object>, DisposalCallbackRegistryImpl> disposalCallbacks;
+
+    public 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();
+        if (ref != null) {
+            log.info("calling disposal for " + ref.toString());
+            DisposalCallbackRegistryImpl registry = disposalCallbacks.remove(ref);
+            registry.onDisposed();
+        }
+    }
+
+    private static final Logger log = LoggerFactory.getLogger(ModelAdapterFactory.class);
+
+    @Reference(name = "injector", referenceInterface = Injector.class,
+            cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
+    private final Map<Object, Injector> injectors = new TreeMap<Object, Injector>();
+
+    private volatile Injector[] sortedInjectors = new Injector[0];
+
+    private ModelPackageBundleListener listener;
+
+    private ServiceRegistration jobRegistration;
+
+    @SuppressWarnings("unchecked")
+    public <AdapterType> AdapterType getAdapter(Object adaptable, Class<AdapterType> type) {
+        Model modelAnnotation = type.getAnnotation(Model.class);
+        if (modelAnnotation == null) {
+            return null;
+        }
+        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);
+            if (handler != null) {
+                return (AdapterType) Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[] { type },
+                        handler);
+            } else {
+                return null;
+            }
+        } else {
+            try {
+                return createObject(adaptable, type);
+            } catch (Exception e) {
+                log.error("unable to create object", e);
+                return null;
+            }
+        }
+    }
+
+    private Set<Field> collectInjectableFields(Class<?> type) {
+        Set<Field> result = new HashSet<Field>();
+        while (type != null) {
+            Field[] fields = type.getDeclaredFields();
+            for (Field field : fields) {
+                Inject injection = field.getAnnotation(Inject.class);
+                if (injection != null) {
+                    result.add(field);
+                }
+            }
+            type = type.getSuperclass();
+        }
+        return result;
+    }
+
+    private Set<Method> collectInjectableMethods(Class<?> type) {
+        Set<Method> result = new HashSet<Method>();
+        while (type != null) {
+            Method[] methods = type.getDeclaredMethods();
+            for (Method method : methods) {
+                Inject injection = method.getAnnotation(Inject.class);
+                if (injection != null) {
+                    result.add(method);
+                }
+            }
+            type = type.getSuperclass();
+        }
+        return result;
+    }
+
+    private InvocationHandler createInvocationHandler(final Object adaptable, final Class<?> type) {
+        Set<Method> injectableMethods = collectInjectableMethods(type);
+        Map<Method, Object> methods = new HashMap<Method, Object>();
+        MapBackedInvocationHandler handler = new MapBackedInvocationHandler(methods);
+
+        DisposalCallbackRegistryImpl registry = createAndRegisterCallbackRegistry(handler);
+
+        for (Injector injector : sortedInjectors) {
+            Iterator<Method> it = injectableMethods.iterator();
+            while (it.hasNext()) {
+                Method method = it.next();
+                String source = getSource(method);
+                if (source == null || source.equals(injector.getName())) {
+                    String name = getName(method);
+                    Type returnType = mapPrimitiveClasses(method.getGenericReturnType());
+                    Object injectionAdaptable = getAdaptable(adaptable, method);
+                    if (injectionAdaptable != null) {
+                        Object value = injector.getValue(injectionAdaptable, name, returnType, method, registry);
+                        if (setMethod(method, methods, value)) {
+                            it.remove();
+                        }
+                    }
+                }
+            }
+        }
+
+        Iterator<Method> it = injectableMethods.iterator();
+        while (it.hasNext()) {
+            Method method = it.next();
+            Default defaultAnnotation = method.getAnnotation(Default.class);
+            if (defaultAnnotation != null) {
+                Type returnType = mapPrimitiveClasses(method.getGenericReturnType());
+                Object value = getDefaultValue(defaultAnnotation, returnType);
+                if (setMethod(method, methods, value)) {
+                    it.remove();
+                }
+            }
+        }
+
+        if (injectableMethods.isEmpty()) {
+            return handler;
+        } else {
+            Set<Method> requiredMethods = new HashSet<Method>();
+            for (Method method : injectableMethods) {
+                if (method.getAnnotation(Optional.class) == null) {
+                    requiredMethods.add(method);
+                }
+            }
+
+            if (!requiredMethods.isEmpty()) {
+                log.warn("Required methods {} on model class {} were not able to be injected.", requiredMethods,
+                        type);
+                return null;
+            } else {
+                return handler;
+            }
+        }
+    }
+
+    private DisposalCallbackRegistryImpl createAndRegisterCallbackRegistry(Object object) {
+        PhantomReference<Object> reference = new PhantomReference<Object>(object, queue);
+        DisposalCallbackRegistryImpl registry = new DisposalCallbackRegistryImpl();
+        disposalCallbacks.put(reference, registry);
+        return registry;
+    }
+
+    private String getSource(AnnotatedElement element) {
+        Source source = element.getAnnotation(Source.class);
+        if (source != null) {
+            return source.value();
+        } else {
+            for (Annotation ann : element.getAnnotations()) {
+                source = ann.annotationType().getAnnotation(Source.class);
+                if (source != null) {
+                    return source.value();
+                }
+            }
+        }
+        return null;
+    }
+
+    private <AdapterType> AdapterType createObject(Object adaptable, Class<AdapterType> type)
+            throws InstantiationException, IllegalAccessException {
+        Set<Field> injectableFields = collectInjectableFields(type);
+
+        AdapterType object = type.newInstance();
+
+        DisposalCallbackRegistryImpl registry = createAndRegisterCallbackRegistry(object);
+
+        for (Injector injector : sortedInjectors) {
+            Iterator<Field> it = injectableFields.iterator();
+            while (it.hasNext()) {
+                Field field = it.next();
+                String source = getSource(field);
+                if (source == null || source.equals(injector.getName())) {
+                    String name = getName(field);
+                    Type fieldType = mapPrimitiveClasses(field.getGenericType());
+                    Object injectionAdaptable = getAdaptable(adaptable, field);
+                    if (injectionAdaptable != null) {
+                        Object value = injector.getValue(injectionAdaptable, name, fieldType, field, registry);
+                        if (setField(field, object, value)) {
+                            it.remove();
+                        }
+                    }
+                }
+            }
+        }
+
+        Iterator<Field> it = injectableFields.iterator();
+        while (it.hasNext()) {
+            Field field = it.next();
+            Default defaultAnnotation = field.getAnnotation(Default.class);
+            if (defaultAnnotation != null) {
+                Type fieldType = mapPrimitiveClasses(field.getGenericType());
+                Object value = getDefaultValue(defaultAnnotation, fieldType);
+                if (setField(field, object, value)) {
+                    it.remove();
+                }
+            }
+        }
+
+        if (injectableFields.isEmpty()) {
+            try {
+                invokePostConstruct(object);
+                return object;
+            } catch (Exception e) {
+                log.error("Unable to invoke post construct method.", e);
+                return null;
+            }
+        } else {
+            Set<Field> requiredFields = new HashSet<Field>();
+            for (Field field : injectableFields) {
+                if (field.getAnnotation(Optional.class) == null) {
+                    requiredFields.add(field);
+                }
+            }
+
+            if (!requiredFields.isEmpty()) {
+                log.warn("Required properties {} on model class {} were not able to be injected.", requiredFields,
+                        type);
+                return null;
+            } else {
+                try {
+                    invokePostConstruct(object);
+                    return object;
+                } catch (Exception e) {
+                    log.error("Unable to invoke post construct method.", e);
+                    return null;
+                }
+            }
+        }
+    }
+
+    private Object getDefaultValue(Default defaultAnnotation, Type type) {
+        if (type instanceof Class) {
+            Class<?> injectedClass = (Class<?>) type;
+            if (injectedClass.isArray()) {
+                Class<?> componentType = injectedClass.getComponentType();
+                if (componentType == String.class) {
+                    return defaultAnnotation.values();
+                }
+                if (componentType == Integer.TYPE) {
+                    return defaultAnnotation.intValues();
+                }
+                if (componentType == Long.TYPE) {
+                    return defaultAnnotation.longValues();
+                }
+                if (componentType == Boolean.TYPE) {
+                    return defaultAnnotation.booleanValues();
+                }
+                if (componentType == Short.TYPE) {
+                    return defaultAnnotation.shortValues();
+                }
+                if (componentType == Float.TYPE) {
+                    return defaultAnnotation.floatValues();
+                }
+                if (componentType == Double.TYPE) {
+                    return defaultAnnotation.doubleValues();
+                }
+
+                log.warn("Default values for {} are not supported", componentType);
+                return null;
+            } else {
+                if (injectedClass == String.class) {
+                    return defaultAnnotation.values()[0];
+                }
+                if (injectedClass == Integer.TYPE) {
+                    return defaultAnnotation.intValues()[0];
+                }
+                if (injectedClass == Long.TYPE) {
+                    return defaultAnnotation.longValues()[0];
+                }
+                if (injectedClass == Boolean.TYPE) {
+                    return defaultAnnotation.booleanValues()[0];
+                }
+                if (injectedClass == Short.TYPE) {
+                    return defaultAnnotation.shortValues()[0];
+                }
+                if (injectedClass == Float.TYPE) {
+                    return defaultAnnotation.floatValues()[0];
+                }
+                if (injectedClass == Double.TYPE) {
+                    return defaultAnnotation.doubleValues()[0];
+                }
+
+                log.warn("Default values for {} are not supported", injectedClass);
+                return null;
+            }
+        } else {
+            log.warn("Cannot provide default for {}", type);
+            return null;
+        }
+    }
+
+    private Object getAdaptable(Object adaptable, AnnotatedElement point) {
+        Via viaAnnotation = point.getAnnotation(Via.class);
+        if (viaAnnotation == null) {
+            return adaptable;
+        }
+        String viaPropertyName = viaAnnotation.value();
+        try {
+            return PropertyUtils.getProperty(adaptable, viaPropertyName);
+        } catch (Exception e) {
+            log.error("Unable to execution projection " + viaPropertyName, e);
+            return null;
+        }
+    }
+
+    private String getName(Field field) {
+        Named named = field.getAnnotation(Named.class);
+        if (named != null) {
+            return named.value();
+        }
+        return field.getName();
+    }
+
+    private String getName(Method method) {
+        Named named = method.getAnnotation(Named.class);
+        if (named != null) {
+            return named.value();
+        }
+        String methodName = method.getName();
+        if (methodName.startsWith("get")) {
+            return methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
+        } else if (methodName.startsWith("is")) {
+            return methodName.substring(2, 3).toLowerCase() + methodName.substring(3);
+        } else {
+            return methodName;
+        }
+    }
+
+    private void invokePostConstruct(Object object) throws Exception {
+        Class<?> clazz = object.getClass();
+        List<Method> postConstructMethods = new ArrayList<Method>();
+        while (clazz != null) {
+            Method[] methods = clazz.getDeclaredMethods();
+            for (Method method : methods) {
+                if (method.isAnnotationPresent(PostConstruct.class)) {
+                    postConstructMethods.add(method);
+                }
+            }
+            clazz = clazz.getSuperclass();
+        }
+        Collections.reverse(postConstructMethods);
+        for (Method method : postConstructMethods) {
+            boolean accessible = method.isAccessible();
+            try {
+                if (!accessible) {
+                    method.setAccessible(true);
+                }
+                method.invoke(object);
+            } finally {
+                if (!accessible) {
+                    method.setAccessible(false);
+                }
+            }
+        }
+    }
+
+    private Type mapPrimitiveClasses(Type type) {
+        if (type == Integer.TYPE) {
+            return Integer.class;
+        }
+        if (type == Long.TYPE) {
+            return Long.class;
+        }
+        if (type == Boolean.TYPE) {
+            return Boolean.class;
+        }
+        if (type == Double.TYPE) {
+            return Double.class;
+        }
+        if (type == Float.TYPE) {
+            return Float.class;
+        }
+        if (type == Short.TYPE) {
+            return Short.class;
+        }
+        if (type == Character.TYPE) {
+            return Character.class;
+        }
+
+        return type;
+    }
+
+    private boolean setField(Field field, Object createdObject, Object value) {
+        if (value != null) {
+            if (!isAcceptableType(field.getClass(), value) && value instanceof Adaptable) {
+                value = ((Adaptable) value).adaptTo(field.getClass());
+                if (value == null) {
+                    return false;
+                }
+            }
+            boolean accessible = field.isAccessible();
+            try {
+                if (!accessible) {
+                    field.setAccessible(true);
+                }
+                field.set(createdObject, value);
+                return true;
+            } catch (Exception e) {
+                log.error("unable to inject field", e);
+                return false;
+            } finally {
+                if (!accessible) {
+                    field.setAccessible(false);
+                }
+            }
+        } else {
+            return false;
+        }
+    }
+
+    private boolean setMethod(Method method, Map<Method, Object> methods, Object value) {
+        if (value != null) {
+            if (!isAcceptableType(method.getReturnType(), value) && value instanceof Adaptable) {
+                value = ((Adaptable) value).adaptTo(method.getReturnType());
+                if (value == null) {
+                    return false;
+                }
+            }
+            methods.put(method, value);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private boolean isAcceptableType(Class<?> type, Object value) {
+        if (type.isInstance(value)) {
+            return true;
+        }
+
+        if (type == Integer.TYPE) {
+            return Integer.class.isInstance(value);
+        }
+        if (type == Long.TYPE) {
+            return Long.class.isInstance(value);
+        }
+        if (type == Boolean.TYPE) {
+            return Boolean.class.isInstance(value);
+        }
+        if (type == Double.TYPE) {
+            return Double.class.isInstance(value);
+        }
+        if (type == Float.TYPE) {
+            return Float.class.isInstance(value);
+        }
+        if (type == Short.TYPE) {
+            return Short.class.isInstance(value);
+        }
+        if (type == Character.TYPE) {
+            return Character.class.isInstance(value);
+        }
+
+        return false;
+    }
+
+    @Activate
+    protected void activate(final ComponentContext ctx) {
+        this.queue = new ReferenceQueue<Object>();
+        this.disposalCallbacks = new ConcurrentHashMap<java.lang.ref.Reference<Object>, DisposalCallbackRegistryImpl>();
+        Hashtable<Object, Object> properties = new Hashtable<Object, Object>();
+        properties.put("scheduler.concurrent", false);
+        properties.put("scheduler.period", Long.valueOf(30));
+
+        this.jobRegistration = ctx.getBundleContext().registerService(Runnable.class.getName(), this,
+                properties);
+
+        this.listener = new ModelPackageBundleListener(ctx.getBundleContext(), this);
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        this.listener.unregisterAll();
+        if (jobRegistration != null) {
+            jobRegistration.unregister();
+            jobRegistration = null;
+        }
+    }
+
+    protected void bindInjector(final Injector injector, final Map<String, Object> props) {
+        synchronized (injectors) {
+            injectors.put(ServiceUtil.getComparableForServiceRanking(props), injector);
+            sortedInjectors = injectors.values().toArray(new Injector[injectors.size()]);
+        }
+    }
+
+    protected void unbindInjector(final Injector injector, final Map<String, Object> props) {
+        synchronized (injectors) {
+            injectors.remove(ServiceUtil.getComparableForServiceRanking(props));
+            sortedInjectors = injectors.values().toArray(new Injector[injectors.size()]);
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java b/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
new file mode 100644
index 0000000..ba45ca0
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
@@ -0,0 +1,130 @@
+/*
+ * 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.net.URL;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+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.ServiceRegistration;
+import org.osgi.util.tracker.BundleTracker;
+import org.osgi.util.tracker.BundleTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ModelPackageBundleListener implements BundleTrackerCustomizer {
+
+    private static final String HEADER = "Sling-Model-Packages";
+
+    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) {
+        this.bundleContext = bundleContext;
+        this.factory = factory;
+        this.bundleTracker = new BundleTracker(bundleContext, Bundle.ACTIVE, this);
+        this.bundleTracker.open();
+    }
+    
+    @Override
+    public Object addingBundle(Bundle bundle, BundleEvent event) {
+List<ServiceRegistration> regs = new ArrayList<ServiceRegistration>();
+        
+        Dictionary<?, ?> headers = bundle.getHeaders();
+        String packageList = PropertiesUtil.toString(headers.get(HEADER), null);
+        if (packageList != null) {
+
+            packageList = StringUtils.deleteWhitespace(packageList);
+            String[] packages = packageList.split(",");
+            for (String singlePackage : packages) {
+                @SuppressWarnings("unchecked")
+                Enumeration<URL> classUrls = bundle.findEntries("/" + singlePackage.replace('.', '/'), "*.class",
+                        true);
+                while (classUrls.hasMoreElements()) {
+                    URL url = classUrls.nextElement();
+                    String className = toClassName(url);
+                    try {
+                        Class<?> clazz = bundle.loadClass(className);
+                        Model annotation = clazz.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);
+                            ServiceRegistration reg = bundleContext.registerService(AdapterFactory.SERVICE_NAME,
+                                    factory, registrationProps);
+                            regs.add(reg);
+                        }
+                    } catch (ClassNotFoundException e) {
+                        log.warn("Unable to load class", e);
+                    }
+
+                }
+            }
+        }
+        return regs.toArray(new ServiceRegistration[0]);
+    }
+
+    @Override
+    public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
+    }
+
+    @Override
+    public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+        if (object instanceof ServiceRegistration[]) {
+            for (ServiceRegistration reg : (ServiceRegistration[]) object) {
+                reg.unregister();
+            }
+        }
+    }
+
+    public synchronized void unregisterAll() {
+        this.bundleTracker.close();
+    }
+
+    /** Convert class URL to class name */
+    private String toClassName(URL url) {
+        final String f = url.getFile();
+        final String cn = f.substring(1, f.length() - ".class".length());
+        return cn.replace('/', '.');
+    }
+
+    private String[] toStringArray(Class<?>[] classes) {
+        String[] arr = new String[classes.length];
+        for (int i = 0; i < classes.length; i++) {
+            arr[i] = classes[i].getName();
+        }
+        return arr;
+    }
+
+}
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
new file mode 100644
index 0000000..2a6fcc3
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/BindingsInjector.java
@@ -0,0 +1,75 @@
+/*
+ * 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.ServletRequest;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+@Service
+public class BindingsInjector implements Injector {
+
+    private static final Logger log = LoggerFactory.getLogger(BindingsInjector.class);
+
+    @Override
+    public String getName() {
+        return "script-bindings";
+    }
+
+    private static Object getValue(SlingBindings bindings, String name, Class<?> type) {
+        Object value = bindings.get(name);
+        if (type.isInstance(value)) {
+            return value;
+        } else {
+            return null;
+        }
+    }
+
+    public Object getValue(Object adaptable, String name, Type type, AnnotatedElement element, DisposalCallbackRegistry callbackRegistry) {
+        SlingBindings bindings = getBindings(adaptable);
+        if (bindings == null) {
+            return null;
+        }
+        if (type instanceof Class<?>) {
+            return getValue(bindings, name, (Class<?>) type);
+        } else {
+            log.debug("BindingsInjector doesn't support non-class type {}", type);
+            return null;
+        }
+
+    }
+
+    private SlingBindings getBindings(Object adaptable) {
+        if (adaptable instanceof ServletRequest) {
+            ServletRequest request = (ServletRequest) adaptable;
+            return (SlingBindings) request.getAttribute(SlingBindings.class.getName());
+        } else {
+            return null;
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/ChildResourceInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/ChildResourceInjector.java
new file mode 100644
index 0000000..6afec71
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/ChildResourceInjector.java
@@ -0,0 +1,46 @@
+/*
+ * 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.Service;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+
+@Component
+@Service
+public class ChildResourceInjector implements Injector {
+
+    @Override
+    public String getName() {
+        return "child-resources";
+    }
+
+    @Override
+    public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element, DisposalCallbackRegistry callbackRegistry) {
+        if (adaptable instanceof Resource) {
+            return ((Resource) adaptable).getChild(name);
+        } else {
+            return null;
+        }
+    }
+
+}
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
new file mode 100644
index 0000000..f19c9ed
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java
@@ -0,0 +1,194 @@
+/*
+ * 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.Array;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import javax.servlet.ServletRequest;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.models.annotations.Filter;
+import org.apache.sling.models.spi.DisposalCallback;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+@Service
+public class OSGiServiceInjector implements Injector {
+
+    private static final Logger log = LoggerFactory.getLogger(OSGiServiceInjector.class);
+
+    private BundleContext bundleContext;
+
+    @Override
+    public String getName() {
+        return "osgi-services";
+    }
+
+    @Activate
+    public void activate(ComponentContext ctx) {
+        this.bundleContext = ctx.getBundleContext();
+    }
+
+    public Object getValue(Object adaptable, String name, Type type, AnnotatedElement element, DisposalCallbackRegistry callbackRegistry) {
+        Filter filter = element.getAnnotation(Filter.class);
+        String filterString = null;
+        if (filter != null) {
+            filterString = filter.value();
+        }
+
+        return getValue(adaptable, type, filterString, callbackRegistry);
+    }
+
+    private <T> Object getService(Object adaptable, Class<T> type, String filter, DisposalCallbackRegistry callbackRegistry) {
+        SlingScriptHelper helper = getScriptHelper(adaptable);
+
+        if (helper != null) {
+            T[] services = helper.getServices(type, filter);
+            if (services == null || services.length == 0) {
+                return null;
+            } else {
+                return services[0];
+            }
+        } else {
+            try {
+                ServiceReference[] refs = bundleContext.getServiceReferences(type.getName(), filter);
+                if (refs == null || refs.length == 0) {
+                    return null;
+                } else {
+                    callbackRegistry.addDisposalCallback(new Callback(refs, bundleContext));
+                    return bundleContext.getService(refs[0]);
+                }
+            } catch (InvalidSyntaxException e) {
+                log.error("invalid filter expression", e);
+                return null;
+            }
+        }
+    }
+
+    private <T> Object[] getServices(Object adaptable, Class<T> type, String filter, DisposalCallbackRegistry callbackRegistry) {
+        SlingScriptHelper helper = getScriptHelper(adaptable);
+
+        if (helper != null) {
+            T[] services = helper.getServices(type, filter);
+            return services;
+        } else {
+            try {
+                ServiceReference[] refs = bundleContext.getServiceReferences(type.getName(), filter);
+                if (refs == null || refs.length == 0) {
+                    return null;
+                } else {
+                    callbackRegistry.addDisposalCallback(new Callback(refs, bundleContext));
+                    List<Object> services = new ArrayList<Object>();
+                    for (ServiceReference ref : refs) {
+                        Object service = bundleContext.getService(ref);
+                        if (service != null) {
+                            services.add(service);
+                        }
+                    }
+                    return services.toArray();
+                }
+            } catch (InvalidSyntaxException e) {
+                log.error("invalid filter expression", e);
+                return null;
+            }
+        }
+    }
+
+    private SlingScriptHelper getScriptHelper(Object adaptable) {
+        if (adaptable instanceof ServletRequest) {
+            ServletRequest request = (ServletRequest) adaptable;
+            SlingBindings bindings = (SlingBindings) request.getAttribute(SlingBindings.class.getName());
+            if (bindings != null) {
+                return bindings.getSling();
+            } else {
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    private Object getValue(Object adaptable, Type type, String filterString, DisposalCallbackRegistry callbackRegistry) {
+        if (type instanceof Class) {
+            Class<?> injectedClass = (Class<?>) type;
+            if (injectedClass.isArray()) {
+                Object[] services = getServices(adaptable, injectedClass.getComponentType(), filterString, callbackRegistry);
+                Object arr = Array.newInstance(injectedClass.getComponentType(), services.length);
+                for (int i = 0; i < services.length; i++) {
+                    Array.set(arr, i, services[i]);
+                }
+                return arr;
+            } else {
+                return getService(adaptable, injectedClass, filterString, callbackRegistry);
+            }
+        } else if (type instanceof ParameterizedType) {
+            ParameterizedType ptype = (ParameterizedType) type;
+            if (ptype.getActualTypeArguments().length != 1) {
+                return null;
+            }
+            Class<?> collectionType = (Class<?>) ptype.getRawType();
+            if (!(collectionType.equals(Collection.class) || collectionType.equals(List.class))) {
+                return null;
+            }
+
+            Class<?> serviceType = (Class<?>) ptype.getActualTypeArguments()[0];
+            Object[] services = getServices(adaptable, serviceType, filterString, callbackRegistry);
+            return Arrays.asList(services);
+        } else {
+            log.warn("Cannot handle type {}", type);
+            return null;
+        }
+    }
+    
+    private static class Callback implements DisposalCallback {
+        private final ServiceReference[] refs;
+        private final BundleContext context;
+        
+        public Callback(ServiceReference[] refs, BundleContext context) {
+            this.refs = refs;
+            this.context = context;
+        }
+        
+        @Override
+        public void onDisposed() {
+            if (refs != null) {
+                for (ServiceReference ref : refs) {
+                    context.ungetService(ref);
+                }
+            }
+        }
+    }
+
+}
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
new file mode 100644
index 0000000..ccd7138
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/RequestAttributeInjector.java
@@ -0,0 +1,60 @@
+/*
+ * 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.ServletRequest;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+@Service
+public class RequestAttributeInjector implements Injector {
+
+    private static final Logger log = LoggerFactory.getLogger(RequestAttributeInjector.class);
+    
+    @Override
+    public String getName() {
+        return "request-attributes";
+    }
+
+    @Override
+    public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element, DisposalCallbackRegistry callbackRegistry) {
+        if (!(adaptable instanceof ServletRequest)) {
+            return null;
+        } else if (declaredType instanceof Class<?>) {
+            Class<?> clazz = (Class<?>) declaredType;
+            Object attribute = ((ServletRequest)adaptable).getAttribute(name);
+            if (clazz.isInstance(attribute)) {
+                return attribute;
+            } else {
+                return null;
+            }
+        } else {
+            log.debug("BindingsInjector doesn't support non-class type {}", declaredType);
+            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
new file mode 100644
index 0000000..f81fb35
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java
@@ -0,0 +1,65 @@
+/*
+ * 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.Service;
+import org.apache.sling.api.adapter.Adaptable;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component
+@Service
+public class ValueMapInjector implements Injector {
+
+    private static final Logger log = LoggerFactory.getLogger(ValueMapInjector.class);
+    
+    @Override
+    public String getName() {
+        return "valuemap";
+    }
+
+    public Object getValue(Object adaptable, String name, Type type, AnnotatedElement element, DisposalCallbackRegistry callbackRegistry) {
+        ValueMap map = getMap(adaptable);
+        if (map == null) {
+            return null;
+        } else if (type instanceof Class<?>) {
+            return map.get(name, (Class<?>) type);
+        } else {
+            log.debug("ValueMapInjector doesn't support non-class types {}", type);
+            return null;
+        }
+    }
+
+    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;
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/DefaultTest.java b/src/test/java/org/apache/sling/models/impl/DefaultTest.java
new file mode 100644
index 0000000..a0ca9e7
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/DefaultTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 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.testmodels.classes.DefaultStringModel;
+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.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DefaultTest {
+
+    @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(),
+                Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 0L));
+    }
+
+    @Test
+    public void testDefaultStringValue() {
+        ValueMap vm = new ValueMapDecorator(Collections.<String, Object>emptyMap());
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        DefaultStringModel model = factory.getAdapter(res, DefaultStringModel.class);
+        assertNotNull(model);
+        assertEquals("firstDefault", model.getFirstProperty());
+        assertEquals(2, model.getSecondProperty().length);
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java b/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java
new file mode 100644
index 0000000..087c075
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/MultipleInjectorTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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 javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Source;
+import org.apache.sling.models.impl.injectors.BindingsInjector;
+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.Spy;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MultipleInjectorTest {
+
+    @Spy
+    private BindingsInjector bindingsInjector;
+
+    @Spy
+    private RequestAttributeInjector attributesInjector;
+
+    @Mock
+    private SlingHttpServletRequest request;
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    private ModelAdapterFactory factory;
+
+    private SlingBindings bindings;
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        bindings = new SlingBindings();
+
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(bindingsInjector, Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 2L));
+        factory.bindInjector(attributesInjector,
+                Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 1L));
+
+        when(request.getAttribute(SlingBindings.class.getName())).thenReturn(bindings);
+    }
+
+    @Test
+    public void testInjectorOrder() {
+        String bindingsValue = "bindings value";
+        bindings.put("firstAttribute", bindingsValue);
+
+        String attributeValue = "attribute value";
+        when(request.getAttribute("firstAttribute")).thenReturn(attributeValue);
+
+        ForTwoInjectors obj = factory.getAdapter(request, ForTwoInjectors.class);
+
+        assertNotNull(obj);
+        assertEquals(obj.firstAttribute, bindingsValue);
+
+        verifyNoMoreInteractions(attributesInjector);
+    }
+
+    @Test
+    public void testInjectorOrderWithSource() {
+        String bindingsValue = "bindings value";
+        bindings.put("firstAttribute", bindingsValue);
+
+        String attributeValue = "attribute value";
+        when(request.getAttribute("firstAttribute")).thenReturn(attributeValue);
+
+        ForTwoInjectorsWithSource obj = factory.getAdapter(request, ForTwoInjectorsWithSource.class);
+
+        assertNotNull(obj);
+        assertEquals(obj.firstAttribute, attributeValue);
+
+        verify(bindingsInjector).getName();
+        verifyNoMoreInteractions(bindingsInjector);
+    }
+
+    @Model(adaptables = SlingHttpServletRequest.class)
+    public static class ForTwoInjectors {
+
+        @Inject
+        private String firstAttribute;
+
+    }
+
+    @Model(adaptables = SlingHttpServletRequest.class)
+    public static class ForTwoInjectorsWithSource {
+
+        @Inject
+        @Source("request-attributes")
+        private String firstAttribute;
+
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java b/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
new file mode 100644
index 0000000..a7989ee
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.Dictionary;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.models.impl.injectors.OSGiServiceInjector;
+import org.apache.sling.models.testmodels.classes.ArrayOSGiModel;
+import org.apache.sling.models.testmodels.classes.CollectionOSGiModel;
+import org.apache.sling.models.testmodels.classes.ListOSGiModel;
+import org.apache.sling.models.testmodels.classes.RequestOSGiModel;
+import org.apache.sling.models.testmodels.classes.SetOSGiModel;
+import org.apache.sling.models.testmodels.classes.SimpleOSGiModel;
+import org.apache.sling.models.testmodels.interfaces.ServiceInterface;
+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.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class OSGiInjectionTest {
+    private ModelAdapterFactory factory;
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    @Mock
+    private SlingScriptHelper helper;
+
+    private SlingBindings bindings = new SlingBindings();
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+
+        OSGiServiceInjector injectorFactory = new OSGiServiceInjector();
+        injectorFactory.activate(componentCtx);
+        factory.bindInjector(injectorFactory, Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 0L));
+
+        bindings.setSling(helper);
+    }
+
+    @Test
+    public void testSimpleOSGiModel() 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);
+
+        SimpleOSGiModel model = factory.getAdapter(res, SimpleOSGiModel.class);
+        assertNotNull(model);
+        assertNotNull(model.getService());
+        assertEquals(service, model.getService());
+
+        verifyNoMoreInteractions(res);
+    }
+
+    @Test
+    public void testRequestOSGiModel() throws Exception {
+        ServiceInterface service = mock(ServiceInterface.class);
+
+        SlingHttpServletRequest request = mock(SlingHttpServletRequest.class);
+        when(request.getAttribute(SlingBindings.class.getName())).thenReturn(bindings);
+
+        when(helper.getServices(ServiceInterface.class, null)).thenReturn(new ServiceInterface[] { service });
+
+        RequestOSGiModel model = factory.getAdapter(request, RequestOSGiModel.class);
+        assertNotNull(model);
+        assertNotNull(model.getService());
+        assertEquals(service, model.getService());
+
+        verify(bundleContext).registerService(eq(Runnable.class.getName()), eq(factory), any(Dictionary.class));
+        verify(bundleContext).addBundleListener(any(BundleListener.class));
+        verify(bundleContext).getBundles();
+        verifyNoMoreInteractions(bundleContext);
+    }
+
+    @Test
+    public void testListOSGiModel() 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);
+
+        ListOSGiModel model = factory.getAdapter(res, 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);
+    }
+
+    @Test
+    public void testArrayOSGiModel() 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);
+
+        ArrayOSGiModel model = factory.getAdapter(res, ArrayOSGiModel.class);
+        assertNotNull(model);
+        assertNotNull(model.getServices());
+        assertEquals(2, model.getServices().length);
+        assertEquals(service1, model.getServices()[0]);
+        assertEquals(service2, model.getServices()[1]);
+
+        verifyNoMoreInteractions(res);
+    }
+
+    @Test
+    public void testCollectionOSGiModel() 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);
+
+        CollectionOSGiModel model = factory.getAdapter(res, CollectionOSGiModel.class);
+        assertNotNull(model);
+        assertNotNull(model.getServices());
+        assertEquals(2, model.getServices().size());
+
+        assertTrue(model.getServices().contains(service1));
+        assertTrue(model.getServices().contains(service2));
+
+        verifyNoMoreInteractions(res);
+    }
+
+    @Test
+    public void testSetOSGiModel() 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);
+
+        SetOSGiModel model = factory.getAdapter(res, SetOSGiModel.class);
+        assertNull(model);
+
+        verify(bundleContext).registerService(eq(Runnable.class.getName()), eq(factory), any(Dictionary.class));
+        verify(bundleContext).addBundleListener(any(BundleListener.class));
+        verify(bundleContext).getBundles();
+        verifyNoMoreInteractions(res, bundleContext);
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/impl/PostConstructTest.java b/src/test/java/org/apache/sling/models/impl/PostConstructTest.java
new file mode 100644
index 0000000..7b59be4
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/PostConstructTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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 org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.testmodels.classes.SubClass;
+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 PostConstructTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+    }
+
+    @Test
+    public void testClassOrder() {
+        Resource r = mock(Resource.class);
+        ModelAdapterFactory factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        // no injectors are necessary
+        
+        SubClass sc = factory.getAdapter(r, SubClass.class);
+        assertTrue(sc.getPostConstructCalledTimestampInSub() > sc.getPostConstructCalledTimestampInSuper());
+        assertTrue(sc.getPostConstructCalledTimestampInSuper() > 0);
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java b/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
new file mode 100644
index 0000000..8a48ef0
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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 org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.models.impl.injectors.BindingsInjector;
+import org.apache.sling.models.testmodels.classes.BindingsModel;
+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.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RequestInjectionTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    private ModelAdapterFactory factory;
+
+    @Mock
+    private SlingHttpServletRequest request;
+
+    @Mock
+    private SlingScriptHelper sling;
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+
+        SlingBindings bindings = new SlingBindings();
+        bindings.setSling(sling);
+        when(request.getAttribute(SlingBindings.class.getName())).thenReturn(bindings);
+
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(new BindingsInjector(),
+                Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 0L));
+    }
+
+    @Test
+    public void testNamedInjection() {
+        BindingsModel model = factory.getAdapter(request, BindingsModel.class);
+        assertNotNull(model.getSling());
+        assertEquals(sling, model.getSling());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java b/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
new file mode 100644
index 0000000..46e825a
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.HashMap;
+import java.util.Map;
+
+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.ResourceModelWithRequiredField;
+import org.apache.sling.models.testmodels.classes.SimplePropertyModel;
+import org.apache.sling.models.testmodels.interfaces.ChildResourceModel;
+import org.apache.sling.models.testmodels.interfaces.ChildValueMapModel;
+import org.apache.sling.models.testmodels.interfaces.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.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ResourceModelClassesTest {
+
+    @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(),
+                Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 1L));
+        factory.bindInjector(new ChildResourceInjector(),
+                Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 0L));
+    }
+
+    @Test
+    public void testSimplePropertyModel() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("first", "first-value");
+        map.put("third", "third-value");
+        map.put("intProperty", new Integer(3));
+        ValueMap vm = new ValueMapDecorator(map);
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        SimplePropertyModel model = factory.getAdapter(res, SimplePropertyModel.class);
+        assertNotNull(model);
+        assertEquals("first-value", model.getFirst());
+        assertNull(model.getSecond());
+        assertEquals("third-value", model.getThirdProperty());
+        assertEquals(3, model.getIntProperty());
+        assertTrue(model.isPostConstructCalled());
+    }
+
+    @Test
+    public void testRequiredPropertyModel() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("first", "first-value");
+        map.put("third", "third-value");
+        ValueMap vm = spy(new ValueMapDecorator(map));
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        ResourceModelWithRequiredField model = factory.getAdapter(res, ResourceModelWithRequiredField.class);
+        assertNull(model);
+
+        verify(vm).get("required", String.class);
+    }
+
+    @Test
+    public void testChildResource() {
+        Resource child = mock(Resource.class);
+
+        Resource res = mock(Resource.class);
+        when(res.getChild("firstChild")).thenReturn(child);
+
+        ChildResourceModel model = factory.getAdapter(res, ChildResourceModel.class);
+        assertNotNull(model);
+        assertEquals(child, model.getFirstChild());
+    }
+
+    @Test
+    public void testChildValueMap() {
+        ValueMap map = ValueMapDecorator.EMPTY;
+
+        Resource child = mock(Resource.class);
+        when(child.adaptTo(ValueMap.class)).thenReturn(map);
+
+        Resource res = mock(Resource.class);
+        when(res.getChild("firstChild")).thenReturn(child);
+
+        ChildValueMapModel model = factory.getAdapter(res, ChildValueMapModel.class);
+        assertNotNull(model);
+        assertEquals(map, model.getFirstChild());
+    }
+
+    @Test
+    public void testChildModel() {
+        Object value = RandomStringUtils.randomAlphabetic(10);
+        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>() {
+
+            @Override
+            public ChildModel answer(InvocationOnMock invocation) throws Throwable {
+                return factory.getAdapter(child, ChildModel.class);
+            }
+
+        });
+
+        Resource res = mock(Resource.class);
+        when(res.getChild("firstChild")).thenReturn(child);
+
+        ParentModel model = factory.getAdapter(res, ParentModel.class);
+        assertNotNull(model);
+        
+        ChildModel childModel = model.getFirstChild();
+        assertNotNull(childModel);
+        assertEquals(value, childModel.getProperty());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java b/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
new file mode 100644
index 0000000..6d1b0c8
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ResourceModelInterfacesTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.mockito.Mockito.*;
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+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.testmodels.classes.ResourceModelWithRequiredField;
+import org.apache.sling.models.testmodels.interfaces.SimplePropertyModel;
+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.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ResourceModelInterfacesTest {
+
+    @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(),
+                Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 0L));
+    }
+
+    @Test
+    public void testSimplePropertyModel() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("first", "first-value");
+        map.put("third", "third-value");
+        map.put("fourth", true);
+        ValueMap vm = new ValueMapDecorator(map);
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        SimplePropertyModel model = factory.getAdapter(res, SimplePropertyModel.class);
+        assertNotNull(model);
+        assertEquals("first-value", model.getFirst());
+        assertNull(model.getSecond());
+        assertEquals("third-value", model.getThirdProperty());
+        assertTrue(model.isFourth());
+    }
+
+    @Test
+    public void testRequiredPropertyModel() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("first", "first-value");
+        map.put("third", "third-value");
+        ValueMap vm = spy(new ValueMapDecorator(map));
+
+        Resource res = mock(Resource.class);
+        when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+        ResourceModelWithRequiredField model = factory.getAdapter(res, ResourceModelWithRequiredField.class);
+        assertNull(model);
+
+        verify(vm).get("required", String.class);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/impl/ViaTest.java b/src/test/java/org/apache/sling/models/impl/ViaTest.java
new file mode 100644
index 0000000..0485030
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ViaTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.mockito.Mockito.*;
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+
+import org.apache.commons.lang.RandomStringUtils;
+import org.apache.sling.api.SlingHttpServletRequest;
+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.testmodels.classes.ViaModel;
+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.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ViaTest {
+
+    @Mock
+    private Resource resource;
+
+    @Mock
+    private SlingHttpServletRequest request;
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+    
+    private ModelAdapterFactory factory;
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(request.getResource()).thenReturn(resource);
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(new ValueMapInjector(),
+                Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 0L));
+    }
+
+    @Test
+    public void testProjectionToResource() {
+        String value = RandomStringUtils.randomAlphanumeric(10);
+        ValueMap map = new ValueMapDecorator(Collections.<String, Object> singletonMap("firstProperty", value));
+        when(resource.adaptTo(ValueMap.class)).thenReturn(map);
+        
+        ViaModel model = factory.getAdapter(request, ViaModel.class);
+        assertNotNull(model);
+        assertEquals(value, model.getFirstProperty());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/ArrayOSGiModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/ArrayOSGiModel.java
new file mode 100644
index 0000000..3e31a97
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/ArrayOSGiModel.java
@@ -0,0 +1,35 @@
+/*
+ * 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.testmodels.interfaces.ServiceInterface;
+
+@Model(adaptables = Resource.class)
+public class ArrayOSGiModel {
+    
+    @Inject
+    private ServiceInterface[] services;
+    
+    public ServiceInterface[] getServices() {
+        return services;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.java
new file mode 100644
index 0000000..342b9cf
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/BindingsModel.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.testmodels.classes;
+
+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)
+public class BindingsModel {
+    
+    @Inject
+    @Named("sling")
+    private SlingScriptHelper sling;
+    
+    public SlingScriptHelper getSling() {
+        return sling;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/ChildModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/ChildModel.java
new file mode 100644
index 0000000..071e37f
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/ChildModel.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+@Model(adaptables = Resource.class)
+public class ChildModel {
+
+    @Inject
+    private String property;
+    
+    public String getProperty() {
+        return property;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/CollectionOSGiModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/CollectionOSGiModel.java
new file mode 100644
index 0000000..115b5e4
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/CollectionOSGiModel.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.testmodels.classes;
+
+import java.util.Collection;
+
+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)
+public class CollectionOSGiModel {
+    
+    @Inject
+    private Collection<ServiceInterface> services;
+    
+    public Collection<ServiceInterface> getServices() {
+        return services;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/DefaultStringModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/DefaultStringModel.java
new file mode 100644
index 0000000..fecfcb0
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/DefaultStringModel.java
@@ -0,0 +1,43 @@
+/*
+ * 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.Default;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+public class DefaultStringModel {
+
+    @Inject
+    @Default(values = "firstDefault")
+    private String firstProperty;
+
+    @Inject
+    @Default(values = { "firstDefault", "secondDefault" })
+    private String[] secondProperty;
+
+    public String getFirstProperty() {
+        return firstProperty;
+    }
+
+    public String[] getSecondProperty() {
+        return secondProperty;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/ListOSGiModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/ListOSGiModel.java
new file mode 100644
index 0000000..33b2ed4
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/ListOSGiModel.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.testmodels.classes;
+
+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)
+public class ListOSGiModel {
+    
+    @Inject
+    private List<ServiceInterface> services;
+    
+    public List<ServiceInterface> getServices() {
+        return services;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/RequestOSGiModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/RequestOSGiModel.java
new file mode 100644
index 0000000..253e9ef
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/RequestOSGiModel.java
@@ -0,0 +1,35 @@
+/*
+ * 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.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.testmodels.interfaces.ServiceInterface;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class RequestOSGiModel {
+    
+    @Inject
+    private ServiceInterface service;
+    
+    public ServiceInterface getService() {
+        return service;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java b/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.java
new file mode 100644
index 0000000..8ebc5f6
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/ResourceModelWithRequiredField.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;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+public class ResourceModelWithRequiredField {
+    
+    @Inject
+    private String required;
+    
+    public String getRequired() {
+        return required;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SetOSGiModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/SetOSGiModel.java
new file mode 100644
index 0000000..9e185c6
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SetOSGiModel.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.testmodels.classes;
+
+import java.util.Set;
+
+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)
+public class SetOSGiModel {
+    
+    @Inject
+    private Set<ServiceInterface> services;
+    
+    public Set<ServiceInterface> getServices() {
+        return services;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SimpleOSGiModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/SimpleOSGiModel.java
new file mode 100644
index 0000000..1fc3d62
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SimpleOSGiModel.java
@@ -0,0 +1,35 @@
+/*
+ * 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.testmodels.interfaces.ServiceInterface;
+
+@Model(adaptables = Resource.class)
+public class SimpleOSGiModel {
+    
+    @Inject
+    private ServiceInterface service;
+    
+    public ServiceInterface getService() {
+        return service;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SimplePropertyModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/SimplePropertyModel.java
new file mode 100644
index 0000000..ddd3b2f
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SimplePropertyModel.java
@@ -0,0 +1,71 @@
+/*
+ * 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.annotation.PostConstruct;
+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;
+
+@Model(adaptables = Resource.class)
+public class SimplePropertyModel {
+
+    @Inject
+    private String first;
+
+    @Inject
+    @Optional
+    private String second;
+
+    @Inject
+    @Named("third")
+    private String thirdProperty;
+
+    @Inject
+    private int intProperty;
+
+    private boolean postConstructCalled;
+
+    public int getIntProperty() {
+        return intProperty;
+    }
+
+    public String getFirst() {
+        return first;
+    }
+
+    public String getSecond() {
+        return second;
+    }
+
+    public String getThirdProperty() {
+        return thirdProperty;
+    }
+
+    @PostConstruct
+    protected void postConstruct() {
+        postConstructCalled = true;
+    }
+
+    public boolean isPostConstructCalled() {
+        return postConstructCalled;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SubClass.java b/src/test/java/org/apache/sling/models/testmodels/classes/SubClass.java
new file mode 100644
index 0000000..997cf74
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SubClass.java
@@ -0,0 +1,43 @@
+/*
+ * 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.annotation.PostConstruct;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables=Resource.class)
+public class SubClass extends SuperClass {
+
+    private long postConstructCalledTimestampInSub;
+
+    public long getPostConstructCalledTimestampInSub() {
+        return postConstructCalledTimestampInSub;
+    }
+    
+    @PostConstruct
+    protected void pc2() {
+        try {
+            Thread.sleep(100);
+        } catch (InterruptedException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        postConstructCalledTimestampInSub = System.currentTimeMillis();
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SuperClass.java b/src/test/java/org/apache/sling/models/testmodels/classes/SuperClass.java
new file mode 100644
index 0000000..a7047ce
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SuperClass.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;
+
+import javax.annotation.PostConstruct;
+
+public class SuperClass {
+
+    private long postConstructCalledTimestampInSuper;
+
+    public long getPostConstructCalledTimestampInSuper() {
+        return postConstructCalledTimestampInSuper;
+    }
+
+    @PostConstruct
+    protected void pc() {
+        postConstructCalledTimestampInSuper = System.currentTimeMillis();
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/ViaModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/ViaModel.java
new file mode 100644
index 0000000..5e5054e
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/ViaModel.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 javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Via;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class ViaModel {
+
+    @Inject
+    @Via("resource")
+    private String firstProperty;
+
+    public String getFirstProperty() {
+        return firstProperty;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/interfaces/ChildResourceModel.java b/src/test/java/org/apache/sling/models/testmodels/interfaces/ChildResourceModel.java
new file mode 100644
index 0000000..b2ce65c
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/interfaces/ChildResourceModel.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+@Model(adaptables = Resource.class)
+public interface ChildResourceModel {
+
+    @Inject
+    public Resource getFirstChild();
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/interfaces/ChildValueMapModel.java b/src/test/java/org/apache/sling/models/testmodels/interfaces/ChildValueMapModel.java
new file mode 100644
index 0000000..e7021d7
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/interfaces/ChildValueMapModel.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.interfaces;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+public interface ChildValueMapModel {
+
+    @Inject
+    public ValueMap getFirstChild();
+
+}
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
new file mode 100644
index 0000000..e0ec29d
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/interfaces/ParentModel.java
@@ -0,0 +1,30 @@
+/*
+ * 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.testmodels.classes.ChildModel;
+
+@Model(adaptables = Resource.class)
+public interface ParentModel {
+
+    @Inject
+    public ChildModel getFirstChild();
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/interfaces/ResourceModelWithRequiredField.java b/src/test/java/org/apache/sling/models/testmodels/interfaces/ResourceModelWithRequiredField.java
new file mode 100644
index 0000000..dd68f78
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/interfaces/ResourceModelWithRequiredField.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+@Model(adaptables = Resource.class)
+public interface ResourceModelWithRequiredField {
+
+    @Inject
+    public String getRequired();
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/interfaces/ServiceInterface.java b/src/test/java/org/apache/sling/models/testmodels/interfaces/ServiceInterface.java
new file mode 100644
index 0000000..73c9b41
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/interfaces/ServiceInterface.java
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+public interface ServiceInterface {
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/interfaces/SimplePropertyModel.java b/src/test/java/org/apache/sling/models/testmodels/interfaces/SimplePropertyModel.java
new file mode 100644
index 0000000..cdff785
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/interfaces/SimplePropertyModel.java
@@ -0,0 +1,43 @@
+/*
+ * 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 javax.inject.Named;
+
+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 SimplePropertyModel {
+
+    @Inject
+    public String getFirst();
+
+    @Inject
+    @Optional
+    public String getSecond();
+
+    @Inject
+    @Named("third")
+    public String getThirdProperty();
+    
+    @Inject
+    public boolean isFourth();
+
+}

-- 
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/10: [maven-release-plugin] copy for tag org.apache.sling.models.impl-1.0.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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit 41e32f4ab69b1fc9601b5474e7fbe27683e771f2
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jan 31 04:30:06 2014 +0000

    [maven-release-plugin]  copy for tag org.apache.sling.models.impl-1.0.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.models.impl-1.0.0@1563058 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] 05/10: SLING-3334 - explicitly rank 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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit ae43b9e95b4f7659ff00a23a7fa0d0f544685beb
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jan 31 04:07:01 2014 +0000

    SLING-3334 - explicitly rank injectors
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1563048 13f79535-47bb-0310-9956-ffa450edef68
---
 .../java/org/apache/sling/models/impl/injectors/BindingsInjector.java  | 3 +++
 .../org/apache/sling/models/impl/injectors/ChildResourceInjector.java  | 3 +++
 .../org/apache/sling/models/impl/injectors/OSGiServiceInjector.java    | 3 +++
 .../apache/sling/models/impl/injectors/RequestAttributeInjector.java   | 3 +++
 .../java/org/apache/sling/models/impl/injectors/ValueMapInjector.java  | 3 +++
 5 files changed, 15 insertions(+)

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 2a6fcc3..aa5ed5c 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
@@ -22,15 +22,18 @@ import java.lang.reflect.Type;
 import javax.servlet.ServletRequest;
 
 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.scripting.SlingBindings;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
 import org.apache.sling.models.spi.Injector;
+import org.osgi.framework.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component
 @Service
+@Property(name = Constants.SERVICE_RANKING, intValue = 1000)
 public class BindingsInjector implements Injector {
 
     private static final Logger log = LoggerFactory.getLogger(BindingsInjector.class);
diff --git a/src/main/java/org/apache/sling/models/impl/injectors/ChildResourceInjector.java b/src/main/java/org/apache/sling/models/impl/injectors/ChildResourceInjector.java
index 6afec71..194db83 100644
--- a/src/main/java/org/apache/sling/models/impl/injectors/ChildResourceInjector.java
+++ b/src/main/java/org/apache/sling/models/impl/injectors/ChildResourceInjector.java
@@ -20,13 +20,16 @@ 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.Resource;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
 import org.apache.sling.models.spi.Injector;
+import org.osgi.framework.Constants;
 
 @Component
 @Service
+@Property(name = Constants.SERVICE_RANKING, intValue = 3000)
 public class ChildResourceInjector implements Injector {
 
     @Override
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 f19c9ed..78a73bb 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
@@ -29,6 +29,7 @@ import javax.servlet.ServletRequest;
 
 import org.apache.felix.scr.annotations.Activate;
 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.scripting.SlingBindings;
 import org.apache.sling.api.scripting.SlingScriptHelper;
@@ -37,6 +38,7 @@ import org.apache.sling.models.spi.DisposalCallback;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
 import org.apache.sling.models.spi.Injector;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
@@ -45,6 +47,7 @@ import org.slf4j.LoggerFactory;
 
 @Component
 @Service
+@Property(name = Constants.SERVICE_RANKING, intValue = 5000)
 public class OSGiServiceInjector implements Injector {
 
     private static final Logger log = LoggerFactory.getLogger(OSGiServiceInjector.class);
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 ccd7138..fb73063 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
@@ -22,14 +22,17 @@ import java.lang.reflect.Type;
 import javax.servlet.ServletRequest;
 
 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.DisposalCallbackRegistry;
 import org.apache.sling.models.spi.Injector;
+import org.osgi.framework.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component
 @Service
+@Property(name = Constants.SERVICE_RANKING, intValue = 4000)
 public class RequestAttributeInjector implements Injector {
 
     private static final Logger log = LoggerFactory.getLogger(RequestAttributeInjector.class);
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 f81fb35..f6bea43 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
@@ -20,16 +20,19 @@ 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.adapter.Adaptable;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
 import org.apache.sling.models.spi.Injector;
+import org.osgi.framework.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component
 @Service
+@Property(name = Constants.SERVICE_RANKING, intValue = 2000)
 public class ValueMapInjector implements Injector {
 
     private static final Logger log = LoggerFactory.getLogger(ValueMapInjector.class);

-- 
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/10: avoid the use of Integer.compare()

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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit fe08a9634f1636a823ce50bf40377d0ecb10ec87
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jan 31 04:29:40 2014 +0000

    avoid the use of Integer.compare()
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1563056 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java | 6 +++++-
 1 file changed, 5 insertions(+), 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 7d29234..caf88a6 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -82,7 +82,11 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
         @Override
         public int compare(Constructor<?> o1, Constructor<?> o2) {
-            return Integer.compare(o2.getParameterTypes().length, o1.getParameterTypes().length);
+            return compare(o2.getParameterTypes().length, o1.getParameterTypes().length);
+        }
+
+        public int compare(int x, int y) {
+            return (x < y) ? -1 : ((x == y) ? 0 : 1);
         }
 
     }

-- 
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/10: SLING-3335 - add a models configuration printer to see the currently registered 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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit 40ea6f5d34ffd495e996e1fe66b83424367127c8
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jan 31 04:06:59 2014 +0000

    SLING-3335 - add a models configuration printer to see the currently registered injectors
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1563047 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/models/impl/ModelAdapterFactory.java     | 33 +++++++++++++--
 .../models/impl/ModelConfigurationPrinter.java     | 47 ++++++++++++++++++++++
 .../sling/models/impl/OSGiInjectionTest.java       |  2 +
 3 files changed, 78 insertions(+), 4 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 aeb0655..92fc791 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -55,11 +55,13 @@ import org.apache.sling.commons.osgi.ServiceUtil;
 import org.apache.sling.models.annotations.Default;
 import org.apache.sling.models.annotations.Model;
 import org.apache.sling.models.annotations.Optional;
-import org.apache.sling.models.annotations.Via;
 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.Injector;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
@@ -68,7 +70,7 @@ import org.slf4j.LoggerFactory;
 @Component
 public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
-    public static class DisposalCallbackRegistryImpl implements DisposalCallbackRegistry {
+    private static class DisposalCallbackRegistryImpl implements DisposalCallbackRegistry {
 
         private List<DisposalCallback> callbacks = new ArrayList<DisposalCallback>();
 
@@ -93,7 +95,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     private ConcurrentMap<java.lang.ref.Reference<Object>, DisposalCallbackRegistryImpl> disposalCallbacks;
 
-    public static class MapBackedInvocationHandler implements InvocationHandler {
+    private static class MapBackedInvocationHandler implements InvocationHandler {
 
         private Map<Method, Object> methods;
 
@@ -129,6 +131,8 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     private ServiceRegistration jobRegistration;
 
+    private ServiceRegistration configPrinterRegistration;
+
     @SuppressWarnings("unchecked")
     public <AdapterType> AdapterType getAdapter(Object adaptable, Class<AdapterType> type) {
         Model modelAnnotation = type.getAnnotation(Model.class);
@@ -579,16 +583,29 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
     @Activate
     protected void activate(final ComponentContext ctx) {
+        BundleContext bundleContext = ctx.getBundleContext();
         this.queue = new ReferenceQueue<Object>();
         this.disposalCallbacks = new ConcurrentHashMap<java.lang.ref.Reference<Object>, DisposalCallbackRegistryImpl>();
         Hashtable<Object, Object> properties = new Hashtable<Object, Object>();
+        properties.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
+        properties.put(Constants.SERVICE_DESCRIPTION, "Sling Models OSGi Service Disposal Job");
         properties.put("scheduler.concurrent", false);
         properties.put("scheduler.period", Long.valueOf(30));
 
-        this.jobRegistration = ctx.getBundleContext().registerService(Runnable.class.getName(), this,
+        this.jobRegistration = bundleContext.registerService(Runnable.class.getName(), this,
                 properties);
 
         this.listener = new ModelPackageBundleListener(ctx.getBundleContext(), this);
+
+        Hashtable<Object, Object> printerProps = new Hashtable<Object, Object>();
+        printerProps.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
+        printerProps.put(Constants.SERVICE_DESCRIPTION, "Sling Models Configuration Printer");
+        printerProps.put("felix.webconsole.label", "slingmodels");
+        printerProps.put("felix.webconsole.title", "Sling Models");
+        printerProps.put("felix.webconsole.configprinter.modes", "always");
+
+        this.configPrinterRegistration = bundleContext.registerService(Object.class.getName(),
+            new ModelConfigurationPrinter(this), printerProps);
     }
 
     @Deactivate
@@ -598,6 +615,10 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
             jobRegistration.unregister();
             jobRegistration = null;
         }
+        if (configPrinterRegistration != null) {
+            configPrinterRegistration.unregister();
+            configPrinterRegistration = null;
+        }
     }
 
     protected void bindInjector(final Injector injector, final Map<String, Object> props) {
@@ -614,4 +635,8 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         }
     }
 
+    Injector[] getInjectors() {
+        return sortedInjectors;
+    }
+
 }
diff --git a/src/main/java/org/apache/sling/models/impl/ModelConfigurationPrinter.java b/src/main/java/org/apache/sling/models/impl/ModelConfigurationPrinter.java
new file mode 100644
index 0000000..3e874b1
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/impl/ModelConfigurationPrinter.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.impl;
+
+import java.io.PrintWriter;
+
+import org.apache.sling.models.spi.Injector;
+
+public class ModelConfigurationPrinter {
+
+    private final ModelAdapterFactory modelAdapterFactory;
+
+    /**
+     * @param modelAdapterFactory
+     */
+    ModelConfigurationPrinter(ModelAdapterFactory modelAdapterFactory) {
+        this.modelAdapterFactory = modelAdapterFactory;
+    }
+
+    public void printConfiguration(PrintWriter printWriter) {
+        printWriter.println("Sling Models Injectors:");
+        Injector[] injectors = modelAdapterFactory.getInjectors();
+        if (injectors == null) {
+            printWriter.println("none");
+        } else {
+            for (Injector injector : injectors) {
+                printWriter.printf("%s - %s", injector.getName(), injector.getClass().getName());
+                printWriter.println();
+            }
+        }
+    }
+
+}
\ No newline at end of file
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 a7989ee..b26eb13 100644
--- a/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
+++ b/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
@@ -107,6 +107,7 @@ public class OSGiInjectionTest {
 
         verify(bundleContext).registerService(eq(Runnable.class.getName()), eq(factory), any(Dictionary.class));
         verify(bundleContext).addBundleListener(any(BundleListener.class));
+        verify(bundleContext).registerService(eq(Object.class.getName()), any(Object.class), any(Dictionary.class));
         verify(bundleContext).getBundles();
         verifyNoMoreInteractions(bundleContext);
     }
@@ -203,6 +204,7 @@ public class OSGiInjectionTest {
 
         verify(bundleContext).registerService(eq(Runnable.class.getName()), eq(factory), any(Dictionary.class));
         verify(bundleContext).addBundleListener(any(BundleListener.class));
+        verify(bundleContext).registerService(eq(Object.class.getName()), any(Object.class), any(Dictionary.class));
         verify(bundleContext).getBundles();
         verifyNoMoreInteractions(res, bundleContext);
     }

-- 
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/10: SLING-3313 - actually use the seal() method to make the disposal callback list unmodifiable

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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit d407d6f69cc24d60d4ac0a94396aa13c8ca20b99
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jan 31 04:06:42 2014 +0000

    SLING-3313 - actually use the seal() method to make the disposal callback list unmodifiable
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1563046 13f79535-47bb-0310-9956-ffa450edef68
---
 .../java/org/apache/sling/models/impl/ModelAdapterFactory.java | 10 ++++++----
 1 file changed, 6 insertions(+), 4 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 39bce98..aeb0655 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -60,8 +60,6 @@ import org.apache.sling.models.annotations.Source;
 import org.apache.sling.models.spi.DisposalCallback;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
 import org.apache.sling.models.spi.Injector;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
@@ -79,7 +77,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
             callbacks.add(callback);
         }
 
-        private void lock() {
+        private void seal() {
             callbacks = Collections.unmodifiableList(callbacks);
         }
 
@@ -113,7 +111,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
     public void run() {
         java.lang.ref.Reference<? extends Object> ref = queue.poll();
         if (ref != null) {
-            log.info("calling disposal for " + ref.toString());
+            log.debug("calling disposal for " + ref.toString());
             DisposalCallbackRegistryImpl registry = disposalCallbacks.remove(ref);
             registry.onDisposed();
         }
@@ -223,6 +221,8 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
             }
         }
 
+        registry.seal();
+
         Iterator<Method> it = injectableMethods.iterator();
         while (it.hasNext()) {
             Method method = it.next();
@@ -305,6 +305,8 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
             }
         }
 
+        registry.seal();
+
         Iterator<Field> it = injectableFields.iterator();
         while (it.hasNext()) {
             Field field = it.next();

-- 
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/10: set svn:ignore

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.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit 45be0c6fb5284dbf1e86ea8dd4041ce6b54b7b3d
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Thu Jan 23 11:08:38 2014 +0000

    set svn:ignore
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1560637 13f79535-47bb-0310-9956-ffa450edef68

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