Author: justin
Date: Tue Aug 19 22:51:36 2014
New Revision: 1619007
URL: http://svn.apache.org/r1619007
Log:
SLING-3716 SLING-3718 - adding support for constructor injection and self
injection based on a patch from Stefan Seifert
Added:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/Self.java
- copied, changed from r1618976,
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/RequestAttribute.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/AcceptsNullName.java
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/MapBackedInvocationHandler.java
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ParameterCountInjectComparator.java
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/SelfDependencyTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/injectors/BindingsInjectorTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/injectors/RequestAttributeInjectorTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/injectors/SelfInjectorTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/injectors/ValueMapInjectorTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/DirectCyclicSelfDependencyModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/IndirectCyclicSelfDependencyModelA.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/IndirectCyclicSelfDependencyModelB.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/SelfDependencyModelA.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/SelfDependencyModelB.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/BindingsModel.java
- copied, changed from r1618976,
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/TestModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultPrimitivesModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultStringModel.java
- copied, changed from r1618976,
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/TestModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/DefaultWrappersModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/InjectorSpecificAnnotationModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/ListOSGiModel.java
- copied, changed from r1618976,
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/TestModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/NoNameModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/SimpleOSGiModel.java
- copied, changed from r1618976,
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/TestModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/constructorinjection/WithThreeConstructorsOneInjectModel.java
- copied, changed from r1618976,
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/TestModel.java
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/ConstructorInjectionTestModel.java
- copied, changed from r1618976,
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/TestModel.java
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/FieldInjectionTestModel.java
- copied, changed from r1618976,
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/TestModel.java
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/InterfaceInjectionTestModel.java
- copied, changed from r1618976,
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/TestModel.java
Removed:
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/models/TestModel.java
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Default.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Filter.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Optional.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Source.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Via.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ChildResource.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/OSGiService.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/RequestAttribute.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ScriptVariable.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ValueMapValue.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/package-info.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/package-info.java
sling/trunk/bundles/extensions/models/impl/pom.xml
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/DefaultTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/RequestInjectionTest.java
sling/trunk/bundles/extensions/models/integration-tests/src/main/java/org/apache/sling/models/it/SimpleTest.java
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Default.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Default.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Default.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Default.java
Tue Aug 19 22:51:36 2014
@@ -24,7 +24,7 @@ import java.lang.annotation.Target;
/**
* Default value for an injection.
*/
-@Target({ ElementType.FIELD, ElementType.METHOD })
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface Default {
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Filter.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Filter.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Filter.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Filter.java
Tue Aug 19 22:51:36 2014
@@ -26,7 +26,7 @@ import javax.inject.Qualifier;
/**
* Provide a filter on an @Inject.
*/
-@Target({ ElementType.FIELD, ElementType.METHOD })
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Source("osgi-services")
@Qualifier
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Optional.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Optional.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Optional.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Optional.java
Tue Aug 19 22:51:36 2014
@@ -24,7 +24,7 @@ import java.lang.annotation.Target;
/**
* Marker annotation for optional injections.
*/
-@Target({ ElementType.FIELD, ElementType.METHOD })
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface Optional {
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Required.java
Tue Aug 19 22:51:36 2014
@@ -24,7 +24,7 @@ import java.lang.annotation.Target;
/**
* Marker annotation for required injections.
*/
-@Target({ ElementType.FIELD, ElementType.METHOD })
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface Required {
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Source.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Source.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Source.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Source.java
Tue Aug 19 22:51:36 2014
@@ -28,7 +28,7 @@ import javax.inject.Qualifier;
* Can also be used as a meta-annotation to declare that some other annotation
implies
* a source.
*/
-@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Source {
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Via.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Via.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Via.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Via.java
Tue Aug 19 22:51:36 2014
@@ -25,7 +25,7 @@ import java.lang.annotation.Target;
* Indicate that this injection point should be handled using a projected
* property of the adaptable.
*/
-@Target({ ElementType.FIELD, ElementType.METHOD })
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface Via {
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ChildResource.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ChildResource.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ChildResource.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ChildResource.java
Tue Aug 19 22:51:36 2014
@@ -18,6 +18,7 @@ package org.apache.sling.models.annotati
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
@@ -27,10 +28,10 @@ import org.apache.sling.models.annotatio
import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
/**
- * Annotation to be used on either methods or fields to let Sling Models
inject a child resource
+ * Annotation to be used on either methods, fields or constructor parameters
to let Sling Models inject a child resource
*
*/
-@Target({ METHOD, FIELD })
+@Target({ METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
@InjectAnnotation
@Source("child-resources")
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/OSGiService.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/OSGiService.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/OSGiService.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/OSGiService.java
Tue Aug 19 22:51:36 2014
@@ -18,6 +18,7 @@ package org.apache.sling.models.annotati
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
@@ -27,10 +28,10 @@ import org.apache.sling.models.annotatio
import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
/**
- * Annotation to be used on either methods or fields to let Sling Models
inject an OSGi service
+ * Annotation to be used on either methods, fields or constructor parameters
to let Sling Models inject an OSGi service
*
*/
-@Target({ METHOD, FIELD })
+@Target({ METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
@InjectAnnotation
@Source("osgi-services")
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/RequestAttribute.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/RequestAttribute.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/RequestAttribute.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/RequestAttribute.java
Tue Aug 19 22:51:36 2014
@@ -18,6 +18,7 @@ package org.apache.sling.models.annotati
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
@@ -27,11 +28,11 @@ import org.apache.sling.models.annotatio
import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
/**
- * Annotation to be used on either methods or fields to let Sling Models
inject a
+ * Annotation to be used on either methods, fields or constructor parameters
to let Sling Models inject a
* request attribute.
*
*/
-@Target({ METHOD, FIELD })
+@Target({ METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
@InjectAnnotation
@Source("request-attributes")
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ScriptVariable.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ScriptVariable.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ScriptVariable.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ScriptVariable.java
Tue Aug 19 22:51:36 2014
@@ -18,6 +18,7 @@ package org.apache.sling.models.annotati
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
@@ -27,11 +28,11 @@ import org.apache.sling.models.annotatio
import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
/**
- * Annotation to be used on either methods or fields to let Sling Models
inject a
+ * Annotation to be used on either methods, fields or constructor parameters
to let Sling Models inject a
* script variable (from the {@link
org.apache.sling.api.scripting.SlingBindings})
*
*/
-@Target({ METHOD, FIELD })
+@Target({ METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
@InjectAnnotation
@Source("script-bindings")
Copied:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/Self.java
(from r1618976,
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/RequestAttribute.java)
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/Self.java?p2=sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/Self.java&p1=sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/RequestAttribute.java&r1=1618976&r2=1619007&rev=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/RequestAttribute.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/Self.java
Tue Aug 19 22:51:36 2014
@@ -18,6 +18,7 @@ package org.apache.sling.models.annotati
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
@@ -27,26 +28,19 @@ import org.apache.sling.models.annotatio
import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
/**
- * Annotation to be used on either methods or fields to let Sling Models
inject a
- * request attribute.
- *
+ * Annotation to be used on either methods, fields or constructor parameters
to let Sling Models
+ * inject the adaptable itself, or an object that can be adapted from it.
*/
-@Target({ METHOD, FIELD })
+@Target({ METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
@InjectAnnotation
-@Source("request-attributes")
-public @interface RequestAttribute {
+@Source("self")
+public @interface Self {
/**
- * Specifies the name of the request attribute. If empty or not set, then
the name
- * is derived from the method or field.
- */
- public String name() default "";
-
- /**
- * If set to true, the model can be instantiated even if there is no
request attribute
- * with the given name found.
+ * If set to true, the model can be instantiated even if there is no
object that can be adapted from the adaptable itself.
* Default = false.
*/
public boolean optional() default false;
+
}
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ValueMapValue.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ValueMapValue.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ValueMapValue.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ValueMapValue.java
Tue Aug 19 22:51:36 2014
@@ -18,6 +18,7 @@ package org.apache.sling.models.annotati
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
@@ -27,10 +28,11 @@ import org.apache.sling.models.annotatio
import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
/**
- * Annotation to be used on either methods or fields to let Sling Models
inject a value from the ValueMap of the current resource.
+ * Annotation to be used on either methods, fields or constructor parameter to
let Sling Models
+ * inject a value from the ValueMap of the current resource.
*
*/
-@Target({ METHOD, FIELD })
+@Target({ METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
@InjectAnnotation
@Source("valuemap")
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/package-info.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/package-info.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/package-info.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/package-info.java
Tue Aug 19 22:51:36 2014
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("1.0.0")
+@Version("1.0.2")
package org.apache.sling.models.annotations.injectorspecific;
import aQute.bnd.annotation.Version;
\ No newline at end of file
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java
Tue Aug 19 22:51:36 2014
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("1.1.0")
+@Version("1.1.2")
package org.apache.sling.models.annotations;
import aQute.bnd.annotation.Version;
\ No newline at end of file
Added:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/AcceptsNullName.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/AcceptsNullName.java?rev=1619007&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/AcceptsNullName.java
(added)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/AcceptsNullName.java
Tue Aug 19 22:51:36 2014
@@ -0,0 +1,27 @@
+/*
+ * 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.spi;
+
+/**
+ * Marker interface for an injector to declare that it ignores the name
+ * parameter.
+ *
+ */
+public interface AcceptsNullName {
+}
Modified:
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/package-info.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/package-info.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/package-info.java
(original)
+++
sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/spi/package-info.java
Tue Aug 19 22:51:36 2014
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("1.0.0")
+@Version("1.0.2")
package org.apache.sling.models.spi;
import aQute.bnd.annotation.Version;
\ No newline at end of file
Modified: sling/trunk/bundles/extensions/models/impl/pom.xml
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/pom.xml?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/pom.xml (original)
+++ sling/trunk/bundles/extensions/models/impl/pom.xml Tue Aug 19 22:51:36 2014
@@ -63,7 +63,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.models.api</artifactId>
- <version>1.0.2</version>
+ <version>1.0.3-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
Added:
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java?rev=1619007&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java
(added)
+++
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ConstructorParameter.java
Tue Aug 19 22:51:36 2014
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.models.impl;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+
+/**
+ * Constructor parameters aren't normally accessible using the
+ * AnnotatedElement. This class acts as a facade to ease
+ * compatibility with field and method injection.
+ */
+class ConstructorParameter implements AnnotatedElement {
+
+ private final Annotation[] annotations;
+ private final Class<?> type;
+ private final Type genericType;
+ private final int parameterIndex;
+
+ ConstructorParameter(Annotation[] annotations, Class<?> type, Type
genericType, int parameterIndex) {
+ this.annotations = annotations;
+ this.type = type;
+ this.genericType = genericType;
+ this.parameterIndex = parameterIndex;
+ }
+
+ @Override
+ public boolean isAnnotationPresent(Class<? extends Annotation> paramClass)
{
+ return getAnnotation(paramClass) != null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> paramClass) {
+ for (Annotation annotation : this.annotations) {
+ if (paramClass.isInstance(annotation)) {
+ return (T)annotation;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Annotation[] getAnnotations() {
+ return annotations;
+ }
+
+ @Override
+ public Annotation[] getDeclaredAnnotations() {
+ return annotations;
+ }
+
+ public Class<?> getType() {
+ return this.type;
+ }
+
+ public Type getGenericType() {
+ return this.genericType;
+ }
+
+ public int getParameterIndex() {
+ return this.parameterIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "Parameter" + this.parameterIndex + "[" +
this.genericType.toString() + "]";
+ }
+
+}
\ No newline at end of file
Added:
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/MapBackedInvocationHandler.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/MapBackedInvocationHandler.java?rev=1619007&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/MapBackedInvocationHandler.java
(added)
+++
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/MapBackedInvocationHandler.java
Tue Aug 19 22:51:36 2014
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.models.impl;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+class MapBackedInvocationHandler implements InvocationHandler {
+
+ private Map<Method, Object> methods;
+
+ public MapBackedInvocationHandler(Map<Method, Object> methods) {
+ this.methods = methods;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
+ return methods.get(method);
+ }
+
+}
\ No newline at end of file
Modified:
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
(original)
+++
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
Tue Aug 19 22:51:36 2014
@@ -32,7 +32,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
@@ -69,6 +68,7 @@ import org.apache.sling.models.annotatio
import org.apache.sling.models.annotations.Via;
import org.apache.sling.models.spi.DisposalCallback;
import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.AcceptsNullName;
import org.apache.sling.models.spi.Injector;
import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
@@ -83,23 +83,6 @@ import org.slf4j.LoggerFactory;
@Component
public class ModelAdapterFactory implements AdapterFactory, Runnable {
- /**
- * Comparator which sorts constructors by the number of parameters
- * in reverse order (most params to least params).
- */
- public class ParameterCountComparator implements
Comparator<Constructor<?>> {
-
- @Override
- public int compare(Constructor<?> o1, Constructor<?> o2) {
- return compare(o2.getParameterTypes().length,
o1.getParameterTypes().length);
- }
-
- public int compare(int x, int y) {
- return (x < y) ? -1 : ((x == y) ? 0 : 1);
- }
-
- }
-
private static class DisposalCallbackRegistryImpl implements
DisposalCallbackRegistry {
private List<DisposalCallback> callbacks = new
ArrayList<DisposalCallback>();
@@ -125,20 +108,6 @@ public class ModelAdapterFactory impleme
private ConcurrentMap<java.lang.ref.Reference<Object>,
DisposalCallbackRegistryImpl> disposalCallbacks;
- private static class MapBackedInvocationHandler implements
InvocationHandler {
-
- private Map<Method, Object> methods;
-
- public MapBackedInvocationHandler(Map<Method, Object> methods) {
- this.methods = methods;
- }
-
- public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
- return methods.get(method);
- }
-
- }
-
@Override
public void run() {
java.lang.ref.Reference<? extends Object> ref = queue.poll();
@@ -169,39 +138,72 @@ public class ModelAdapterFactory impleme
private ServiceRegistration jobRegistration;
private ServiceRegistration configPrinterRegistration;
+
+ // Use threadlocal to count recursive invocations and break recursing if a
max. limit is reached (to avoid cyclic dependencies)
+ private static final int MAX_RECURSIVE_INOVCATIONS = 20;
- @SuppressWarnings("unchecked")
- public <AdapterType> AdapterType getAdapter(Object adaptable,
Class<AdapterType> type) {
- Model modelAnnotation = type.getAnnotation(Model.class);
- if (modelAnnotation == null) {
- return null;
+ private static class ThreadInvocationCounter {
+ private int count;
+ public boolean isMaximumReached() {
+ return count >= MAX_RECURSIVE_INOVCATIONS;
}
- boolean isAdaptable = false;
-
- Class<?>[] declaredAdaptable = modelAnnotation.adaptables();
- for (Class<?> clazz : declaredAdaptable) {
- if (clazz.isInstance(adaptable)) {
- isAdaptable = true;
- }
+ public void increase() {
+ this.count++;
}
- if (!isAdaptable) {
- return null;
+ public void decrease() {
+ this.count--;
}
+ }
- if (type.isInterface()) {
- InvocationHandler handler = createInvocationHandler(adaptable,
type, modelAnnotation);
- if (handler != null) {
- return (AdapterType)
Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[] { type }, handler);
- } else {
+ private static final ThreadLocal<ThreadInvocationCounter>
INVOCATION_COUNT_THREADLOCAL = new
ThreadLocal<ModelAdapterFactory.ThreadInvocationCounter>() {
+ @Override
+ protected ThreadInvocationCounter initialValue() {
+ return new ThreadInvocationCounter();
+ }
+ };
+
+ @SuppressWarnings("unchecked")
+ public <AdapterType> AdapterType getAdapter(Object adaptable,
Class<AdapterType> type) {
+ if (INVOCATION_COUNT_THREADLOCAL.get().isMaximumReached()) {
+ log.error("Adapting {} to {} failed, too much recursive
invocations (>={}).",
+ new Object[] { adaptable, type, MAX_RECURSIVE_INOVCATIONS
});
+ return null;
+ };
+ INVOCATION_COUNT_THREADLOCAL.get().increase();
+ try {
+ Model modelAnnotation = type.getAnnotation(Model.class);
+ if (modelAnnotation == null) {
return null;
}
- } else {
- try {
- return createObject(adaptable, type, modelAnnotation);
- } catch (Exception e) {
- log.error("unable to create object", e);
+ boolean isAdaptable = false;
+
+ Class<?>[] declaredAdaptable = modelAnnotation.adaptables();
+ for (Class<?> clazz : declaredAdaptable) {
+ if (clazz.isInstance(adaptable)) {
+ isAdaptable = true;
+ }
+ }
+ if (!isAdaptable) {
return null;
}
+
+ if (type.isInterface()) {
+ InvocationHandler handler = createInvocationHandler(adaptable,
type, modelAnnotation);
+ if (handler != null) {
+ return (AdapterType)
Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[] { type }, handler);
+ } else {
+ return null;
+ }
+ } else {
+ try {
+ return createObject(adaptable, type, modelAnnotation);
+ } catch (Exception e) {
+ log.error("unable to create object", e);
+ return null;
+ }
+ }
+ } finally {
+ INVOCATION_COUNT_THREADLOCAL.get().decrease();
}
}
@@ -276,14 +278,28 @@ public class ModelAdapterFactory impleme
return setMethod((Method) element, methods, value);
}
}
+
+ private static class SetConstructorParameterCallback implements
InjectCallback {
+
+ private final List<Object> parameterValues;
- private boolean injectFieldOrMethod(final AnnotatedElement element, final
Object adaptable, final Type type,
+ private SetConstructorParameterCallback(List<Object> parameterValues) {
+ this.parameterValues = parameterValues;
+ }
+
+ @Override
+ public boolean inject(AnnotatedElement element, Object value) {
+ return setConstructorParameter((ConstructorParameter)element,
parameterValues, value);
+ }
+ }
+
+ private boolean injectElement(final AnnotatedElement element, final Object
adaptable, final Type type,
final Model modelAnnotation, final DisposalCallbackRegistry
registry, InjectCallback callback) {
InjectAnnotationProcessor annotationProcessor = null;
String source = getSource(element);
boolean wasInjectionSuccessful = false;
-
+
// find an appropriate annotation processor
for (InjectAnnotationProcessorFactory factory :
sortedInjectAnnotationProcessorFactories) {
annotationProcessor = factory.createAnnotationProcessor(adaptable,
element);
@@ -292,16 +308,19 @@ public class ModelAdapterFactory impleme
}
}
+ String name = getName(element, annotationProcessor);
+ Object injectionAdaptable = getAdaptable(adaptable, element,
annotationProcessor);
+
// find the right injector
for (Injector injector : sortedInjectors) {
if (source == null || source.equals(injector.getName())) {
- String name = getName(element, annotationProcessor);
- Object injectionAdaptable = getAdaptable(adaptable, element,
annotationProcessor);
- if (injectionAdaptable != null) {
- Object value = injector.getValue(injectionAdaptable, name,
type, element, registry);
- if (callback.inject(element, value)) {
- wasInjectionSuccessful = true;
- break;
+ if (name != null || injector instanceof AcceptsNullName) {
+ if (injectionAdaptable != null) {
+ Object value = injector.getValue(injectionAdaptable,
name, type, element, registry);
+ if (callback.inject(element, value)) {
+ wasInjectionSuccessful = true;
+ break;
+ }
}
}
}
@@ -324,12 +343,13 @@ public class ModelAdapterFactory impleme
SetMethodsCallback callback = new SetMethodsCallback(methods);
MapBackedInvocationHandler handler = new
MapBackedInvocationHandler(methods);
- DisposalCallbackRegistryImpl registry =
createAndRegisterCallbackRegistry(handler);
+ DisposalCallbackRegistryImpl registry = new
DisposalCallbackRegistryImpl();
+ registerCallbackRegistry(handler, registry);
Set<Method> requiredMethods = new HashSet<Method>();
for (Method method : injectableMethods) {
Type returnType =
mapPrimitiveClasses(method.getGenericReturnType());
- if (!injectFieldOrMethod(method, adaptable, returnType,
modelAnnotation, registry, callback)) {
+ if (!injectElement(method, adaptable, returnType, modelAnnotation,
registry, callback)) {
requiredMethods.add(method);
}
}
@@ -341,11 +361,9 @@ public class ModelAdapterFactory impleme
return handler;
}
- private DisposalCallbackRegistryImpl
createAndRegisterCallbackRegistry(Object object) {
+ private void registerCallbackRegistry(Object object,
DisposalCallbackRegistryImpl registry) {
PhantomReference<Object> reference = new
PhantomReference<Object>(object, queue);
- DisposalCallbackRegistryImpl registry = new
DisposalCallbackRegistryImpl();
disposalCallbacks.put(reference, registry);
- return registry;
}
private String getSource(AnnotatedElement element) {
@@ -380,60 +398,52 @@ public class ModelAdapterFactory impleme
return null;
}
- @SuppressWarnings("unchecked")
private <AdapterType> AdapterType createObject(Object adaptable,
Class<AdapterType> type, Model modelAnnotation)
throws InstantiationException, InvocationTargetException,
IllegalAccessException {
- Set<Field> injectableFields = collectInjectableFields(type);
+ DisposalCallbackRegistryImpl registry = new
DisposalCallbackRegistryImpl();
- Constructor<?>[] constructors = type.getConstructors();
- if (constructors.length == 0) {
- log.warn("Model class {} does not have a public constructor.",
type.getName());
+ Constructor<AdapterType> constructorToUse =
getBestMatchingConstructor(adaptable, type);
+ if (constructorToUse == null) {
+ log.warn("Model class {} does not have a usable constructor",
type.getName());
return null;
}
- // sort the constructor list in order from most params to least params
- Arrays.sort(constructors, new ParameterCountComparator());
-
- Constructor<AdapterType> constructorToUse = null;
- boolean constructorHasParam = false;
- for (Constructor<?> constructor : constructors) {
- final Class<?>[] paramTypes = constructor.getParameterTypes();
- if (paramTypes.length == 1) {
- Class<?> paramType = constructor.getParameterTypes()[0];
- if (paramType.isInstance(adaptable)) {
- constructorToUse = (Constructor<AdapterType>) constructor;
- constructorHasParam = true;
- break;
- }
- }
-
- if (constructor.getParameterTypes().length == 0) {
- constructorToUse = (Constructor<AdapterType>) constructor;
- constructorHasParam = false;
- break;
+ final AdapterType object;
+ if (constructorToUse.getParameterTypes().length == 0) {
+ // no parameters for constructor injection? instantiate it right
away
+ object = constructorToUse.newInstance();
+ } else {
+ // instantiate with constructor injection
+ // if this fails, make sure resources that may be claimed by
injectors are cleared up again
+ try {
+ object = newInstanceWithConstructorInjection(constructorToUse,
adaptable, type, modelAnnotation, registry);
+ } catch (InstantiationException ex) {
+ registry.onDisposed();
+ throw ex;
+ } catch (InvocationTargetException ex) {
+ registry.onDisposed();
+ throw ex;
+ } catch (IllegalAccessException ex) {
+ registry.onDisposed();
+ throw ex;
}
}
- if (constructorToUse == null) {
- log.warn("Model class {} does not have a usable constructor",
type.getName());
+ if (object == null) {
+ registry.onDisposed();
return null;
}
- final AdapterType object;
- if (constructorHasParam) {
- object = constructorToUse.newInstance(adaptable);
- } else {
- object = constructorToUse.newInstance();
- }
- InjectCallback callback = new SetFieldCallback(object);
+ registerCallbackRegistry(object, registry);
- DisposalCallbackRegistryImpl registry =
createAndRegisterCallbackRegistry(object);
+ InjectCallback callback = new SetFieldCallback(object);
Set<Field> requiredFields = new HashSet<Field>();
+ Set<Field> injectableFields = collectInjectableFields(type);
for (Field field : injectableFields) {
Type fieldType = mapPrimitiveClasses(field.getGenericType());
- if (!injectFieldOrMethod(field, adaptable, fieldType,
modelAnnotation, registry, callback)) {
+ if (!injectElement(field, adaptable, fieldType, modelAnnotation,
registry, callback)) {
requiredFields.add(field);
}
}
@@ -453,6 +463,64 @@ public class ModelAdapterFactory impleme
}
+ /**
+ * Gets best matching constructor for constructor injection - or default
constructor if none is found.
+ * @param adaptable Adaptable instance
+ * @param type Model type
+ * @return Constructor or null if none found
+ */
+ @SuppressWarnings("unchecked")
+ private <AdapterType> Constructor<AdapterType>
getBestMatchingConstructor(Object adaptable, Class<AdapterType> type) {
+ Constructor<?>[] constructors = type.getConstructors();
+
+ // sort the constructor list in order from most params to least
params, and constructors with @Inject annotation first
+ Arrays.sort(constructors, new ParameterCountInjectComparator());
+
+ for (Constructor<?> constructor : constructors) {
+ // first try to find the constructor with most parameters and
@Inject annotation
+ if (constructor.isAnnotationPresent(Inject.class)) {
+ return (Constructor<AdapterType>) constructor;
+ }
+ // compatibility mode for sling models implementation <= 1.0.6:
+ // support constructor without @Inject if it has exactly one
parameter matching the adaptable class
+ final Class<?>[] paramTypes = constructor.getParameterTypes();
+ if (paramTypes.length == 1) {
+ Class<?> paramType = constructor.getParameterTypes()[0];
+ if (paramType.isInstance(adaptable)) {
+ return (Constructor<AdapterType>) constructor;
+ }
+ }
+ // if no constructor for injection found use public constructor
without any params
+ if (constructor.getParameterTypes().length == 0) {
+ return (Constructor<AdapterType>) constructor;
+ }
+ }
+ return null;
+ }
+
+ private <AdapterType> AdapterType
newInstanceWithConstructorInjection(Constructor<AdapterType> constructor,
Object adaptable,
+ Class<AdapterType> type, Model modelAnnotation,
DisposalCallbackRegistry registry)
+ throws InstantiationException, InvocationTargetException,
IllegalAccessException {
+ Set<ConstructorParameter> requiredParameters = new
HashSet<ConstructorParameter>();
+ Type[] parameterTypes = constructor.getGenericParameterTypes();
+ List<Object> paramValues = new ArrayList<Object>(Arrays.asList(new
Object[parameterTypes.length]));
+ InjectCallback callback = new
SetConstructorParameterCallback(paramValues);
+
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Type genericType = mapPrimitiveClasses(parameterTypes[i]);
+ ConstructorParameter constructorParameter = new
ConstructorParameter(
+ constructor.getParameterAnnotations()[i],
constructor.getParameterTypes()[i], genericType, i);
+ if (!injectElement(constructorParameter, adaptable, genericType,
modelAnnotation, registry, callback)) {
+ requiredParameters.add(constructorParameter);
+ }
+ }
+ if (!requiredParameters.isEmpty()) {
+ log.warn("Required constructor parameters {} on model class {}
were not able to be injected.", requiredParameters, type);
+ return null;
+ }
+ return constructor.newInstance(paramValues.toArray(new
Object[paramValues.size()]));
+ }
+
private boolean isOptional(AnnotatedElement point, Model modelAnnotation,
InjectAnnotationProcessor annotationProcessor) {
if (annotationProcessor != null) {
Boolean isOptional = annotationProcessor.isOptional();
@@ -582,6 +650,9 @@ public class ModelAdapterFactory impleme
return getNameFromMethod((Method) element);
} else if (element instanceof Field) {
return getNameFromField((Field) element);
+ } else if (element instanceof ConstructorParameter) {
+ // implicit name not supported for constructor parameters - but do
not throw exception because class-based injection is still possible
+ return null;
} else {
throw new IllegalArgumentException("The given element must be
either method or field but is " + element);
}
@@ -702,6 +773,27 @@ public class ModelAdapterFactory impleme
}
}
+ private static boolean setConstructorParameter(ConstructorParameter
constructorParameter, List<Object> parameterValues, Object value) {
+ if (value != null && constructorParameter.getType() instanceof
Class<?>) {
+ Class<?> requestedType = (Class<?>)constructorParameter.getType();
+ if (!isAcceptableType(requestedType,
constructorParameter.getGenericType(), value)) {
+ if (value instanceof Adaptable) {
+ value = ((Adaptable) value).adaptTo(requestedType);
+ if (value == null) {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+ parameterValues.set(constructorParameter.getParameterIndex(),
value);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
private static boolean isAcceptableType(Class<?> type, Type genericType,
Object value) {
if (type.isInstance(value)) {
if ((type == Collection.class || type == List.class) &&
genericType instanceof ParameterizedType &&
Added:
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ParameterCountInjectComparator.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ParameterCountInjectComparator.java?rev=1619007&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ParameterCountInjectComparator.java
(added)
+++
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ParameterCountInjectComparator.java
Tue Aug 19 22:51:36 2014
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.models.impl;
+
+import java.lang.reflect.Constructor;
+import java.util.Comparator;
+
+import javax.inject.Inject;
+
+/**
+ * Comparator which sorts constructors by the number of parameters
+ * in reverse order (most params to least params).
+ * If two constructors have the same number of parameters constructors with
+ * @Inject annotation are sorted first.
+ */
+class ParameterCountInjectComparator implements Comparator<Constructor<?>> {
+
+ @Override
+ public int compare(Constructor<?> o1, Constructor<?> o2) {
+ int result = compareParameterCount(o2.getParameterTypes().length,
o1.getParameterTypes().length);
+ if (result==0) {
+ return compareInjectAnnotation(o1, o2);
+ }
+ else {
+ return result;
+ }
+ }
+
+ private int compareParameterCount(int x, int y) {
+ return (x < y) ? -1 : ((x == y) ? 0 : 1);
+ }
+
+ private int compareInjectAnnotation(Constructor<?> o1, Constructor<?> o2) {
+ boolean hasInject1 = o1.isAnnotationPresent(Inject.class);
+ boolean hasInject2 = o2.isAnnotationPresent(Inject.class);
+ if (hasInject1 && !hasInject2) {
+ return -1;
+ }
+ else if (hasInject2 && !hasInject1) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+
+}
\ No newline at end of file
Modified:
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java
(original)
+++
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/OSGiServiceInjector.java
Tue Aug 19 22:51:36 2014
@@ -38,6 +38,7 @@ import org.apache.sling.models.annotatio
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.spi.DisposalCallback;
import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.AcceptsNullName;
import org.apache.sling.models.spi.Injector;
import
org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor;
import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
@@ -53,7 +54,7 @@ import org.slf4j.LoggerFactory;
@Component
@Service
@Property(name = Constants.SERVICE_RANKING, intValue = 5000)
-public class OSGiServiceInjector implements Injector,
InjectAnnotationProcessorFactory {
+public class OSGiServiceInjector implements Injector,
InjectAnnotationProcessorFactory, AcceptsNullName {
private static final Logger log =
LoggerFactory.getLogger(OSGiServiceInjector.class);
Added:
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java?rev=1619007&view=auto
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java
(added)
+++
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/SelfInjector.java
Tue Aug 19 22:51:36 2014
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.models.impl.injectors;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.AcceptsNullName;
+import org.apache.sling.models.spi.Injector;
+import
org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
+import
org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory;
+import org.osgi.framework.Constants;
+
+/**
+ * Injects the adaptable object itself.
+ */
+@Component
+@Service
+@Property(name = Constants.SERVICE_RANKING, intValue = 100)
+public class SelfInjector implements Injector,
InjectAnnotationProcessorFactory, AcceptsNullName {
+
+ @Override
+ public String getName() {
+ return "self";
+ }
+
+ public Object getValue(Object adaptable, String name, Type type,
AnnotatedElement element,
+ DisposalCallbackRegistry callbackRegistry) {
+ // if the @Self annotation is present return the adaptable to be
inserted directly or to be adapted from
+ if (element.isAnnotationPresent(Self.class)) {
+ return adaptable;
+ }
+ // otherwise apply class-based injection only if class matches or is a
superclass
+ else if (type instanceof Class<?>) {
+ Class<?> requestedClass = (Class<?>)type;
+ if (requestedClass.isAssignableFrom(adaptable.getClass())) {
+ return adaptable;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public InjectAnnotationProcessor createAnnotationProcessor(Object
adaptable, AnnotatedElement element) {
+ // check if the element has the expected annotation
+ Self annotation = element.getAnnotation(Self.class);
+ if (annotation != null) {
+ return new SelfAnnotationProcessor(annotation);
+ }
+ return null;
+ }
+
+ private static class SelfAnnotationProcessor extends
AbstractInjectAnnotationProcessor {
+
+ private final Self annotation;
+
+ public SelfAnnotationProcessor(Self annotation) {
+ this.annotation = annotation;
+ }
+
+ @Override
+ public Boolean isOptional() {
+ return annotation.optional();
+ }
+ }
+
+}
Modified:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
(original)
+++
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
Tue Aug 19 22:51:36 2014
@@ -21,11 +21,14 @@ import static org.mockito.Mockito.*;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
+import org.apache.sling.models.impl.injectors.SelfInjector;
import org.apache.sling.models.testmodels.classes.InvalidConstructorModel;
import org.apache.sling.models.testmodels.classes.SuperclassConstructorModel;
import org.apache.sling.models.testmodels.classes.WithOneConstructorModel;
import org.apache.sling.models.testmodels.classes.WithThreeConstructorsModel;
import org.apache.sling.models.testmodels.classes.WithTwoConstructorsModel;
+import
org.apache.sling.models.testmodels.classes.constructorinjection.NoNameModel;
+import
org.apache.sling.models.testmodels.classes.constructorinjection.WithThreeConstructorsOneInjectModel;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,6 +38,7 @@ import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
public class ConstructorTest {
@Mock
@@ -48,15 +52,21 @@ public class ConstructorTest {
@Mock
private SlingHttpServletRequest request;
+ private static final int INT_VALUE = 42;
+
+ private static final String STRING_VALUE = "myValue";
+
@Before
public void setup() {
when(componentCtx.getBundleContext()).thenReturn(bundleContext);
- when(request.getAttribute("attribute")).thenReturn(42);
+ when(request.getAttribute("attribute")).thenReturn(INT_VALUE);
+ when(request.getAttribute("attribute2")).thenReturn(STRING_VALUE);
factory = new ModelAdapterFactory();
factory.activate(componentCtx);
factory.bindInjector(new RequestAttributeInjector(), new
ServicePropertiesMap(1, 1));
+ factory.bindInjector(new SelfInjector(), new ServicePropertiesMap(2,
2));
}
@Test
@@ -64,7 +74,7 @@ public class ConstructorTest {
WithOneConstructorModel model = factory.getAdapter(request,
WithOneConstructorModel.class);
assertNotNull(model);
assertEquals(request, model.getRequest());
- assertEquals(42, model.getAttribute());
+ assertEquals(INT_VALUE, model.getAttribute());
}
@Test
@@ -72,7 +82,7 @@ public class ConstructorTest {
WithThreeConstructorsModel model = factory.getAdapter(request,
WithThreeConstructorsModel.class);
assertNotNull(model);
assertEquals(request, model.getRequest());
- assertEquals(42, model.getAttribute());
+ assertEquals(INT_VALUE, model.getAttribute());
}
@Test
@@ -80,7 +90,7 @@ public class ConstructorTest {
WithTwoConstructorsModel model = factory.getAdapter(request,
WithTwoConstructorsModel.class);
assertNotNull(model);
assertEquals(request, model.getRequest());
- assertEquals(42, model.getAttribute());
+ assertEquals(INT_VALUE, model.getAttribute());
}
@Test
@@ -88,7 +98,7 @@ public class ConstructorTest {
SuperclassConstructorModel model = factory.getAdapter(request,
SuperclassConstructorModel.class);
assertNotNull(model);
assertEquals(request, model.getRequest());
- assertEquals(42, model.getAttribute());
+ assertEquals(INT_VALUE, model.getAttribute());
}
@Test
@@ -97,4 +107,23 @@ public class ConstructorTest {
assertNull(model);
}
+ /**
+ * Test model object with three constructors, and make sure that one with
@Inject is picked for instantiation.
+ * Test mixing of constructor injection and field injection as well.
+ */
+ @Test
+ public void testThreeConstructorsOneInjectInjection() {
+ WithThreeConstructorsOneInjectModel model = factory.getAdapter(request,
+ WithThreeConstructorsOneInjectModel.class);
+ assertNotNull(model);
+ assertNull(model.getRequest());
+ assertEquals(INT_VALUE, model.getAttribute());
+ assertEquals(STRING_VALUE, model.getAttribute2());
+ }
+
+ @Test
+ public void testNoNameModel() {
+ NoNameModel model = factory.getAdapter(request, NoNameModel.class);
+ assertNull(model);
+ }
}
Modified:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/DefaultTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/DefaultTest.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/DefaultTest.java
(original)
+++
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/DefaultTest.java
Tue Aug 19 22:51:36 2014
@@ -39,6 +39,7 @@ import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
public class DefaultTest {
@Mock
@@ -58,7 +59,7 @@ public class DefaultTest {
}
@Test
- public void testDefaultStringValue() {
+ public void testDefaultStringValueField() {
ValueMap vm = new ValueMapDecorator(Collections.<String,
Object>emptyMap());
Resource res = mock(Resource.class);
@@ -71,7 +72,7 @@ public class DefaultTest {
}
@Test
- public void testDefaultStringValueOnInterface() {
+ public void testDefaultStringValueOnInterfaceField() {
ValueMap vm = new ValueMapDecorator(Collections.<String,
Object>singletonMap("first", "first value"));
Resource res = mock(Resource.class);
@@ -85,7 +86,7 @@ public class DefaultTest {
@Test
- public void testDefaultPrimitives() {
+ public void testDefaultPrimitivesField() {
ValueMap vm = new ValueMapDecorator(Collections.<String,
Object>emptyMap());
Resource res = mock(Resource.class);
@@ -103,7 +104,7 @@ public class DefaultTest {
}
@Test
- public void testDefaultWrappers() {
+ public void testDefaultWrappersField() {
ValueMap vm = new ValueMapDecorator(Collections.<String,
Object>emptyMap());
Resource res = mock(Resource.class);
@@ -119,4 +120,57 @@ public class DefaultTest {
assertEquals(Long.valueOf(1L), model.getLongWrapperProperty());
assertArrayEquals(new Long[] { Long.valueOf(1L), Long.valueOf(1L) },
model.getLongWrapperArrayProperty());
}
+
+ @Test
+ public void testDefaultStringValueConstructor() {
+ ValueMap vm = new ValueMapDecorator(Collections.<String,
Object>emptyMap());
+
+ Resource res = mock(Resource.class);
+ when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.DefaultStringModel
model
+ = factory.getAdapter(res,
org.apache.sling.models.testmodels.classes.constructorinjection.DefaultStringModel.class);
+ assertNotNull(model);
+ assertEquals("firstDefault", model.getFirstProperty());
+ assertEquals(2, model.getSecondProperty().length);
+ }
+
+ @Test
+ public void testDefaultPrimitivesConstructor() {
+ ValueMap vm = new ValueMapDecorator(Collections.<String,
Object>emptyMap());
+
+ Resource res = mock(Resource.class);
+ when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.DefaultPrimitivesModel
model
+ = factory.getAdapter(res,
org.apache.sling.models.testmodels.classes.constructorinjection.DefaultPrimitivesModel.class);
+ assertNotNull(model);
+
+ assertEquals(true, model.getBooleanProperty());
+ // we need to wait for JUnit 4.12 for this assertArrayEquals to be
working on primitive boolean arrays,
https://github.com/junit-team/junit/issues/86!
+ assertTrue(Arrays.equals(new boolean[] { true, true },
model.getBooleanArrayProperty()));
+
+ assertEquals(1L, model.getLongProperty());
+ assertArrayEquals(new long[] { 1L, 1L }, model.getLongArrayProperty());
+ }
+
+ @Test
+ public void testDefaultWrappersConstructor() {
+ ValueMap vm = new ValueMapDecorator(Collections.<String,
Object>emptyMap());
+
+ Resource res = mock(Resource.class);
+ when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.DefaultWrappersModel
model
+ = factory.getAdapter(res,
org.apache.sling.models.testmodels.classes.constructorinjection.DefaultWrappersModel.class);
+ assertNotNull(model);
+
+ assertEquals(Boolean.valueOf(true), model.getBooleanWrapperProperty());
+ // we need to wait for JUnit 4.12 for this assertArrayEquals to be
working on primitive boolean arrays,
https://github.com/junit-team/junit/issues/86!
+ assertTrue(Arrays.equals(new Boolean[] { Boolean.TRUE, Boolean.TRUE },
model.getBooleanWrapperArrayProperty()));
+
+ assertEquals(Long.valueOf(1L), model.getLongWrapperProperty());
+ assertArrayEquals(new Long[] { Long.valueOf(1L), Long.valueOf(1L) },
model.getLongWrapperArrayProperty());
+ }
+
}
Modified:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
(original)
+++
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InjectorSpecificAnnotationTest.java
Tue Aug 19 22:51:36 2014
@@ -50,6 +50,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
public class InjectorSpecificAnnotationTest {
@Mock
@@ -110,7 +111,7 @@ public class InjectorSpecificAnnotationT
}
@Test
- public void testSimpleValueModel() {
+ public void testSimpleValueModelField() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("first", "first-value");
map.put("second", "second-value");
@@ -127,7 +128,7 @@ public class InjectorSpecificAnnotationT
}
@Test
- public void testOrderForValueAnnotation() {
+ public void testOrderForValueAnnotationField() {
// make sure that that the correct injection is used
// make sure that log is adapted from value map
// and not coming from request attribute
@@ -149,7 +150,7 @@ public class InjectorSpecificAnnotationT
}
@Test
- public void testOSGiService() throws InvalidSyntaxException {
+ public void testOSGiServiceField() throws InvalidSyntaxException {
ServiceReference ref = mock(ServiceReference.class);
Logger log = mock(Logger.class);
when(bundleContext.getServiceReferences(Logger.class.getName(),
null)).thenReturn(
@@ -162,7 +163,7 @@ public class InjectorSpecificAnnotationT
}
@Test
- public void testScriptVariable() throws InvalidSyntaxException {
+ public void testScriptVariableField() throws InvalidSyntaxException {
SlingBindings bindings = new SlingBindings();
SlingScriptHelper helper = mock(SlingScriptHelper.class);
bindings.setSling(helper);
@@ -174,7 +175,7 @@ public class InjectorSpecificAnnotationT
}
@Test
- public void testRequestAttribute() throws InvalidSyntaxException {
+ public void testRequestAttributeField() throws InvalidSyntaxException {
Object attribute = new Object();
when(request.getAttribute("attribute")).thenReturn(attribute);
@@ -184,7 +185,7 @@ public class InjectorSpecificAnnotationT
}
@Test
- public void testChildResource() {
+ public void testChildResourceField() {
Resource res = mock(Resource.class);
Resource child = mock(Resource.class);
when(res.getChild("child1")).thenReturn(child);
@@ -194,4 +195,97 @@ public class InjectorSpecificAnnotationT
assertNotNull("Could not instanciate model", model);
assertEquals(child, model.getChildResource());
}
+
+ @Test
+ public void testSimpleValueModelConstructor() {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("first", "first-value");
+ map.put("second", "second-value");
+ ValueMap vm = new ValueMapDecorator(map);
+
+ Resource res = mock(Resource.class);
+ when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+ when(request.getResource()).thenReturn(res);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel
model
+ = factory.getAdapter(request,
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+ assertNotNull("Could not instanciate model", model);
+ assertEquals("first-value", model.getFirst());
+ assertEquals("second-value", model.getSecond());
+ }
+
+ @Test
+ public void testOrderForValueAnnotationConstructor() {
+ // make sure that that the correct injection is used
+ // make sure that log is adapted from value map
+ // and not coming from request attribute
+ Logger logFromValueMap = LoggerFactory.getLogger(this.getClass());
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("first", "first-value");
+ map.put("log", logFromValueMap);
+ ValueMap vm = new ValueMapDecorator(map);
+
+ Resource res = mock(Resource.class);
+ when(res.adaptTo(ValueMap.class)).thenReturn(vm);
+ when(request.getResource()).thenReturn(res);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel
model
+ = factory.getAdapter(request,
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+ assertNotNull("Could not instanciate model", model);
+ assertEquals("first-value", model.getFirst());
+ assertEquals(logFromValueMap, model.getLog());
+ }
+
+ @Test
+ public void testOSGiServiceConstructor() throws InvalidSyntaxException {
+ ServiceReference ref = mock(ServiceReference.class);
+ Logger log = mock(Logger.class);
+ when(bundleContext.getServiceReferences(Logger.class.getName(),
null)).thenReturn(
+ new ServiceReference[] { ref });
+ when(bundleContext.getService(ref)).thenReturn(log);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel
model
+ = factory.getAdapter(request,
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+ assertNotNull("Could not instanciate model", model);
+ assertEquals(log, model.getService());
+ }
+
+ @Test
+ public void testScriptVariableConstructor() throws InvalidSyntaxException {
+ SlingBindings bindings = new SlingBindings();
+ SlingScriptHelper helper = mock(SlingScriptHelper.class);
+ bindings.setSling(helper);
+
when(request.getAttribute(SlingBindings.class.getName())).thenReturn(bindings);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel
model
+ = factory.getAdapter(request,
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+ assertNotNull("Could not instanciate model", model);
+ assertEquals(helper, model.getHelper());
+ }
+
+ @Test
+ public void testRequestAttributeConstructor() throws
InvalidSyntaxException {
+ Object attribute = new Object();
+ when(request.getAttribute("attribute")).thenReturn(attribute);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel
model
+ = factory.getAdapter(request,
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+ assertNotNull("Could not instanciate model", model);
+ assertEquals(attribute, model.getRequestAttribute());
+ }
+
+ @Test
+ public void testChildResourceConstructor() {
+ Resource res = mock(Resource.class);
+ Resource child = mock(Resource.class);
+ when(res.getChild("child1")).thenReturn(child);
+ when(request.getResource()).thenReturn(res);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel
model
+ = factory.getAdapter(request,
org.apache.sling.models.testmodels.classes.constructorinjection.InjectorSpecificAnnotationModel.class);
+ assertNotNull("Could not instanciate model", model);
+ assertEquals(child, model.getChildResource());
+ }
+
}
Modified:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java?rev=1619007&r1=1619006&r2=1619007&view=diff
==============================================================================
---
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
(original)
+++
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/OSGiInjectionTest.java
Tue Aug 19 22:51:36 2014
@@ -47,6 +47,7 @@ import org.osgi.framework.ServiceReferen
import org.osgi.service.component.ComponentContext;
@RunWith(MockitoJUnitRunner.class)
+@SuppressWarnings("javadoc")
public class OSGiInjectionTest {
private ModelAdapterFactory factory;
@@ -75,7 +76,7 @@ public class OSGiInjectionTest {
}
@Test
- public void testSimpleOSGiModel() throws Exception {
+ public void testSimpleOSGiModelField() throws Exception {
ServiceReference ref = mock(ServiceReference.class);
ServiceInterface service = mock(ServiceInterface.class);
when(bundleContext.getServiceReferences(ServiceInterface.class.getName(),
null)).thenReturn(
@@ -93,7 +94,7 @@ public class OSGiInjectionTest {
}
@Test
- public void testRequestOSGiModel() throws Exception {
+ public void testRequestOSGiModelField() throws Exception {
ServiceInterface service = mock(ServiceInterface.class);
SlingHttpServletRequest request = mock(SlingHttpServletRequest.class);
@@ -114,7 +115,7 @@ public class OSGiInjectionTest {
}
@Test
- public void testListOSGiModel() throws Exception {
+ public void testListOSGiModelField() throws Exception {
ServiceReference ref1 = mock(ServiceReference.class);
ServiceInterface service1 = mock(ServiceInterface.class);
when(bundleContext.getService(ref1)).thenReturn(service1);
@@ -138,7 +139,7 @@ public class OSGiInjectionTest {
}
@Test
- public void testArrayOSGiModel() throws Exception {
+ public void testArrayOSGiModelField() throws Exception {
ServiceReference ref1 = mock(ServiceReference.class);
ServiceInterface service1 = mock(ServiceInterface.class);
when(bundleContext.getService(ref1)).thenReturn(service1);
@@ -162,7 +163,7 @@ public class OSGiInjectionTest {
}
@Test
- public void testOptionalArrayOSGiModel() throws Exception {
+ public void testOptionalArrayOSGiModelField() throws Exception {
Resource res = mock(Resource.class);
@@ -174,7 +175,7 @@ public class OSGiInjectionTest {
}
@Test
- public void testOptionalListOSGiModel() throws Exception {
+ public void testOptionalListOSGiModelField() throws Exception {
Resource res = mock(Resource.class);
OptionalListOSGiModel model = factory.getAdapter(res,
OptionalListOSGiModel.class);
@@ -185,7 +186,7 @@ public class OSGiInjectionTest {
}
@Test
- public void testCollectionOSGiModel() throws Exception {
+ public void testCollectionOSGiModelField() throws Exception {
ServiceReference ref1 = mock(ServiceReference.class);
ServiceInterface service1 = mock(ServiceInterface.class);
when(bundleContext.getService(ref1)).thenReturn(service1);
@@ -210,7 +211,7 @@ public class OSGiInjectionTest {
}
@Test
- public void testSetOSGiModel() throws Exception {
+ public void testSetOSGiModelField() throws Exception {
ServiceReference ref1 = mock(ServiceReference.class);
ServiceInterface service1 = mock(ServiceInterface.class);
when(bundleContext.getService(ref1)).thenReturn(service1);
@@ -232,4 +233,49 @@ public class OSGiInjectionTest {
verify(bundleContext).getBundles();
verifyNoMoreInteractions(res, bundleContext);
}
+
+ @Test
+ public void testSimpleOSGiModelConstructor() throws Exception {
+ ServiceReference ref = mock(ServiceReference.class);
+ ServiceInterface service = mock(ServiceInterface.class);
+
when(bundleContext.getServiceReferences(ServiceInterface.class.getName(),
null)).thenReturn(
+ new ServiceReference[] { ref });
+ when(bundleContext.getService(ref)).thenReturn(service);
+
+ Resource res = mock(Resource.class);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.SimpleOSGiModel
model
+ = factory.getAdapter(res,
org.apache.sling.models.testmodels.classes.constructorinjection.SimpleOSGiModel.class);
+ assertNotNull(model);
+ assertNotNull(model.getService());
+ assertEquals(service, model.getService());
+
+ verifyNoMoreInteractions(res);
+ }
+
+ @Test
+ public void testListOSGiModelConstructor() throws Exception {
+ ServiceReference ref1 = mock(ServiceReference.class);
+ ServiceInterface service1 = mock(ServiceInterface.class);
+ when(bundleContext.getService(ref1)).thenReturn(service1);
+ ServiceReference ref2 = mock(ServiceReference.class);
+ ServiceInterface service2 = mock(ServiceInterface.class);
+ when(bundleContext.getService(ref2)).thenReturn(service2);
+
+
when(bundleContext.getServiceReferences(ServiceInterface.class.getName(),
null)).thenReturn(
+ new ServiceReference[] { ref1, ref2 });
+
+ Resource res = mock(Resource.class);
+
+
org.apache.sling.models.testmodels.classes.constructorinjection.ListOSGiModel
model
+ = factory.getAdapter(res,
org.apache.sling.models.testmodels.classes.constructorinjection.ListOSGiModel.class);
+ assertNotNull(model);
+ assertNotNull(model.getServices());
+ assertEquals(2, model.getServices().size());
+ assertEquals(service1, model.getServices().get(0));
+ assertEquals(service2, model.getServices().get(1));
+
+ verifyNoMoreInteractions(res);
+ }
+
}