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

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

  • June 23, 2025
  • 2 replies
  • 458 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

 

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

AmitVishwakarma
New Participant
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"
SantoshSai
SantoshSaiAccepted solution
New Participant
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