@Inject : A discouraged sling-model annotation



"I just copy and paste it from somewhere and since it was working so I keep it like this. 😎"

        @Model(adaptables = Resource.class)
    public class ExampleModel {

@Inject
private MyService myService;

@Inject
private String title ;

// ... rest of the class
}

I got this reply from the developer while reviewing his code above so thought of writing one extension post of my previous blog Common Myths Around Sling Model

So lets dive into the working mechanism of @Inject annotation but before that I would like to explain the injector first.

                                                        An OOB injector

    @Component(property=Constants.SERVICE_RANKING+":Integer=3000",
            service={Injector.class, InjectAnnotationProcessorFactory2.class})
public class ChildResourceInjector extends AbstractInjector implements Injector,
    InjectAnnotationProcessorFactory2 {

@Override
public @NotNull String getName() {
return "child-resources";
}

@Override
public Object getValue(@NotNull Object adaptable, String name,
                    @NotNull Type declaredType, @NotNull AnnotatedElement element,
@NotNull DisposalCallbackRegistry callbackRegistry) {
if (adaptable instanceof Resource) {
Resource child = ((Resource) adaptable).getChild(name);
if (child != null) {
return getValue(child, declaredType);
}
}
return null;
}
}

In the context of sling model "injector" is a mechanism that provides a way to inject various types of resources, values or services into a sling model. Injectors allow us to retrieve and use resources, properties, services and other objects without manually looking them up or creating them. All active Sling Model Injectors are available at http://localhost:4502/system/console/status-slingmodels in an AEM instance.


So what happens when we use @Inject?

AEM iterates through all the available injectors and inject the first non-null value provided by an injector. And the order of the injector's list depends on the service ranking of the particular injector implementation as an injector is originally an OSGI Service.

So rolling over a list of injector and picks the first one which resolve something don't you think this will lead to an unwanted and unpredictable behaviour? Definitely Yes...!

This becomes a very big performance bottleneck if an optional injection were not successful and then all other injector have to be tried.

When we use @Inject to resolve a service into a sling model, the underlaying framework searches through the OSGI service registry to locate the right service instance. Once the appropriate service is resolved, it needs to be instantiated. Depending on the implementation logic and complexities of the service, initialisation certainly takes time and resources. This is again a drawback with @Inject annotation. 


The above four paragraph is the main inspiration behind the title of this post.

So what is the way forward?

This is where the injector specific annotation comes into picture. It is strongly recommend to use the injector specific annotation for respective purposes. Below are some of the important injector specific annotation available:
  1. @ValueMapValue
  2. @ChildResource
  3. @RequestAttribute
  4. @ResourcePath
  5. @OSGiService
  6. @SlingObject
All the details about the above annotations can be found on the sling document.

So after implementing injector specific annotations the above sling model will look like 

    @Model(adaptables = Resource.class)
public class ExampleModel {

@OSGiService
private MyService myService;

@ValueMapValue
private String title ;

// ... rest of the class
}



Happy Reading...!



Comments

Popular posts from this blog

Common cause for NullPionterException or Null value in Junit test case for sling model in aem

"java.lang.NoSuchFieldError: FACTORY" while running Junit test in AEM codebase