kwin commented on code in PR #106: URL: https://github.com/apache/sling-site/pull/106#discussion_r1061127843
########## src/main/jbake/content/documentation/bundles/models.md: ########## @@ -179,92 +150,121 @@ Since Sling Models 1.2.0 there is another way of instantiating models. The OSGi // See the javadoc of the ModelFactory for which Exception can be expected here } -In addition `ModelFactory` provides methods for checking whether a given class is a model at all (having the model annotation) or whether a class can be adapted from a given adaptable. +In addition `ModelFactory` provides methods for checking whether a given class is a model at all (having the model annotation) or whether a class can be adapted from a given adaptable. ## Usage in HTL -[Sling Models Use Provider](/documentation/bundles/scripting/scripting-htl.html#java-use-provider-1) (internally uses the `ModelFactory` from above). +Please see [Sling Models Use Provider](/documentation/bundles/scripting/scripting-htl.html#java-use-provider-1); internally it uses the `ModelFactory` from above. -# Other Options -## Names -If the field or method name doesn't exactly match the property name, `@Named` can be used: - ::java - @Model(adaptables=Resource.class) - public class MyModel { - - @Inject @Named("secondPropertyName") - private String otherName; - } - +# Available injectors + +In the above cases just the `@ValueMapValue` annotation was used, but there other available injectors. For each injector there is a specialized annotation available. For the optional parameters see the next section. + + +Injector Name | Annotation | Supported Optional Elements | Description | Array Support | Parametrized Type Support Review Comment: The first column is now a label and no longer the name. The name should still be documented as it must be used with annotation `@Source` ########## src/main/jbake/content/documentation/bundles/models.md: ########## @@ -89,40 +83,13 @@ Constructor injection is also supported (as of Sling Models 1.1.0): Because the name of a constructor argument parameter cannot be detected via the Java Reflection API a `@Named` annotation is mandatory for injectors that require a name for resolving the injection. -Constructors may use any visibility modifier (as of [Sling Models 1.5.0](https://issues.apache.org/jira/browse/SLING-8069)): +Constructors may use any visibility modifier (as of [Sling Models 1.5.0](https://issues.apache.org/jira/browse/SLING-8069)). - ::java - @Model(adaptables=Resource.class) - public class PublicConstructorModel { - @Inject - public PublicConstructorModel() { - // constructor code - } - } +## @Model and adaptable types - @Model(adaptables=Resource.class) - public class ProtectedConstructorModel { - @Inject - protected ProtectedConstructorModel() { - // constructor code - } - } +While technically it is possible to provide any class implementing the `Adaptable` interface as the `adaptable` parameter to the `@Model` annotation, the Sling Model Framework and the default injectors is mostly built under the assumption that the adaption is done from a Sling Resource. All injectors also support adaption from a `SlingHttpServletRequest` object, but normally this is then converted into a adaption of the resource of the request. The only exception on the default injectors is the "Request Attribute" injector, which requires that the model is adapted from a SlingHttpServletRequest. Review Comment: More prominent examples requiring request: script bindings and sling object ########## src/main/jbake/content/documentation/bundles/models.md: ########## @@ -660,86 +612,78 @@ If you want to generate a bundle header compliant with Sling Models < 1.3.4 (i.e </instructions> </configuration> -# Caching -By default, Sling Models do not do any caching of the adaptation result and every request for a model class will -result in a new instance of the model class. However, there are two notable cases when the adaptation result can be cached. The first case is when the adaptable extends the `SlingAdaptable` base class. Most significantly, this is the case for many `Resource` adaptables as `AbstractResource` extends `SlingAdaptable`. `SlingAdaptable` implements a caching mechanism such that multiple invocations of `adaptTo()` will return the same object. For example: - ::java - // assume that resource is an instance of some subclass of AbstractResource - ModelClass object1 = resource.adaptTo(ModelClass.class); // creates new instance of ModelClass - ModelClass object2 = resource.adaptTo(ModelClass.class); // SlingAdaptable returns the cached instance - assert object1 == object2; -While this is true for `AbstractResource` subclasses, it is notably **not** the case for `SlingHttpServletRequest` as this class does not extend `SlingAdaptable`. So: - ::java - // assume that request is some SlingHttpServletRequest object - ModelClass object1 = request.adaptTo(ModelClass.class); // creates new instance of ModelClass - ModelClass object2 = request.adaptTo(ModelClass.class); // creates another new instance of ModelClass - assert object1 != object2; +# Discouraged annotations -Since API version 1.3.4, Sling Models *can* cache an adaptation result, regardless of the adaptable by specifying `cache = true` on the `@Model` annotation. +In earlier versions of Sling Models the use of the annotation `@Inject` was suggested and documented; but over time it turned out that it had 2 major issues: +* This injection iterated through all available injectors and injected the first non-null value provided by an injector. This lead to unpredictable behavior, although the order is well-defined. The addition of the `@Source` annotation did not really help. Review Comment: Although @Source would have helped it was rarely used. ########## src/main/jbake/content/documentation/bundles/models.md: ########## @@ -660,86 +612,78 @@ If you want to generate a bundle header compliant with Sling Models < 1.3.4 (i.e </instructions> </configuration> -# Caching -By default, Sling Models do not do any caching of the adaptation result and every request for a model class will -result in a new instance of the model class. However, there are two notable cases when the adaptation result can be cached. The first case is when the adaptable extends the `SlingAdaptable` base class. Most significantly, this is the case for many `Resource` adaptables as `AbstractResource` extends `SlingAdaptable`. `SlingAdaptable` implements a caching mechanism such that multiple invocations of `adaptTo()` will return the same object. For example: - ::java - // assume that resource is an instance of some subclass of AbstractResource - ModelClass object1 = resource.adaptTo(ModelClass.class); // creates new instance of ModelClass - ModelClass object2 = resource.adaptTo(ModelClass.class); // SlingAdaptable returns the cached instance - assert object1 == object2; -While this is true for `AbstractResource` subclasses, it is notably **not** the case for `SlingHttpServletRequest` as this class does not extend `SlingAdaptable`. So: - ::java - // assume that request is some SlingHttpServletRequest object - ModelClass object1 = request.adaptTo(ModelClass.class); // creates new instance of ModelClass - ModelClass object2 = request.adaptTo(ModelClass.class); // creates another new instance of ModelClass - assert object1 != object2; +# Discouraged annotations -Since API version 1.3.4, Sling Models *can* cache an adaptation result, regardless of the adaptable by specifying `cache = true` on the `@Model` annotation. +In earlier versions of Sling Models the use of the annotation `@Inject` was suggested and documented; but over time it turned out that it had 2 major issues: +* This injection iterated through all available injectors and injected the first non-null value provided by an injector. This lead to unpredictable behavior, although the order is well-defined. The addition of the `@Source` annotation did not really help. +* This iteration turned out to the performance bottleneck, especially if (optional) injections were not succesful, and then all other injectors have to be tried. Review Comment: turned out to be a performance bottleneck ########## src/main/jbake/content/documentation/bundles/models.md: ########## @@ -179,92 +150,121 @@ Since Sling Models 1.2.0 there is another way of instantiating models. The OSGi // See the javadoc of the ModelFactory for which Exception can be expected here } -In addition `ModelFactory` provides methods for checking whether a given class is a model at all (having the model annotation) or whether a class can be adapted from a given adaptable. +In addition `ModelFactory` provides methods for checking whether a given class is a model at all (having the model annotation) or whether a class can be adapted from a given adaptable. ## Usage in HTL -[Sling Models Use Provider](/documentation/bundles/scripting/scripting-htl.html#java-use-provider-1) (internally uses the `ModelFactory` from above). +Please see [Sling Models Use Provider](/documentation/bundles/scripting/scripting-htl.html#java-use-provider-1); internally it uses the `ModelFactory` from above. -# Other Options -## Names -If the field or method name doesn't exactly match the property name, `@Named` can be used: - ::java - @Model(adaptables=Resource.class) - public class MyModel { - - @Inject @Named("secondPropertyName") - private String otherName; - } - +# Available injectors + +In the above cases just the `@ValueMapValue` annotation was used, but there other available injectors. For each injector there is a specialized annotation available. For the optional parameters see the next section. + + +Injector Name | Annotation | Supported Optional Elements | Description | Array Support | Parametrized Type Support +----- | ----------------- | ------------------------------ |------------------------- | --------------- | --------------------------- +Scripting Bindings|`@ScriptVariable` | `injectionStrategy` and `name` | Injects the script variable defined via [Sling Bindings](https://cwiki.apache.org/confluence/display/SLING/Scripting+variables). If `name` is not set the name is derived from the method/field name. | no conversion is done | If a parameterized type is passed, the bindings value must be of a compatible type of the parameterized type. +ValueMap | `@ValueMapValue` | `injectionStrategy`, `name` | Injects a `ValueMap` value taken from the adapted resource (either taking from the adapted resource or the resource of the adapted SlingHttpServletRequest). If `name` is not set the name is derived from the method/field name. | Primitive arrays wrapped/unwrapped as necessary. Wrapper object arrays are unwrapped/wrapped as necessary. | Parameterized `List` and `Collection` injection points are injected by getting an array of the component type and creating an unmodifiable `List` from the array. +Child Resource | `@ChildResource` | `injectionStrategy`, `name` | Injects a child resource by name (taken from the adapted resource (either taking from the adapted resource or the resource of the adapted SlingHttpServletRequest). If `name` is not set the name is derived from the method/field name. | none | if a parameterized type `List` or `Collection` is passed, a `List<Resource>` is returned (the contents of which may be adapted to the target type) filled with all child resources of the resource looked up by the given name. +Request Attribute | `@RequestAttribute` | `injectionStrategy`, `name` | Injects a request attribute by name, it requires the the adaptable is a `SlingHttpServletRequest` . If `name` is not set the name is derived from the method/field name. | no conversion is done | If a parameterized type is passed, the request attribute must be of a compatible type of the parameterized type. +Resource path | `@ResourcePath` | `injectionStrategy`, `path`, and `name` |Injects a resource either by path or by reading a property with the given name. | yes | none +OSGi service | `@OSGiService` | `injectionStrategy`, `filter` | Injects an OSGi service by type (and the optional filter) | yes | Parameterized `List` and `Collection` injection points are injected by getting an array of the services and creating an unmodifiable `List` from the array. +Context-Aware Configuration | `@ContextAwareConfiguration` | `injectionStrategy`, `name` | Lookup context-aware configuration. See [Context-Aware Configuration](#context-aware-configuration) below. | yes | If a parameterized type `List` or `Collection` is used, a configuration collection is looked up. +Self | `@Self` | `injectionStrategy` | Injects the adaptable itself. If the field type does not match with the adaptable it is tried to adapt the adaptable to the requested type. | none | none +Sling Object | `@SlingObject` | `injectionStrategy` | Injects commonly used sling objects if the field matches with the class: request, response, resource resolver, current resource, SlingScriptHelper | none | none + +# Parameters to the Injectors + +Injectors can support optional parameters as listed in the above table + ## Optional and Required -`@Inject`ed fields/methods are assumed to be required. To mark them as optional, use `@Optional`: - ::java - @Model(adaptables=Resource.class) - public class MyModel { - - @Inject @Optional - private String otherName; - } +Injected fields/methods are assumed to be required. To mark them as optional, there are 2 options: + +* add the parameter `injectionStrategy=InjectionStrategy.OPTIONAL` to the annotation +* or wrap the type into an `Optional` + +It is recommended to use the approach using the `Optional` type, because then this "optionality" is also expressed in the type system. + + ::java + import java.util.Optional; + + @Model(adaptables=Resource.class) + public class MyModel { + + @ValueMapValue(injectionStrategy=InjectionStrategy.OPTIONAL) + private String optionalProperty; + + @ValueMapValue + private Optional<String> anotherOptionalProperty; + } +Please note, that also injections marked as optional are always tried. It is just that any failure to inject a value does not lead to the termination of the creation of the SlingModel, but instead it continues, leaving the field value/return value at the default value of the used type. Review Comment: that even injections marked as -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@sling.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org