Need to add multifield child Resource as JSON in the Sling Component Exporter | Community
Skip to main content
NageshRaja
Level 5
June 23, 2025
Solved

Need to add multifield child Resource as JSON in the Sling Component Exporter

  • June 23, 2025
  • 2 replies
  • 461 views

Hi All,

 

I have a JSON for the component which is exported as below - 

"componentA": {
":type": "a/b/c",
"test": "Test String.",
"test1": "cf63d10c-5ad7-44d5-9986-e1673b21675c",
"test2": "#E5E5E5",
"test3": "false"
}

 

However, the component has an inherent logic - The sightly for the component calls a generic model which collects multi-field items as resource and displays its details.

<sly data-sly-use.testList="${'test.abc.core.models.multifieldcollection.MultifieldCollectionModel' @ resourcePath = resource.path , multifieldName='testList'}"
if (resourcePath != null && multifieldName != null) {
String multifieldResourcePath = String.join("/", resourcePath, multifieldName);
ResourceResolver resolver = resource.getResourceResolver();
Resource multifieldResource = resolver.getResource(multifieldResourcePath);
if (multifieldResource != null) {
multifieldResource.listChildren().forEachRemaining(multiCollection::add);
}
}

 

As you can see this helps fetches all the multi-field items but doesn't extend the same to JSON as there is no way to export this as @JsonProperty.

What should be the best way to export these items as part of the component's JSON?

 

Thanks,

NR

 

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by SantoshSai

Hi @nageshraja,

You’ll need to update the model MultifieldCollectionModel so that it implements Sling Model Exporter (e.g., ComponentExporter or ContainerExporter) and explicitly expose the list of child items using a getter annotated with @JsonProperty.

1. Update the Model
@Model(
    adaptables = Resource.class,
    defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL,
    resourceType = "your/component/resourceType",
    adapters = {MultifieldCollectionModel.class, ComponentExporter.class}
)
public class MultifieldCollectionModel implements ComponentExporter {

    @Self
    private Resource resource;

    private List<MultifieldItem> items;

    @PostConstruct
    protected void init() {
        items = new ArrayList<>();
        Resource childRes = resource.getChild("testList");
        if (childRes != null) {
            childRes.getChildren().forEach(child -> {
                items.add(child.adaptTo(MultifieldItem.class));
            });
        }
    }

    @JsonProperty("testList")
    public List<MultifieldItem> getItems() {
        return items;
    }

