For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt, and this page is available as Markdown at https://nhanbe.id.vn/aem/backend/servlets.md.
Sling Servlets are Java classes that handle HTTP requests in AEM. They are the standard way to build custom endpoints - REST APIs, form handlers, AJAX callbacks, data sources for dialog dropdowns, and more. Sling's servlet resolution mechanism routes requests to servlets based on resource type or path, making them a natural extension of the content-driven architecture.
Requires a resource with the matching type to exist
Path
Works without a resource, simple URL
Bypasses Sling ACLs, must be explicitly allowed in the Sling Servlet Resolver config
[!-warning] -warning
warning
Path-based servlets bypass JCR access controls. On AEMaaCS, only specific path prefixes are allowed (/bin/). Always prefer resource-type registration unless you have a specific reason to use paths.
Read-only operations (GET endpoints, data sources)
SlingAllMethodsServlet
All of the above + doPost(), doPut(), doDelete()
Write operations (form submissions, API mutations)
[!-success] -success
tip
Always extend SlingSafeMethodsServlet if your servlet only handles GET requests. This makes the read-only intent explicit and prevents accidental POST handling.
DataSource servlets populate dialog dropdowns, selects, and autocomplete fields dynamically from backend data. The result is set as a request attribute (not written to the response).
package com.myproject.core.servlets;import com.adobe.granite.ui.components.ds.DataSource;import com.adobe.granite.ui.components.ds.SimpleDataSource;import com.adobe.granite.ui.components.ds.ValueMapResource;import com.day.cq.commons.jcr.JcrConstants;import org.apache.commons.collections4.iterators.TransformIterator;import org.apache.sling.api.SlingHttpServletRequest;import org.apache.sling.api.SlingHttpServletResponse;import org.apache.sling.api.resource.ResourceMetadata;import org.apache.sling.api.resource.ResourceResolver;import org.apache.sling.api.resource.ValueMap;import org.apache.sling.api.servlets.HttpConstants;import org.apache.sling.api.servlets.SlingSafeMethodsServlet;import org.apache.sling.api.wrappers.ValueMapDecorator;import org.apache.sling.servlets.annotations.SlingServletResourceTypes;import org.osgi.service.component.annotations.Component;import javax.servlet.Servlet;import java.util.*;@Component(service = Servlet.class)@SlingServletResourceTypes( methods = HttpConstants.METHOD_GET, resourceTypes = "/apps/myproject/datasource/categories")public class CategoryDataSourceServlet extends SlingSafeMethodsServlet { @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) { ResourceResolver resolver = request.getResourceResolver(); // Build the list of options (could come from JCR, an API, OSGi config, etc.) List<Map.Entry<String, String>> options = new ArrayList<>(); options.add(Map.entry("news", "News")); options.add(Map.entry("blog", "Blog")); options.add(Map.entry("product", "Product")); options.add(Map.entry("event", "Event")); // Convert to a DataSource DataSource dataSource = new SimpleDataSource( new TransformIterator<>(options.iterator(), entry -> { ValueMap vm = new ValueMapDecorator(new HashMap<>()); vm.put("value", entry.getKey()); vm.put("text", entry.getValue()); return new ValueMapResource( resolver, new ResourceMetadata(), JcrConstants.NT_UNSTRUCTURED, vm ); }) ); // Set on the request - NOT the response request.setAttribute(DataSource.class.getName(), dataSource); }}
[!-info] -info
info
The DataSource is set as a request attribute, not written to the response body. The Granite UI framework reads the attribute and renders the dropdown options automatically.
# Local SDK / dev only - never ship admin:admin credentials against a real environment.# 1. Authenticate and capture the cookiecurl -u admin:admin -c cookies.txt http://localhost:4502/libs/granite/core/content/login.html# 2. Use the cookie for the POST requestcurl -b cookies.txt \ -X POST \ -d "name=John&[email protected]&message=Hello" \ http://localhost:4502/content/myproject/en/contact/jcr:content/root/container/form.submit.json
By default, Dispatcher caches GET responses. For servlets that return dynamic data, you need to either disable caching or configure appropriate cache rules.
On AEMaaCS, path-based servlets are restricted to specific prefixes (/bin/). Even on AEM 6.5, prefer resource-type registration. If you must use a path, configure the Sling Servlet Resolver to allow it: