I have written my own custom annotation 'Jeroen':
import com.asadventure.platform.component.text.JeroenInjector;
import org.apache.sling.models.annotations.Source;
import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@InjectAnnotation
@Source(JeroenInjector.NAME)
public @interface Jeroen {
String property();
}
And a custom injector:
import com.asadventure.core.constant.PropertyConstants;
import com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap;
import com.day.cq.commons.inherit.InheritanceValueMap;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.spi.DisposalCallbackRegistry;
import org.apache.sling.models.spi.Injector;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Type;
@Component(service = {Injector.class}, property = {
Constants.SERVICE_RANKING + ":Integer=" + 4300
})
public class JeroenInjector implements Injector {
public static final String NAME = "jeroen-injector";
@Override
public String getName() {
return NAME;
}
@Override
public Object getValue(final Object adaptable, final String name, final Type type, final AnnotatedElement element,
final DisposalCallbackRegistry callbackRegistry) {
// Only class types are supported
if (!(type instanceof Class<?>)) {
return null;
}
Class<?> requestedClass = (Class<?>) type;
Resource resource = getResource(adaptable);
Page page = getResourcePage(adaptable);
if (requestedClass.equals(String.class)) {
return getValueFromInheritanceMap("as:hrefLang", resource, page);
}
return null;
}
//... more logic here
}
It seems that the getValue in the jeroenInjector class also gets called for properties that are NOT annotated with my custom '@Jeroen' annotation. I tought the @Source on my annotation would prevent this from happening:
@Inject
@Optional
@Named("configPageImage/fileReference")
String pageImageReference;
I only expect fields annotated with @Jeroen to call my injectors getValue method as here:
@Jeroen(property = "as:hrefLang")
private String jeroenTest;
What am I doing wrong? Thanks in advance
Solved! Go to Solution.
Views
Replies
Total Likes
The way sling injectors work is the following:
when an element is annotated with @Inject, ALL injector services (including your custom one) are called according to their ranking untill a non-null value is returned if no injector returns a non-null value, null is returned.
When using a custom injector, only the injector service registered to that injector is called.
Your custom injector seems very specific, so you'll need an exit case in your injector, something like:
"if property option is null, return null"
or "If element where injector is used is not annotated with @Jeroen return null"
or some other specific condition so that your injector always returns null except for the specific condition you use it for.
Views
Replies
Total Likes
This looks like a really good topic to base a Community article on. We do not have an example that I can refer you to. However - here is a community artilce that may help:
Sling Models: How to write Sling Model Injector - Bots & AEM corner
Also - i am asking internal ppl.
Our team also suggested you look here to see a code example that works:
ACS Commons has a feature that does this: https://adobe-consulting-services.github.io/acs-aem-commons/features/sling-model-injectors/aem-objec...
This is an not the way Sling Models works by default. If there is no @Source annotation (or no custom injector which provides the source value), all injectors are checked. The @Source annotation is just used to refine the scope of annotations checked. You can certainly achieve what you are describing in your custom injector by returning null if the annotation isn't present.
The way sling injectors work is the following:
when an element is annotated with @Inject, ALL injector services (including your custom one) are called according to their ranking untill a non-null value is returned if no injector returns a non-null value, null is returned.
When using a custom injector, only the injector service registered to that injector is called.
Your custom injector seems very specific, so you'll need an exit case in your injector, something like:
"if property option is null, return null"
or "If element where injector is used is not annotated with @Jeroen return null"
or some other specific condition so that your injector always returns null except for the specific condition you use it for.
Views
Replies
Total Likes
So the @Inject annotation has no @Source annotation pointing to a specific injector so they all pass my customer injector? By "or no custom injector which provides the source value" you mean that the getName method of the injector returns a value matching the value in the @Source annotation?
Views
Replies
Total Likes
I could use something like here? sling-models-demo/ResourcePathInjector.java at master · justinedelson/sling-models-demo · GitHub
ResourcePath path = element.getAnnotation(ResourcePath.class);
if (path == null) {
return null;
}
Views
Replies
Total Likes