Your achievements

Level 1

0% to

Level 2

Tip /
Sign in

Sign in to Community

to gain points, level up, and earn exciting badges like the new
BedrockMission!

Learn More

View all

Sign in to view all badges

Need Jackson Exporter JSON response within SlingModel Class

Avatar

Avatar
Validate 1
Level 2
aman_goyal_15
Level 2

Likes

3 likes

Total Posts

14 posts

Correct Reply

0 solutions
Top badges earned
Validate 1
Boost 3
Boost 1
View profile

Avatar
Validate 1
Level 2
aman_goyal_15
Level 2

Likes

3 likes

Total Posts

14 posts

Correct Reply

0 solutions
Top badges earned
Validate 1
Boost 3
Boost 1
View profile
aman_goyal_15
Level 2

22-12-2020

Hi Team,

Usecase:  Need to utilize model JSON response in the component sightly file. 

 

Basically, we use Jackson Exporter to get JSON response for SlingModel but it's a servlet call on the component resource. But my requirement is to get the JSON response for SlingModel from one of the getter functions of the Sling Model. 

something like - 

 

 

 

 

@Model(adaptables = {
        SlingHttpServletRequest.class
}, adapters = {
        Button2.class,
        ComponentExporter.class
}, resourceType = Button2Impl.RESOURCE_TYPE)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class Button2Impl implements Button2 {

@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
private String label;

 public String getJsonString() {
  String json = "logic to get model json response like sling model exporter;
  return json;
 }
}
<sly data-sly-use.buttonProvider="${'com.sample.general.models.Button2'}">
<span> ${buttonProvider.jsonString} </span>
</sly>

 

 

 

 

Could anyone suggest how to achieve the above scenario? 

 

Thanks,

Aman

 

SlingModel Implementation Class -

 

 

import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.sample.sample.data_providers.general.models.Button2;
import com.sample.sample.services.utils.LinkUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
import org.apache.sling.models.factory.ExportException;
import org.apache.sling.models.factory.MissingExporterException;
import org.apache.sling.models.factory.ModelFactory;

import java.util.HashMap;
import java.util.Map;

@Model(adaptables = {
        SlingHttpServletRequest.class
}, adapters = {
        Button2.class,
        ComponentExporter.class
}, resourceType = Button2Impl.RESOURCE_TYPE)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class Button2Impl
        implements Button2
{
    public static final String RESOURCE_TYPE = "sample/components/general/button-2-0";

    
    private ResourceResolverFactory resourceResolverFactory;

    @SlingObject
    private ResourceResolver resourceResolver;
   
    @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
    private String iconAlignment;
    @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
    private String buttonAlignment;
    @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
    private String marginBottom;

    @SlingObject
    private Resource resource;
    @SlingObject
    private SlingHttpServletRequest request;
    @OSGiService
    ModelFactory modelFactory;
    
    
    public String getIconAlignment() { return iconAlignment; }

    
    public String getButtonAlignment() { return buttonAlignment; }

    
    @JsonIgnore
    public String getMarginBottom() { return marginBottom; }

    
    public String getExportedType() {
        return resource.getResourceType();
    }

    public String getJsonString() {
        Button2 buttonModel = request.adaptTo(Button2Impl.class); // tried adapting with resource as well but no luck 
        Map<String,String> options = new HashMap();
        String s = null;
        try {
            s = modelFactory.exportModel(buttonModel,ExporterConstants.SLING_MODEL_EXPORTER_NAME,String.class,options);
        } catch (ExportException e) {
            e.printStackTrace();
        } catch (MissingExporterException e) {
            e.printStackTrace();
        }
        return s;
    }

}

 

 

The solution to this query - 

 @JsonIgnore
    public String getJsonString() {
        ObjectMapper mapper = new ObjectMapper().configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        JsonNode node = mapper.valueToTree(this);
        String jsonString =null;
        try {
            jsonString = mapper.writeValueAsString(node);
        } catch (JsonProcessingException e) {
            e.getMessage();
        }
        return jsonString;
    }

Accepted Solutions (1)

Accepted Solutions (1)

Avatar

Avatar
Give Back 10
MVP
shelly-goel
MVP

Likes

183 likes

Total Posts

343 posts

Correct Reply

88 solutions
Top badges earned
Give Back 10
Validate 1
Shape 1
Ignite 1
Give Back 5
View profile

Avatar
Give Back 10
MVP
shelly-goel
MVP

Likes

183 likes

Total Posts

343 posts

Correct Reply

88 solutions
Top badges earned
Give Back 10
Validate 1
Shape 1
Ignite 1
Give Back 5
View profile
shelly-goel
MVP

22-12-2020

Hi@aman_goyal_15 

Another option is to use 'ObjectMapper' (com.fasterxml.jackson.databind.ObjectMapper) to map the model object as json. Add below method in your sling model class and either map the Button resource object or custom map object (with the specific value you need in json).

public String getJsonString() {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.valueToTree(<button object>);
String jsonString ="no value";
try {
jsonString = mapper.writeValueAsString(node);
} catch (JsonProcessingException e) {
LOG.error("Cannot output json", e);
}
return jsonString;
}

You need to have the 'Button' object in the model

