Comprehensive AEM Interview Guide

Advanced Edition with Detailed Questions, Answers & Code Examples

Enhanced by: Ayush Kumar (Adobe Certified Full Stack & AEM Developer)

📋 Table of Contents

🏗️ AEM Overview & Architecture
Q1: Explain AEM Architecture and its key components with the request flow.

AEM Architecture consists of:

  • Author Instance: Content creation and management environment
  • Publish Instance: Live environment serving content to end users
  • Dispatcher: Apache module for caching, load balancing, and security
  • JCR (Java Content Repository): Content storage based on JSR-170
  • Sling Framework: RESTful web framework built on OSGi
  • OSGi Container: Modular runtime environment
Request Flow:
Client → Dispatcher → Publish/Author → Sling → JCR → Component → Response
Q2: What is the difference between CRX and Oak in AEM?

CRX (Content Repository Extreme):

  • Adobe's implementation of JCR specification
  • Used in AEM 5.x and early 6.x versions
  • Based on Apache Jackrabbit

Oak:

  • Next-generation content repository
  • Used in AEM 6.0+ versions
  • Better performance, scalability, and MongoDB support
  • Supports multiple storage backends (Segment, Document)
🧩 Components Deep Dive
Q3: Create a custom AEM component with dialog and explain the structure.

A complete AEM component consists of:

Component Structure:
/apps/myproject/components/content/hero/
├── .content.xml           # Component definition
├── cq:dialog/             # Touch UI dialog
├── hero.html              # HTL rendering script
├── hero.js                # Client-side JavaScript
├── hero.css               # Component styles
└── HeroModel.java         # Sling Model (if needed)
.content.xml - Component Definition:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0"
          xmlns:jcr="http://www.jcp.org/jcr/1.0"
          xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
    jcr:primaryType="cq:Component"
    jcr:title="Hero Component"
    jcr:description="A responsive hero banner component"
    componentGroup="MyProject - Content"
    sling:resourceSuperType="core/wcm/components/commons/v1/datalayer"/>
cq:dialog/.content.xml - Touch UI Dialog:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
          xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
          xmlns:cq="http://www.day.com/jcr/cq/1.0"
          xmlns:jcr="http://www.jcp.org/jcr/1.0"
          xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured"
    jcr:title="Hero Configuration"
    sling:resourceType="cq/gui/components/authoring/dialog"
    extraClientlibs="[myproject.author]"
    helpPath="en/docs/myproject/hero">
    <content jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/container">
        <items jcr:primaryType="nt:unstructured">
            <tabs jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/tabs"
                maximized="{Boolean}true">
                <items jcr:primaryType="nt:unstructured">
                    <content jcr:primaryType="nt:unstructured"
                        jcr:title="Content"
                        sling:resourceType="granite/ui/components/coral/foundation/container"
                        margin="{Boolean}true">
                        <items jcr:primaryType="nt:unstructured">
                            <title jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                fieldLabel="Title"
                                name="./title"
                                required="{Boolean}true"/>
                            <subtitle jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                fieldLabel="Subtitle"
                                name="./subtitle"/>
                            <description jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
                                fieldLabel="Description"
                                name="./description"
                                rows="5"/>
                            <image jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
                                fieldLabel="Background Image"
                                name="./image"
                                rootPath="/content/dam/myproject"/>
                            <ctaText jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                fieldLabel="CTA Text"
                                name="./ctaText"/>
                            <ctaLink jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
                                fieldLabel="CTA Link"
                                name="./ctaLink"
                                rootPath="/content/myproject"/>
                        </items>
                    </content>
                    <styling jcr:primaryType="nt:unstructured"
                        jcr:title="Styling"
                        sling:resourceType="granite/ui/components/coral/foundation/container"
                        margin="{Boolean}true">
                        <items jcr:primaryType="nt:unstructured">
                            <theme jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/select"
                                fieldLabel="Theme"
                                name="./theme">
                                <items jcr:primaryType="nt:unstructured">
                                    <light jcr:primaryType="nt:unstructured"
                                        text="Light"
                                        value="light"/>
                                    <dark jcr:primaryType="nt:unstructured"
                                        text="Dark"
                                        value="dark"/>
                                </items>
                            </theme>
                        </items>
                    </styling>
                </items>
            </tabs>
        </items>
    </content>