    @Override
    public String getExportedType() {
        return resource.getResourceType();
    }
}
2. Create the MultifieldItem Model
@Model(adaptables = Resource.class
public class MultifieldItem {
    
    @ValueMapValue
    private String itemTitle;

    @ValueMapValue
    private String itemDesc;

    public String getItemTitle() {
        return itemTitle;
    }

    public String getItemDesc() {
        return itemDesc;
    }
}
3. HTL Usage (optional)
<sly data-sly-use.model="com.example.MultifieldCollectionModel"
     data-sly-list.item="${model.testList}">
  <div>
    <h3>${item.itemTitle}</h3>
    <p>${item.itemDesc}</p>
  </div>
</sly>
You should then expect the resulting JSON output
{
  ":type": "your/component/resourceType",
  "testList": [
    {
      "itemTitle": "Title 1",
      "itemDesc": "Description 1"
    },
    {
      "itemTitle": "Title 2",
      "itemDesc": "Description 2"
    }
  ]
} 

 

2 replies

SantoshSai
Community Advisor
SantoshSaiCommunity AdvisorAccepted solution
Community Advisor
June 23, 2025

Hi @nageshraja,

You’ll need to update the model MultifieldCollectionModel so that it implements Sling Model Exporter (e.g., ComponentExporter or ContainerExporter) and explicitly expose the list of child items using a getter annotated with @JsonProperty.

1. Update the Model
@Model(
    adaptables = Resource.class,
    defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL,
    resourceType = "your/component/resourceType",
    adapters = {MultifieldCollectionModel.class, ComponentExporter.class}
)
public class MultifieldCollectionModel implements ComponentExporter {

    @Self
    private Resource resource;

    private List<MultifieldItem> items;

    @PostConstruct
    protected void init() {
        items = new ArrayList<>();
        Resource childRes = resource.getChild("testList");
        if (childRes != null) {
            childRes.getChildren().forEach(child -> {
                items.add(child.adaptTo(MultifieldItem.class));
            });
        }
    }

    @JsonProperty("testList")
    public List<MultifieldItem> getItems() {
        return items;
    }

    @Override
    public String getExportedType() {
        return resource.getResourceType();
    }
}
2. Create the MultifieldItem Model
@Model(adaptables = Resource.class
public class MultifieldItem {
    
    @ValueMapValue
    private String itemTitle;

    @ValueMapValue
    private String itemDesc;

    public String getItemTitle() {
        return itemTitle;
    }

    public String getItemDesc() {
        return itemDesc;
    }
}
3. HTL Usage (optional)
<sly data-sly-use.model="com.example.MultifieldCollectionModel"
     data-sly-list.item="${model.testList}">
  <div>
    <h3>${item.itemTitle}</h3>
    <p>${item.itemDesc}</p>
  </div>
</sly>
You should then expect the resulting JSON output
{
  ":type": "your/component/resourceType",
  "testList": [
    {
      "itemTitle": "Title 1",
      "itemDesc": "Description 1"
    },
    {
      "itemTitle": "Title 2",
      "itemDesc": "Description 2"
    }
  ]
} 

 

Santosh Sai
AmitVishwakarma
Community Advisor
Community Advisor
June 24, 2025

Hi @nageshraja ,

Try below solution:

1. Multifield Item Model

package com.project.core.models; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.DefaultInjectionStrategy; import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; import javax.inject.Inject; @Model(adaptables = org.apache.sling.api.resource.Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) public class MultifieldItem { @ValueMapValue private String itemTitle; @ValueMapValue private String itemDesc; public String getItemTitle() { return itemTitle; } public String getItemDesc() { return itemDesc; } }

2. Component Model Exporter Class

package com.project.core.models; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.sling.api.resource.Resource; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.DefaultInjectionStrategy; import org.apache.sling.models.annotations.injectorspecific.Self; import org.apache.sling.models.annotations.Exporter; import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; import org.apache.sling.models.annotations.Default; import org.apache.sling.models.annotations.injectorspecific.ChildResource; import org.apache.sling.models.factory.ModelFactory; import javax.annotation.PostConstruct; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import com.adobe.cq.export.json.ComponentExporter; @Model(adaptables = Resource.class, adapters = { ComponentExporter.class }, resourceType = "project/components/component-a", defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) @Exporter(name = "jackson", extensions = "model.json") public class ComponentAModel implements ComponentExporter { @Self private Resource resource; @Inject @Default(values = "") private String test; @Inject @Default(values = "") private String test1; @Inject @Default(values = "") private String test2; @Inject @Default(values = "") private String test3; @ChildResource(name = "testList") private List<Resource> testListResources; @Inject private ModelFactory modelFactory; private List<MultifieldItem> testList; @PostConstruct protected void init() { testList = new ArrayList<>(); if (testListResources != null) { for (Resource res : testListResources) { MultifieldItem item = modelFactory.createModel(res, MultifieldItem.class); if (item != null) { testList.add(item); } } } } @JsonProperty("test") public String getTest() { return test; } @JsonProperty("test1") public String getTest1() { return test1; } @JsonProperty("test2") public String getTest2() { return test2; } @JsonProperty("test3") public String getTest3() { return test3; } @JsonProperty("testList") public List<MultifieldItem> getTestList() { return testList; } @Override public String getExportedType() { return resource.getResourceType(); } }

 3. HTL

<sly data-sly-use.model="com.project.core.models.ComponentAModel" data-sly-list.item="${model.testList}"> <div class="multi-item"> <h3>${item.itemTitle}</h3> <p>${item.itemDesc}</p> </div> </sly>

Deployment Notes

Multifield Path Structure in CRXDE:

  - Author dialog must store multifield items under testList/ node.

  - Each item should have itemTitle, itemDesc as properties.

  - Example structure in /content:

component-a └── testList ├── item0 │ ├── itemTitle = "Title 1" │ └── itemDesc = "Description 1" └── item1 ├── itemTitle = "Title 2" └── itemDesc = "Description 2"