@Self @Via(type = ResourceSuperType.class)
private Button2 button;

 

aman_goyal_15
Thanks for your response. Sling Model is not working when we are trying to get the Button2 object with @Self and @Via. I was checking on the @Via(type = ResourceSuperType.class), it is basically when we want to override the core component sling model. https://github.com/adobe/aem-core-wcm-components/wiki/Delegation-Pattern-for-Sling-Models#step-2-cre...
shelly-goel

@aman_goyal_15Yes that's the case when you're extending core component model. For your custom component model, you can directly pass the resource and it will work (unless resource is null).

The constraint in this approach would be that it would not return the values post model transformation but the original values on the resource and trying to access the exported model object from within the model will lead to infinite recursion.

As I mentioned earlier you can pass the custom object as per your needs (json structure/ fields as needed) in the ObjectMapper and below logic would work. It gives the flexibility in terms of what fields you want to include/ exclude in the json and pipelines can be attached to the mapper.

 

@JsonIgnore
public String getJsonString() {
ObjectMapper mapper = new ObjectMapper().configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
JsonNode node = mapper.valueToTree(new JsonConfig(getTitle(), getPretitle()));
String jsonString ="no value";
try {
jsonString = mapper.writeValueAsString(node);
} catch (JsonProcessingException e) {
LOG.error("Cannot output json", e);
}
return jsonString;
}

 

Here I created the custom object/ pojo as an inner class

private class JsonConfig {
private String title;
private String pretitle;
public JsonConfig() {};
public JsonConfig(String title, String pretitle) {
this.title = title;
this.pretitle = pretitle;
}
public String getTitle() {
return title;
}
public String getPretitle() {
return pretitle;
}
}

Please add @JsonIgnore annotations to all the methods that doesn't need to be part of .model.json request.

aman_goyal_15
Thank You Shelly .. It is working as expected. Passing 'this' reference as an argument to mapper.valueToTree is giving the actual Jackson exported model.json response.

Answers (3)

Answers (3)

Avatar

Avatar
Establish
MVP
Anudeep_Garnepudi
MVP

Likes

274 likes

Total Posts

320 posts

Correct Reply

87 solutions
Top badges earned
Establish
Ignite 1
Give Back 5
Give Back 3
Give Back 10
View profile

Avatar
Establish
MVP
Anudeep_Garnepudi
MVP

Likes

274 likes

Total Posts

320 posts

Correct Reply

87 solutions
Top badges earned
Establish
Ignite 1
Give Back 5
Give Back 3
Give Back 10
View profile
Anudeep_Garnepudi
MVP

23-12-2020

@aman_goyal_15 

Can you try 

@ScriptVariable
Resource resource;

and then

resource.adaptTo(Button2Impl.class);

 

Avatar

Avatar
Establish
MVP
BrianKasingli
MVP

Likes

615 likes

Total Posts

592 posts

Correct Reply

232 solutions
Top badges earned
Establish
Ignite 1
Give Back 5
Give Back 3
Give Back 10
View profile

Avatar
Establish
MVP
BrianKasingli
MVP

Likes

615 likes

Total Posts

592 posts

Correct Reply

232 solutions
Top badges earned
Establish
Ignite 1
Give Back 5
Give Back 3
Give Back 10
View profile
BrianKasingli
MVP

22-12-2020

@aman_goyal_15 

Another way is to do something like this within the servlet.

1. Set the response content-type.

2. Using business logic, locate the Sling resource you need.

3. Adapt the Sling resource to Button2Impl.

4. output the JSON string.

Example:

 

 @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
        response.setContentType(APPLICATION_JSON_UTF8);
        Resource buttonResource = request.getResourceResolver().getResource("/content/my-page/jcr:content/par/button");
        BUtton2 button2 = buttonResource.adaptTo(Button2Impl.class);
        if (button2 != null) {
            response.getWriter().write(button2.getJsonString());    
        }
        ...
    }

 

Avatar

Avatar
Validate 10
MVP
kunal23
MVP

Likes

166 likes

Total Posts

565 posts

Correct Reply

172 solutions
Top badges earned
Validate 10
Validate 1
Ignite 3
Ignite 1
Give Back 50
View profile

Avatar
Validate 10
MVP
kunal23
MVP

Likes

166 likes

Total Posts

565 posts

Correct Reply

172 solutions
Top badges earned
Validate 10
Validate 1
Ignite 3
Ignite 1
Give Back 50
View profile
kunal23
MVP

22-12-2020

You can use below code reference. Its a JSP code, you can convert it to Java and use in your sling model. The code uses Sling ModelFactory API to export a sling model. 

 

<%

//Get reference to model factory
org.apache.sling.models.factory.ModelFactory mf = sling.getService(org.apache.sling.models.factory.ModelFactory.class);

//Get sling model
Title title = slingRequest.adaptTo(com.adobe.cq.wcm.core.components.models.Title.class);


Map<String,String> options = new HashMap();
//Export and print json
String s = mf.exportModel(title,"jackson",String.class,options);
out.println(s);

%>

 

 

 

Output-

{"id":"title-d61980eb4b","linkDisabled":false,"type":"h3","text":"Standard",":type":"core/wcm/components/title/v2/title"}