</jcr:root>
hero.html - HTL Template:
<div data-sly-use.hero="com.myproject.core.models.HeroModel"
     data-sly-test="${hero.title}"
     class="hero hero--${hero.theme @ context='styleToken'}"
     style="background-image: url('${hero.backgroundImage}');">
     
    <div class="hero__overlay"></div>
    
    <div class="hero__content">
        <h1 class="hero__title">${hero.title}</h1>
        
        <h2 data-sly-test="${hero.subtitle}" 
            class="hero__subtitle">${hero.subtitle}</h2>
        
        <p data-sly-test="${hero.description}" 
           class="hero__description">${hero.description @ context='html'}</p>
        
        <a data-sly-test="${hero.ctaText && hero.ctaLink}"
           href="${hero.ctaLink @ extension='html'}"
           class="hero__cta btn btn--primary">${hero.ctaText}</a>
    </div>
</div>
Q4: Explain Core Components and how to extend them.

Core Components are pre-built, well-tested components that follow best practices:

Benefits:
  • SEO optimized and accessible
  • Regular updates and bug fixes
  • Consistent styling via Style System
  • JSON export capability for headless
Extending Core Components - Text Component:
<!-- Custom Text Component -->
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0"
          xmlns:jcr="http://www.jcp.org/jcr/1.0"
          xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
    jcr:primaryType="cq:Component"
    jcr:title="Enhanced Text"
    jcr:description="Extended text component with animation"
    componentGroup="MyProject - Enhanced"
    sling:resourceSuperType="core/wcm/components/text/v2/text"/>
🎯 Sling Models
Q5: Create a comprehensive Sling Model with different injection types and explain each annotation.
HeroModel.java - Complete Sling Model:
package com.myproject.core.models;

import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap;
import com.day.cq.commons.inherit.InheritanceValueMap;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import org.apache.commons.lang3.StringUtils;
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.*;
import org.apache.sling.models.annotations.injectorspecific.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Calendar;
import java.util.Optional;

@Model(
    adaptables = {SlingHttpServletRequest.class, Resource.class},
    adapters = {HeroModel.class, ComponentExporter.class},
    resourceType = HeroModel.RESOURCE_TYPE,
    defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.JSON)
public class HeroModel implements ComponentExporter {

    static final String RESOURCE_TYPE = "myproject/components/content/hero";
    private static final Logger LOG = LoggerFactory.getLogger(HeroModel.class);

    // Basic property injection from current resource
    @ValueMapValue
    @Default(values = "Welcome")
    private String title;

    @ValueMapValue
    private String subtitle;

    @ValueMapValue
    private String description;

    @ValueMapValue
    @Named("ctaText")
    private String callToActionText;

    @ValueMapValue
    @Named("ctaLink")
    private String callToActionLink;

    @ValueMapValue
    @Default(values = "light")
    private String theme;

    @ValueMapValue
    private String image;

    // Request injection
    @SlingObject
    private SlingHttpServletRequest request;

    // Resource injection
    @SlingObject
    private Resource currentResource;

    @SlingObject
    private ResourceResolver resourceResolver;

    // Service injection
    @OSGiService
    private PageManager pageManager;

    // Custom injection with source
    @Inject
    @Source("script-bindings")
    @Named("currentPage")
    private Page currentPage;

    // Child resource injection
    @ChildResource
    @Named("settings")
    private Resource settingsResource;

    // Request attribute injection
    @RequestAttribute
    @Named("analytics")
    private String analyticsData;

    // Computed properties
    private String backgroundImage;
    private boolean hasContent;
    private InheritanceValueMap inheritedProperties;

    @PostConstruct
    protected void init() {
        LOG.debug("Initializing HeroModel for resource: {}", currentResource.getPath());
        
        // Initialize inheritance value map for property inheritance
        inheritedProperties = new HierarchyNodeInheritanceValueMap(currentResource);
        
        // Process background image
        processBackgroundImage();
        
        // Check if component has meaningful content
        hasContent = StringUtils.isNotBlank(title) || StringUtils.isNotBlank(description);
        
        LOG.debug("HeroModel initialized. Has content: {}", hasContent);
    }

    private void processBackgroundImage() {
        if (StringUtils.isNotBlank(image)) {
            // Generate responsive image URL with renditions
            backgroundImage = image + ".transform/hero-large/image.jpg";
        } else {
            // Fallback to inherited property or default
            String inheritedImage = inheritedProperties.getInherited("defaultHeroImage", String.class);
            backgroundImage = Optional.ofNullable(inheritedImage)
                .orElse("/content/dam/myproject/defaults/hero-placeholder.jpg");
        }
    }

    // Getter methods with additional logic
    public String getTitle() {
        return title;
    }

    public String getSubtitle() {
        return subtitle;
    }

    public String getDescription() {
        return description;
    }

    public String getCallToActionText() {
        return callToActionText;
    }

    public String getCallToActionLink() {
        // Process internal links
        if (StringUtils.isNotBlank(callToActionLink) && callToActionLink.startsWith("/content/")) {
            Page linkedPage = pageManager.getPage(callToActionLink);
            if (linkedPage != null) {
                return linkedPage.getPath() + ".html";
            }
        }
        return callToActionLink;
    }

