Article summary


Discusses how to create an AEM 6.3 adaptive form and post the data to a custom service defined within an OSGi bundle. The custom service uses the Java JDBC API to persist the form data into MySQL.

This article uses DS Annotations as opposed to Felix SRC annotations. 

A special thank you to Ratna Kumar Kotla, a member of the AEM community, for testing this article and ensuring it works. 

Digital Marketing Solution(s) Adobe Experience Manager Forms 
Developer (intermediate)
Required Skills
Java, OSGi, Maven
Tested On  Adobe Experience Manager 6.3


You can create an Adobe Experience Manager (AEM) 6.3 form and submit the data to a custom AEM service. The custom service uses the Java JDBC API to persist data into a relational database.  Although an Adaptive Form does let you configure a data model to submit data to a relational database, by creating a custom service, you can fully control how the data is submitted to MySQL. For example, you can perform additional operations by using Java logic prior to updating a database. Another task that you can perform is to update multiple tables in the database with different parts of the same form. 

Te following form represents the form that is created in this article. 

An AEM 6.3 form persisting data into MySQL

When an end user fills out the AEM form and clicks the Submit button, the data is submitted to a custom service defined within an OSGi bundle. The service uses the Java JDBC API to persist the data into MySQL. For information, see Package java.sql

This development article walks you through how to create an AEM 6.3 form and submit the data to an AEM service. The OSGi bundle is created by using an Adobe Maven Archetype 12 project.


For information about using a Form Data Model, see Create form data model.

Here is another Forms example, Sample for integrating drafts & submissions component with database.

Setup the MySQL Database

The first step is to setup a MySQL table. In this article, the MySQL database contains a single table named customerdetails. The following describes this table. 

Field Name Field Type Key
id An integer that specifies the customer identifier value PK
name A string value that specifies the customer’s name  
shipping A string value that specifies the customer’s shipping address  
state A string value that specifies the customer’s state  
zipcode A string value that specifies the customer’s zip code  

The following illustration shows this table within MySQL Workbench. 

A MySQL table named customerdetails


Before following along with this development article, setup MySQL and create a database schema named sooners that contains the customerdetails  table. See

Configure MySQL database as a data source

Perform these steps: 

1. Go to AEM web console at http://localhost:4502/system/console/configMgr.

2. Locate Apache Sling Connection Pooled DataSource configuration. Click to open the configuration in edit mode.

3, In the configuration dialog, specify the following details:

  • Datasource name: You can specify any name. For example, specify WeRetailMySQL
  • DataSource service property name: Specify the name of the service property containing the DataSource name. It is specified while registering the data source instance as OSGi service. For example,
  • JDBC driver class: Specify Java class name of the JDBC driver. For MySQL database, specify com.mysql.jdbc.Driver
  • JDBC connection URI: Specify connection URL of the database. For MySQL database running on port 3306 and schema weretail, the URL is: jdbc:mysql://[server]:3306/sooners
  • Username: Username of the database. It is required to enable JDBC driver to establish a connection with the database.
  • Password: Password of the database. It is required to enable JDBC driver to establish a connection with the database.

Leave other properties with default values and click Save. The following illustration shows an example configuration. 

An AEM database configuration

Author an AEM adaptive customer form

To create an adaptive form, perform these steps:

1. Log in to the AEM author instance and navigate to Adobe Experience Manager > Forms > Forms & Documents. The default URL is http://localhost:4502/aem/forms.html/content/dam/formsanddocuments.

2. Click Create and select Adaptive Form. An option to select a template appears. Click the Blank template to select it and click Next.

3. An option to Add Properties appears. The Title and Name fields are mandatory:

  • Title: Specify Add new or update shipping address in the Title field. The title field specifies the display name of the form. The title helps you identify the form in the AEM Forms user interface.
  • Name: Specify shipping-address-add-update-form in the Name field. The Name field specifies the name of the form. A node with the specified name is created in the repository. As you start typing a title, value for the name field is automatically generated. You can change the suggested value. The name field can include only alphanumeric characters, hyphens, and underscores. All the invalid inputs are replaced with a hyphen.

4. Click Create. An adaptive form is created and a dialog to open the form for editing appears. Click  Open to open the newly created form in a new tab. The form opens for editing. It also displays the sidebar to customize the newly created form according to the needs.


A new adaptive form

Add header and footer

AEM Forms provides many components to display information on an adaptive form. Header and Footer components help provide a consistent look and feel to a form. A header typically includes the logo of a corporation, the title of the form, and summary. A footer typically includes copyright information and links to other pages. 

Perform these steps:

1. Click the Side Panel Toggle button and then the component button. The component browser opens. Drag the Header component from component browser to the adaptive form.

2. Click Image. The toolbar appears. Click  . The properties browser opens on the left of the screen. Browse and upload the logo image. Click . The image appears on the header.

3. Drag the Footer component from  to the adaptive form. At this stage, the form looks like the following:  

An adaptive form with a header and footer

Add components to the adaptive form

Components are building blocks of an adaptive form. AEM Forms provides many components to capture and display information in an adaptive form. You can drag the components from  to a form. Perform these steps: 

1. Drag the Numeric Box component to the adaptive form. Place it before the footer component. Open properties of the component, change Title of the component to Customer ID, change Element Name to customer_ID, enable the Required Field option, enable the Use HTML5 Number Input Type option, and click .

2. Drag three Text Box components to the adaptive form. Place these before the footer component. Set the following properties for these text boxes.

Property Text Box 1 Text Box 2 Text Box 3
Title Name Shipping Address State
Element Name customer_Name customer_Shipping_Address customer_State
Required Field Enabled Enabled Enabled
Allow multiple lines Disabled Enabled Disabled

3. Drag a Numeric Box component before the footer component. Open properties of the component, set values listed in the below table, click .

Property Value
Title ZIP Code
Element Name customer_ZIPCode
Maximum Number of Digits 6
Required Field Enabled
Display Pattern Type No Pattern

4. Drag an Email component before the footer component. Open properties of the component, set values listed in the below table, and tap .

Property Value
Title Email
Element Name customer_Email
Required Field Enabled

5. Drag a Submit Button component to the adaptive form. Place it before the footer component. Open properties of the component, change Element Name to address_addition_update_submit. Click . The layout of the form is complete and the form looks like the following:

An adaptive form

Create an Experience Manager 12 archetype project

You can create an Experience Manager archetype project by using the Maven archetype plugin. In this example, assume that the working directory is C:\AdobeCQ. 

An Experience Manager Maven Archetype 12 project

To create an Experience Manager archetype project, perform these steps:

1. Open the command prompt and go to your working directory (for example, C:\AdobeCQ).

2. Run the following Maven command:

mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeGroupId=com.adobe.granite.archetypes -DarchetypeArtifactId=aem-project-archetype -DarchetypeVersion=12 -DarchetypeCatalog=

3. When prompted, specify the following information:

  • groupId - HandleForm
  • artifactId - HandleForm
  • version - 1.0-SNAPSHOT
  • package - com.aem.form
  • appsFolderName - HandleForm
  • artifactName - HandleForm
  • componentGroupName - HandleForm
  • contentFolderName - HandleForm
  • cssId - HandleForm
  • packageGroup - HandleForm
  • siteName -HandleForm

4. When prompted, specify Y.

5. Once done, you will see a message like:

[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:42 min
[INFO] Finished at: 2016-04-25T14:34:19-04:00
[INFO] Final Memory: 16M/463M
[INFO] ------------------------------------------------------------------------

6. Change the working directory to HandleForm and then enter the following command.

mvn eclipse:eclipse

After you run this command, you can import the project into Eclipse as discussed in the next section.


If you have not setup Maven, see this article Creating an Adobe Experience Manager 6.4 Project using Adobe Maven Archetype 13.

Add Java files to the Maven project using Eclipse 

To make it easier to work with the Maven generated project, import it into the Eclipse development environment, as shown in the following illustration.

Eclipse Import Project Dialog


Do not worry about the errors reported in Eclipse. It does not read the POM file where the APIs are resolved. You build the bundle with Maven. Eclipse is used to edit the Java files and the POM file.

The next step is to add two Java files to the com.aem.form.core package:

  • HandleForm- a Java interface that exposes the method used in the service
  • HandleFormImp - the implementation class that implements HandleForm



The HandleForm interface defines the method exposes by the custom AEM Service that uses Java Mail API to send an email message. The following Java code represents this interface. 

package com.aem.form.core;

public interface HandleForm {
	public void injestFormDataDB(String customer_ID, String customer_Name, String customer_Shipping_Address, String customer_State, String customer_ZIPCode, String customer_Email); 



The HandleFormImp class implements HandleForm and defines the implementation logic for the interface. This class uses the Java JDBC API and also references the DataSourcePool that was configured earlier in this development article. The Java application logic persists the form data into the customerdetails table.   

The following Java code represents this class. 

package com.aem.form.core;

import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Properties;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

//Add the DataSourcePool package
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
import javax.sql.DataSource;

public class HandleFormImp implements HandleForm{
	/** Default log. */
    protected final Logger log = LoggerFactory.getLogger(this.getClass());
    private DataSourcePool source;
    //Inject the Form Data into a database! 
    public void injestFormDataDB(String customer_ID, String customer_Name, String customer_Shipping_Address, String customer_State, String customer_ZIPCode, String customer_Email)
    	//Simply write out the values that are posted from the AEM form to the AEM log file"DB Data posted from an AEM adaptive form - customer_ID: "+customer_ID +" customer_Name: "+customer_Name +" customer_Shipping_Address: "+customer_Shipping_Address +" customer_State "+customer_State) ;
        Connection c = null;
        int rowCount= 0; 
        try {
              // Create a Connection object
              c =  getConnection();
               ResultSet rs = null;
               Statement s = c.createStatement();
               Statement scount = c.createStatement();
               //Use prepared statements to protected against SQL injection attacks
               PreparedStatement pstmt = null;
               PreparedStatement ps = null; 
               int pk = Integer.parseInt(customer_ID);	
               int intZIP =Integer.parseInt(customer_ZIPCode);	
     "****** THe PK IS is "+pk); 
               String insert = "INSERT INTO customerdetails(id, name,shipping, email, state, zipcode) VALUES(?, ?,?,?,?,?);";
               ps = c.prepareStatement(insert);
               ps.setString(2, customer_Name);
               ps.setString(3, customer_Email);
               ps.setString(4, customer_Shipping_Address);
               ps.setString(5, customer_State);
               ps.setInt(6, intZIP);
        catch (Exception e) {
        finally {
            catch (SQLException e) {

  //Returns a connection using the configured DataSourcePool 
    private Connection getConnection()
             DataSource dataSource = null;
             Connection con = null;
                 //Inject the DataSourcePool right here! 
                 dataSource = (DataSource) source.getDataSource("WeRetailMySQL");
                 con = dataSource.getConnection();
                 return con;
             catch (Exception e)
                 return null; 

Modify the Maven POM file

Add the following POM dependency to the POM file located at C:\AdobeCQ\HandleForm.

               <!-- for AEM6.1 use this version     : <version>6.1.0</version> -->
               <!-- for AEM6.1 SP1 use this version : <version>6.1.0-SP1-B0001</version> -->
               <!-- for AEM6.1 SP2 use this version : <version>6.1.0-SP2</version> -->
               <!-- for AEM6.2 use this version     : <version>6.2.0</version> -->

When you add new Java classes under core, you need to modify a POM file to successfully build the OSGi bundle. You modify the POM file located at C:\AdobeCQ\HandleForm\core. The following code represents this POM file.

<?xml version="1.0" encoding="UTF-8"?>
 |  Copyright 2017 Adobe Systems Incorporated
 |  Licensed under the Apache License, Version 2.0 (the "License");
 |  you may not use this file except in compliance with the License.
 |  You may obtain a copy of the License at
 |  Unless required by applicable law or agreed to in writing, software
 |  distributed under the License is distributed on an "AS IS" BASIS,
 |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 |  See the License for the specific language governing permissions and
 |  limitations under the License.
<project xmlns="" xmlns:xsi=""
    <name>HandleForm - Core</name>
    <description>Core bundle for HandleForm</description>
                        <!-- Import any version of javax.inject, to allow running on multiple versions of AEM -->

        <!-- OSGi Dependencies -->
        <!-- Other Dependencies -->

Build the OSGi bundle using Maven

To build the OSGi bundle by using Maven, perform these steps:

  1. Open the command prompt and go to the C:\AdobeCQ\HandleForm.
  2. Run the following maven command: mvn -PautoInstallPackage install.
  3. The OSGi component can be found in the following folder: C:\AdobeCQ\HandleForm\core\target. The file name of the OSGi component is HandleForm.core-1.0-SNAPSHOT.jar.

The command -PautoInstallPackage automatically deploys the OSGi bundle to AEM.

Add the MySQL driver file to Experience Manager

You have to deploy a bundle to Experience Manager that contains the database driver file. In this development article, the name of the database driver file is mysql-connector-java-5.1.22-bin. To create an OSGi bundle that contains this database driver file, perform these tasks:

1. Start Eclipse (Indigo). The steps below have been tested on Eclipse Java EE IDE for Web Developers version Indigo Service Release 1.

2. Select File, New, Other.

3. Under the Plug-in Development folder, choose Plug-in from Existing JAR Archives. Name your project jdbcBundle.

4. In the JAR selection dialog, click the Add external button, and browse to the database driver file.
Click Next.

5. In the Plug-in Project properties dialog, ensure that you check the checkbox for Analyze library contents and add dependencies.

6. Make sure that the Target Platform is the standard OSGi framework.

7. Ensure the checkboxes for Unzip the JAR archives into the project and Update references to the JAR files are both checked.

8. Click Next, and then Finish.

9. Click the Runtime tab.

10. Make sure that the Exported Packages list is populated.

11. Make sure packages have been added under the Export-Package header in MANIFEST.MF. Remove the version information in the MANIFEST.MF file. Version numbers can cause conflicts when you upload the OSGi bundle.

12. Also make sure that the Import-Package header in MANIFEST.MF is also populated.

13. Save the project.

14. Build the OSGi bundle by right-clicking the project in the left pane, choose Export, Plug-in Development, Deployable plug-ins and fragments, and click Next.

15. Select a location for the export (C:\TEMP) and click Finish. (Ignore any error messages).
In C:\TEMP\plugins, you should now find the OSGi bundle.

16. Login to the Apache Felix Web Console at http://server:port/system/console/bundles (default admin user = admin with password= admin).

17. Sort the bundle list by Id and note the Id of the last bundle.

18. Click the Install/Update button.

19. Check the Start Bundle checkbox.

20. Browse to the bundle JAR file you just built. (C:\TEMP\plugins).

21. Click Install.

22. Click the Refresh Packages button.

23. Check the bundle with the highest Id.

24. Your new bundle should now be listed with the status Active.

25. If the status is not Active, check the error.log for exceptions. If you get “org.osgi.framework.BundleException: Unresolved constraint” errors, check the MANIFEST.MF for strict version requirements which might follow: javax.xml.namespace; version=”3.1.0”

26. If the version requirement causes problems, remove it so that the entry looks like this: javax.xml.namespace.

27. If the entry is not required, remove it entirely.

28. Rebuild the bundle.

29. Delete the previous bundle and deploy the new one.


If you do not deploy a bundle that contains the MySQL driver file, you will not be successful at persisting data submitted from an Adaptive form into MySQL. 

View the Active OSGi bundle

After you deploy the OSGi bundle, you can see it in the Apache Felix Web Console.

OSGi bundle

View your OSGi bundle by performing these steps:

  1. Login to Adobe Apache Felix Web Console at http://server:port/system/console/bundles (default admin user = admin with password= admin).
  2. Click the Bundles tab, sort the bundle list by Id, and note the Id of the last bundle.

Create a custom submit action for the customer form

Create a custom submit action for the customer form. To create a custom submit action, you setup nodes and properties within the AEM repository. In addition, you define a JSP file named post.POST.jsp. When the user fills out the form and clicks the submit button, form data is posted to the post.POST.jsp. This JSP captures the submitted data and passes the data to a custom service defined within an OSGi bundle.

Perform these steps: 

1. Log in to CRXDE Lite at http://{server}:{port}/crx/de/index.jsp. Create a node with the property sling:Folder with the name invoke_service in the /apps/custom_submit_action folder. Create the custom_submit_action folder if it does not exist.


A custom submit action folder

2. Make the Action available in Adaptive Form Edit Dialog by adding the following properties in the invoke_service node:

  • guideComponentType of type String and value fd/af/components/guidesubmittype
  • guideDataModel of type String and value xfa,xsd,basic
  • jcr:description of type String and value Invoke Service (this is the value that shows up in the GUI)

3. Open the Customer Adaptive Form and click the Adaptive Form Container, as shown in this illustration (you have to click on the outside of the adaptive form - see blue line below).

Click the adaptive form container

4. Click the wrench icon.

5. From the Adaptive Form container that appears in the left column, select Submission. Then from the Submit Action, select Invoke Service (the custom submit action). 

Select the custom submit action

8. Add post.POST.jsp file in your action by adding this JSP file to /apps/custom_submit_action/invoke_service/. When data is submitted from the adaptive form, it is posted to this JSP file. Add the following code to this JSP file.

<%@include file="/libs/fd/af/components/guidesglobal.jsp" %>
<%@include file="/libs/foundation/global.jsp"%>
<%@page import=",
   " %>
<%@taglib prefix="sling"
                uri="" %>
<%@taglib prefix="cq"
    String customer_ID = request.getParameter("customer_ID");
    String customer_Name = request.getParameter("customer_Name");
    String customer_Shipping_Address = request.getParameter("customer_Shipping_Address");
    String customer_State = request.getParameter("customer_State");
 String customer_ZIPCode = request.getParameter("customer_ZIPCode");
 String customer_Email = request.getParameter("customer_Email");

    com.aem.form.core.HandleForm hf = sling.getService(com.aem.form.core.HandleForm.class);
    hf.injestFormDataDB(customer_ID,customer_Name,customer_Shipping_Address, customer_State,customer_ZIPCode,customer_Email);

This code captures the posted form fields that are submitted from the adaptive form. It then creates an instance of com.aem.form.core.HandleForm object. Finally it invokes the HandleForm object's injestFormDataDB method and passes the submitted values.  


Ensure that the JSP file is named post.POST.jsp. If you do not use the lower and upper case, then the form will not successfully post data to this file.

Submit the form data

The final step is to preview the adaptive form. Open the form in the AEM Form view:


Click the Preview icon and fll out the Fields and click the Submit button. The following video shows this adaptive form being submitted and its data persisted in MySQL. 

Persisting an Adaptive Form data into MySql

Persisting an Adaptive Form data into MySql
Persisting an Adaptive Form data into MySql

See also

Congratulations, you have just created an AEM workflow that approves or rejects an asset. 

You can view additional AEM Community generated content:

Join the AEM community at: Adobe Experience Manager Community