1

2 Sling Models are given and I want to inject one of them. Is this possible with an annotation or do I need to create a PostContruct method as a workaround?

Example:

Model A

@Model(adaptables = Resource.class)
public class ModelA { 
   @ValueMapValue(name = "jcr:title", injectionStrategy = InjectionStrategy.OPTIONAL)
   private String title;

   @Inject // Not working! 
   private ModelB modelB;
}

Model B

@Model(adaptables = Resource.class)
public class ModelB { 
   @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
   private String text;

}
nicolas
  • 101
  • 2
  • 9
  • Is the resource that is represented by `ModelB` a child resource of the resource represented by `ModelA`? – Jens Sep 20 '16 at 13:50
  • No, it is the same resource. – nicolas Sep 20 '16 at 14:10
  • 1
    So you have a `ResourceA` and you want to adapt that resource to `ModelA` and `ModelB` at the same time? What you want to do is possible, as long as the resource represented by `ModelB` is a child resource of the resource represented by `ModelA`. See https://sling.apache.org/documentation/bundles/models.html#adaptations – Jens Sep 20 '16 at 20:08

2 Answers2

5

Since 1.1.0 version of Sling Models you can use @Self annotation to inject models which can be adapted from current adaptable. In this case from Resource of ModelA.

Injects the adaptable object itself (if the class of the field matches or is a supertype). If the @Self annotation is present it is tried to adapt the adaptable to the field type.

@Model(adaptables = Resource.class)
public class ModelA { 
   @ValueMapValue(name = "jcr:title", injectionStrategy = InjectionStrategy.OPTIONAL)
   private String title;

   @Inject // This should works
   @Self
   private ModelB modelB;
}
rzasap
  • 346
  • 1
  • 6
  • 3
    You don't even need to specify ```@Inject```, ```@Inject``` is the generic injection, where @Self is the specific form of injection. – JE Bailey Sep 26 '16 at 01:52
0

You wont be able to inject ModelB into ModelA, what you can do is get the resource instance in ModelA and adapt it to ModelB

@Model(adaptables = SlingHttpServletRequest.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ModelA { 
   @Inject
   @Via("resource") 
   @Named("jcr:title")
   private String title;

   @Inject 
   private Resource resource;

  @PostConstruct
  public void init() {
   final ModelB modelb = resource.adaptTo(ModelB.class);
   }
}
Ameesh Trikha
  • 1,652
  • 2
  • 12
  • 18
  • Yeah, that's what i suggested as a workaround.... No other way how to avoid it? @SlingObject doesn't work either... – nicolas Sep 20 '16 at 14:16
  • Its actually not a workaround, a sling model is based on adapter and Inject is more to facilitate DI and can not invoke adapter call. If you look at the Sling code for the SlingModel you will see the way Model annotation processes the other annotation and is in current state doesn't invoke adaptTo – Ameesh Trikha Sep 20 '16 at 14:20
  • 1
    The concept of using nested models via adaption was part of the sling models design from the very beginning. In 1.0 I believe it was implicitly attempted if other injectors failed and then in 1.1 it was explicitly stated via the Self annotation – JE Bailey Sep 26 '16 at 01:55