Create a Sling Model for the component

[AEM Forms as a Cloud Service]{class="badge informative"}

A Sling Model in AEM is a Java-based framework used to simplify the development of back-end logic for components. It allows developers to map data from AEM resources (JCR nodes) to Java objects using annotations, providing a clean and efficient way to handle dynamic data for components.
This class, CountriesDropDownImpl, is an implementation of the CountriesDropDown interface in an AEM (Adobe Experience Manager) project. It powers a dropdown component where users can select a country based on their selected continent. The dropdown data is dynamically loaded from a JSON file stored in the AEM DAM (Digital Asset Manager).

Fields in the Class

  • multiSelect: Indicates whether the dropdown allows multiple selections.
    Injected from the component properties using @ValueMapValue with a default value of false.
  • request: Represents the current HTTP request. Useful for accessing context-specific information.
  • continent: Stores the selected continent for the dropdown (e.g., “asia”, “europe”).
    Injected from the component’s property dialog, with a default value of “asia” if none is provided.
  • resourceResolver:Used to access and manipulate resources in the AEM repository.
  • jsonData: A JSONObject that stores the parsed data from the JSON file corresponding to the selected continent.

Methods in the Class

  • getContinent() A simple method to return the value of the continent field.
    Logs the value being returned for debugging purposes.
  • init() Lifecycle method annotated with @PostConstruct, executed after the class is constructed and dependencies are injected.Dynamically constructs the path to the JSON file based on the continent value.
    Fetches the JSON file from the AEM DAM using the resourceResolver.
    Adapts the file to an Asset, reads its content, and parses it into a JSONObject.
    Logs any errors or warnings during this process.
  • getEnums() Retrieves all the keys (country codes) from the parsed JSON data.
    Sorts the keys alphabetically and returns them as an array.
    Logs the number of country codes being returned.
  • getEnumNames() Extracts all country names from the parsed JSON data.
    Sorts the names alphabetically and returns them as an array.
    Logs the total number of countries and each retrieved country name.
  • isMultiSelect() Returns the value of the multiSelect field to indicate whether the dropdown allows multiple selections.
package com.aem.customcorecomponent.core.models.impl;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.forms.core.components.internal.form.ReservedProperties;
import com.adobe.cq.forms.core.components.util.AbstractOptionsFieldImpl;
import com.aem.customcorecomponent.core.models.CountriesDropDown;
import com.day.cq.dam.api.Asset;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Default;
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.ValueMapValue;
import org.json.JSONObject;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

//@Model(adaptables = SlingHttpServletRequest.class,adapters = CountriesDropDown.class,defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)

@Model(
        adaptables = { SlingHttpServletRequest.class, Resource.class },
        adapters = { CountriesDropDown.class,
                ComponentExporter.class },
        resourceType = { "corecomponent/components/adaptiveForm/countries" })
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)

public class CountriesDropDownImpl extends AbstractOptionsFieldImpl implements CountriesDropDown {
    @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.PN_MULTISELECT)
    @Default(booleanValues = false)
    protected boolean multiSelect;

    private static final Logger logger = LoggerFactory.getLogger(CountriesDropDownImpl.class);
    @Inject
    SlingHttpServletRequest request;

    @Inject
    @Default(values = "asia")
    public String continent;
    @Inject
    private ResourceResolver resourceResolver;
    private JSONObject jsonData;
    public String getContinent()
    {
        logger.info("Returning continent");
        return continent;
    }
    @PostConstruct
    public void init() {

        String jsonPath = "/content/dam/corecomponent/" + getContinent() + ".json"; // Update path as needed
        logger.info("Initializing JSON data for continent: {}", getContinent());

        try {
            // Fetch the JSON resource
            Resource jsonResource = resourceResolver.getResource(jsonPath);
            if (jsonResource != null) {
                // Adapt the resource to an Asset
                Asset asset = jsonResource.adaptTo(Asset.class);
                if (asset != null) {
                    // Get the original rendition and parse it as JSON
                    try (InputStream inputStream = asset.getOriginal().adaptTo(InputStream.class);
                         BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {

                        String jsonString = reader.lines().collect(Collectors.joining());
                        jsonData = new JSONObject(jsonString);
                        logger.info("Successfully loaded JSON data for path: {}", jsonPath);
                    }
                } else {
                    logger.warn("Failed to adapt resource to Asset at path: {}", jsonPath);
                }
            } else {
                logger.warn("Resource not found at path: {}", jsonPath);
            }
        } catch (Exception e) {
            logger.error("An error occurred while initializing JSON data for path: {}", jsonPath, e);
        }
    }

    @Override
    public Object[] getEnums() {
        Set<String> keySet = jsonData.keySet();


// Convert the set of keys to a sorted array
        String[] countryCodes = keySet.toArray(new String[0]);
        Arrays.sort(countryCodes);

        logger.debug("Returning sorted country codes: " + countryCodes.length);

        return countryCodes;


    }

    @Override
    public String[] getEnumNames() {
        String[] countries = new String[jsonData.keySet().size()];
        logger.info("Fetching countries - Total number: " + countries.length);

// Populate the array with country names
        int index = 0;
        for (String code : jsonData.keySet()) {
            String country = jsonData.getString(code);
            logger.debug("Retrieved country: " + country);
            countries[index++] = country;
        }

// Sort the array alphabetically
        Arrays.sort(countries);
        logger.debug("Returning " + countries.length + " sorted countries");

        return countries;

    }

    @Override
    public Boolean isMultiSelect() {
        return multiSelect;
    }
}

Next Steps

Build,Deploy and Test

recommendation-more-help
4859a77c-7971-4ac9-8f5c-4260823c6f69