Expand my Community achievements bar.

Submissions are now open for the 2026 Adobe Experience Maker Awards.
SOLVED

Issue in Sling Model instantiating from Sightly

Avatar

Level 2

Hi 

I’m trying to use a simple Sling Model from HTL, but the model never instantiates (null bindings). I suspect I’m missing something obvious with the adaptable.

Sling Model

package com.acme.core.models;

import javax.inject.Inject;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;

@Model(
adaptables = Resource.class,
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
public class TeaserModel {

@inject
private String title;

public String getTitle() {
return title;
}
}

 

Sightly

<div data-sly-use.m="com.acme.core.models.TeaserModel">
<h2>${m.title}</h2>
</div>

 

When I check the logs here is what I get, what wrong here?

org.apache.sling.models.impl.ModelAdapterFactory Could not adapt
org.apache.sling.api.SlingHttpServletRequest to com.acme.core.models.TeaserModel

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @AnujaRa,

I think, HTL tries to adapt from the request by default, but your model is Resource-adaptable.

You have 2 options:

1. Make the model request-adaptable (HTL unchanged):

@Model(
  adaptables = org.apache.sling.api.SlingHttpServletRequest.class,
  defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
public class TeaserModel {
  @org.apache.sling.models.annotations.injectorspecific.ValueMapValue(
    name = org.apache.jackrabbit.JcrConstants.JCR_TITLE
  )
  private String title;
  public String getTitle() { return title; }
}

2. Keep Resource-adaptable and force resource adaptation in HTL:

<div data-sly-use.m="${'com.acme.core.models.TeaserModel' @ resource=resource}">
  <h2>${m.title}</h2>
</div>

Also, I see property name mismatch in your code: Field is title, but the JCR property is jcr:title. With plain @Inject it won’t map.
Try to use @ValueMapValue(name = "jcr:title") (shown above) or rename the field to jcr:title (not recommended).


Santosh Sai

AEM BlogsLinkedIn


View solution in original post

3 Replies

Avatar

Level 10

Your model says it adapts from Resource.class, but HTL uses the SlingHttpServletRequest as the adaptable by default when using data-sly-use. Because the model isn’t configured to adapt from request, adaptation fails and returns null. 

Change your model to adapt from SlingHttpServletRequest.class

@Model(adaptables = SlingHttpServletRequest.class,
       defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class TeaserModel {
    @inject
    private String title;

    public String getTitle() {
        return title;
    }
}

This way, when HTL runs data-sly-use, it adapts the current request to your model, which matches the adaptable.

 
 

Avatar

Correct answer by
Community Advisor

Hi @AnujaRa,

I think, HTL tries to adapt from the request by default, but your model is Resource-adaptable.

You have 2 options:

1. Make the model request-adaptable (HTL unchanged):

@Model(
  adaptables = org.apache.sling.api.SlingHttpServletRequest.class,
  defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
public class TeaserModel {
  @org.apache.sling.models.annotations.injectorspecific.ValueMapValue(
    name = org.apache.jackrabbit.JcrConstants.JCR_TITLE
  )
  private String title;
  public String getTitle() { return title; }
}

2. Keep Resource-adaptable and force resource adaptation in HTL:

<div data-sly-use.m="${'com.acme.core.models.TeaserModel' @ resource=resource}">
  <h2>${m.title}</h2>
</div>

Also, I see property name mismatch in your code: Field is title, but the JCR property is jcr:title. With plain @Inject it won’t map.
Try to use @ValueMapValue(name = "jcr:title") (shown above) or rename the field to jcr:title (not recommended).


Santosh Sai

AEM BlogsLinkedIn


Avatar

Level 2

@SantoshSai Thanks for the last point you mentioned about mapping title field, inititally I tried SlingHttpServletRequest but may be because of field mismatch it didn't worked but now it worked!