One of the methods of creating a custom data type in Appian is to define the data type as a Java object in a custom data type plug-in.
To deploy a CDT defined using a Java class, a datatype
plug-in module must be defined in appian-plugin.xml
.
datatype
module must be declared before the smart service or function that uses it.datatype
module descriptor element contains members whose data types are defined in other classes, those data types are automatically included when the plug-in deploys (as long as they contain the minimum required JAXB Annotations). Such data types do not need to be independently listed in class elements.As a best practice, we recommend only grouping data types that are closely related (logically) into a single datatype
module.
The exact JAXB version is determined by the JDK version you have in use.
You can define a Java class or a package using JAXB 2.x annotations to define a data type.
The only required attribute of the class annotation is the namespace attribute, which defines the target namespace.
When using a package to define a set of custom data types, the @XmlSchema package annotation is required. This annotation must include a valid namespace attribute. List the annotation in package-info.java.
Multiple class subelements can be defined in a datatype
module or by listing the packages that contain your CDT classes as package subelements. You can define either class or package subelements, but both types of subelements cannot appear in the same module.
Any XSD generated using JAXB annotations is validated to ensure the definition conforms to Appian XSD restrictions. Valid JAXB XSD definitions can fail to deploy if they do not conform to Appian XSD requirements.
JPA annotations can be used within the Java class, in addition to the JAXB annotations, to add persistence configurations when the data type is used as a Data Store)Entity.
deployment/web.war/WEB-INF/lib/hibernate-jpa-2.0-api-1.0.0.Final.jar
to achieve this.indexed
attribute available on the @OneToMany
and @ManyToMany
annotations, can only be used when using JPA annotations in the XSD definition and cannot be used with JPA annotations in Java. If the use of these is required, you can still create your initial data type as a Java plug-in, then download the XSD from the Data Type Designer interface, add the attribute as desired, and import the XSD with the added attribute.To update a data type, deploy a new version of the plug-in with a version number greater than the currently-deployed plug-in. All dependent design objects will use the new version of the plug-in data type. If you use the data type in a data store, and data store auto-update is enabled, deploying an update to the data type will trigger automatic schema updates. Results of the update will be recorded in the application server logs.
To bind the following XSD:
1
2
3
4
5
<xs:complexType name="jeep_type">
<xs:sequence>
<xs:element name="has_four_wheel_drive" type="xs:boolean"/>
</xs:sequence>
</xs:complexType>
Use the following Java representation:
1
2
3
4
5
6
7
8
9
import java.util.HashSet;
import javax.xml.bind.annotation.XmlID;
@XmlType(name="jeep_type", namespace="http://www.example.org/documentation"})
public class JeepType {
@XmlElement
boolean isHasFourWheelDrive() {...}
void setHasFourWheelDrive(boolean value) {...}
}
The following code snippet lists a Java class that uses JAXB annotations to define a data type:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@XmlRootElement(name="sample-bean-el", namespace="http://www.example.org/test")
@XmlType(name="sample-bean", namespace="http://www.example.org/test", propOrder={"first", "second"})
private static class SampleBean {
private int first;
private String second;
@XmlElement
public int getFirst() {
return first;
}
public void setFirst(int first) {
this.first = first;
}
@XmlElement
public String getSecond() {
return second;
}
public void setSecond(String second) {
this.second = second;
}
}
The following example uses two Java classes with JAXB and JPA annotations to define two related data types. A project has a status, which is managed as a lookup.
The Project data type:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.acme.example;
@XmlRootElement(namespace="urn:my-namespace", name="project")
@XmlType(namespace="urn:my-namespace", name=Project.LOCAL_PART, propOrder={"id", "status", "users"})
@XmlSeeAlso({Status.class})
@Hidden
@Table(name="project")
public class Project implements Serializable {
private static final long serialVersionUID = 1L;
public static final String LOCAL_PART = "Project";
public static final QName QNAME = new QName("urn:my-namespace", LOCAL_PART);
private Long id;
private Status status;
private Set<String> users = new HashSet<String>();
public Project(long id, Status status, Set<String> users) {
this();
setId(id);
setStatus(status);
setUsers(users);
}
public Project() {} // for serialization only
@Id
@GeneratedValue
@XmlElement
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
@XmlElement
public Set<String> getUsers() {
return users;
}
private void setUsers(Set<String> users) {
this.users = new HashSet<String>(users);
}
@ManyToOne(optional=false, cascade={CascadeType.REFRESH})
@JoinColumn(name="status_id")
@XmlElement
public Status getStatus() {
return status;
}
private void setStatus(Status status) {
this.status = status;
}
}
The Status data type:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.acme.example;
@XmlRootElement(namespace="urn:my-namespace", name="status")
@XmlType(namespace="urn:my-namespace", name=Status.LOCAL_PART, propOrder={"id", "name"})
@Hidden
@Table(name="status")
public class Status implements Serializable {
private static final long serialVersionUID = 1L;
public static final String LOCAL_PART = "Status";
public static final QName QNAME = new QName("urn:my-namespace", LOCAL_PART);
private Long id;
private String name;
public Status(Long id, String name) {
this();
setId(id);
setName(name);
}
public Status() {} // for serialization only
@Id
@XmlElement
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
@Column(length=255, nullable=false, unique=true)
@XmlElement
public String getName() {
return name;
}
private void setName(String name) {
this.name = name;
}
}
When used in a plug-in, CDTs defined as Java objects must be configured in your appian-plugin.xml
file in the following manner:
1
2
3
4
5
6
7
8
9
10
11
12
<appian-plugin>
<plugin-info>
<description>...</description>
<vendor name="..." url="..." />
<version>...</version>
<application-version min="..." />
</plugin-info>
<datatype key="ProjectDataType" name="Example Project Data Type">
<class>com.acme.example.Project</class>
<class>com.acme.example.Status</class>
</datatype>
</appian-plugin>
version
number must be greater than the currently-deployed plug-in's version.datatype
elements in one plug-in descriptor file.
datatype
module. This attribute of datatype
must be unique in the system.datatype
module. The name attribute of datatype
appears in log file output. It does not appear in the user interface.Data Type Plug-ins