Jdruwe
Jdruwe

Reputation: 3520

AEM Osgi Sling Model @PostConstruct never called

I am having an issue with the javax.annotation.PostConstruct annotation in my Sling model.

My html file that uses my model:

<div data-sly-use="com.company.platform.component.general.textblockvalidator.TextBlockValidatorModel" data-sly-unwrap />

Model:

import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import javax.inject.Inject;

@Model(adaptables = org.apache.sling.api.resource.Resource.class)
public class TextBlockValidatorModel {

    @PostConstruct
    private void init() {
        System.out.println();
    }

    public String getValidate(){
        return "This works";
    }
}

I can call the getter from my sightly file but I never seem to enter my @PostConstruct init() method.

IntelliJ does give me a warning on the annotation but I am not sure what I am doing wrong:

enter image description here

Sling-model-packages:

<Sling-Model-Packages>
   ...
   com.asadventure.platform.component
   ...
</Sling-Model-Packages>

enter image description here

Any ideas? Thanks in advance!

Upvotes: 2

Views: 8809

Answers (3)

Bill Randall
Bill Randall

Reputation: 41

For anyone still looking for an answer to this that the above did not resolve, the issue for me was that I did not include the javax.annotation-api dependency:

<dependency>
  <groupId>javax.annotation</groupId>
  <artifactId>javax.annotation-api</artifactId>
  <version>1.3.2</version>
  <scope>provided</scope>
</dependency>

Once I added this in the parent pom, and its inclusion in the core pom, @PostConstruct worked just fine.

Update:

The reason I had to do this was because of my inclusion of jersey-client, which requires its own version of javax.annotation-api. Since my first rendition of this answer, I have found I needed to separate jersey-client and its dependencies into a separate bundle project. This allows both Jersey and @PostConstruct to work at the same time.

Just adding the dependency as the answer shows above caused issues with dependency clashes between Jersey's version of javax.annotation-api and AEM's version (Felix's version) of javax.annotation-api.

Upvotes: 2

santiagozky
santiagozky

Reputation: 2539

My guess is that your class is being initialized by the Java Use provider instead of adapting the current resource or request.

In sightly, when you use data-sly-use, it tries several things to obtain an object (I cant recall the order):

  • get an Osgi service with that name
  • use the AEM Java USE Api
  • Adapt the current request / resource into your model class (your desired case)
  • simply treat the class as a Java Pojo and instantiate it (post construct is not called, injection wont be done).

I've seen several cases where the injection or postconstruct methods of the sling models fails and sightly defaults to the java Use provider. If this happens what you describe happens. You have an object of the right class, but no injection happened and no post construct was called.

My recommendation is to careful check the logs, you should see an error if this is the case. Also, you can install the Scripting HTL Sling Models Use Provider which will propagate any error creating the sling model, making the problem obvious.

Upvotes: 1

mickleroy
mickleroy

Reputation: 1008

First, check your Sling Model has been registered correctly by looking for your class in this web page: http://localhost:4502/system/console/status-adapters

If it isn't listed there, you most likely have not specified the <Sling-Model-Packages> property of the maven-bundle-plugin.

I would also try changing the access modifier for the init method to protected or public.

UPDATE:

I've created a sample project for AEM 6.1 demonstrating the use of the @PostConstruct annotation.

The Sling Model class:

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

    private boolean postContructCalled = false;

    @PostConstruct
    public void init() {
        this.postContructCalled = true;
    }

    public boolean isPostContructCalled() {
        return this.postContructCalled;
    }
}

And a simple HTL component:

<sly data-sly-use.model="com.github.mickleroy.models.SampleModel">
    <p>@PostConstruct was called: ${model.postContructCalled}</p>
</sly>

Please take note of the use of the data-sly-use directive - you need to provide a model name.

Also, as I mentioned in the comments, you should not be adding javax.annotation-api as a dependency as it is part of the JDK.

Full source available here: https://github.com/mickleroy/sling-models-sample

Upvotes: 7

Related Questions