    public String getTheme() {
        return theme;
    }

    public String getBackgroundImage() {
        return backgroundImage;
    }

    public boolean isHasContent() {
        return hasContent;
    }

    // Additional computed properties
    public String getPageTitle() {
        return currentPage != null ? currentPage.getTitle() : "";
    }

    public String getLastModified() {
        Calendar lastModified = currentResource.getValueMap().get("jcr:lastModified", Calendar.class);
        return lastModified != null ? lastModified.getTime().toString() : "";
    }

    public boolean isAuthorMode() {
        return request != null && "author".equals(request.getRequestPathInfo().getSelectors());
    }

    // JSON Export support
    @Override
    public String getExportedType() {
        return RESOURCE_TYPE;
    }
}
Key Annotations Explained:
  • @Model - Defines the class as a Sling Model
  • @ValueMapValue - Injects properties from resource's ValueMap
  • @SlingObject - Injects Sling objects (request, resource, etc.)
  • @OSGiService - Injects OSGi services
  • @ChildResource - Injects child resources
  • @PostConstruct - Method called after injection is complete
  • @Default - Provides default values
  • @Named - Maps to different property names
Q6: How do you test Sling Models? Provide a complete unit test.
HeroModelTest.java - JUnit Test:
package com.myproject.core.models;

import com.adobe.cq.wcm.api.PageManager;
import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;
import org.apache.sling.api.resource.Resource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;

@ExtendWith({AemContextExtension.class, MockitoExtension.class})
class HeroModelTest {

    private final AemContext context = new AemContext();

    @Mock
    private PageManager pageManager;

    private HeroModel heroModel;

    @BeforeEach
    void setUp() {
        // Register the PageManager service
        context.registerService(PageManager.class, pageManager);
        
        // Load test content
        context.load().json("/com/myproject/core/models/HeroModelTest.json", "/content");
        
        // Create current page
        context.currentPage("/content/myproject/homepage");
        
        // Get the hero resource
        Resource heroResource = context.resourceResolver()
            .getResource("/content/myproject/homepage/jcr:content/hero");
        
        // Adapt to model
        heroModel = heroResource.adaptTo(HeroModel.class);
    }

    @Test
    void testBasicProperties() {
        assertNotNull(heroModel);
        assertEquals("Welcome to Our Site", heroModel.getTitle());
        assertEquals("Your journey starts here", heroModel.getSubtitle());
        assertEquals("light", heroModel.getTheme());
        assertTrue(heroModel.isHasContent());
    }

    @Test
    void testDefaultValues() {
        Resource emptyResource = context.create().resource("/content/test/empty");
        HeroModel emptyModel = emptyResource.adaptTo(HeroModel.class);
        
        assertEquals("Welcome", emptyModel.getTitle());
        assertEquals("light", emptyModel.getTheme());
    }

    @Test
    void testCTALinkProcessing() {
🔌 Servlets in AEM
Q: How do you create a custom servlet in AEM?
AEM Servlets are created using the `@SlingServletResourceTypes`, `@SlingServletPaths`, or `@SlingServletExtensions` annotations. They respond to HTTP requests mapped via resource types, paths, or selectors.
🧠 OSGi Services
Q: What is OSGi and how is it used in AEM?
OSGi is a Java framework for modular application development. AEM uses OSGi to manage components and services dynamically at runtime.
📐 Templates & Policies
Q: Difference between static and editable templates?
Static templates are defined by developers and cannot be modified by authors. Editable templates allow authors to configure layouts and components directly in the UI.
🔄 Workflows
Q: How do workflows help in AEM?
Workflows automate processes like content approval, publishing, and asset management using AEM’s workflow engine.
📄 Content/Experience Fragments
Q: What is the difference between Content Fragment and Experience Fragment?
Content Fragments are structured content without layout, used for headless delivery. Experience Fragments include layout and are used for personalized experiences.
🔍 GraphQL & Headless
Q: How is GraphQL used in AEM?
AEM provides GraphQL APIs to query Content Fragments, allowing structured, efficient headless delivery of content.
🌐 REST APIs
Q: How do you expose REST endpoints in AEM?
Custom servlets or Sling Models annotated with exporters can expose JSON or XML endpoints.
⚛️ SPA Integration
Q: How is SPA integration handled in AEM?
AEM uses SPA Editor and client-side frameworks like React/Angular to create Single Page Applications with in-context editing.
🔒 Security & Performance
Q: What are best practices for securing an AEM application?
Use dispatcher filters, secure permissions, close unnecessary ports, and sanitize user inputs. Also enable SSL, CSRF protection, and authentication tokens.