Package org.apache.daffodil.api.udf
User Defined Functions
Introduction
Apache Daffodil allows execution of Java/Scala external (user defined) functions in DFDL expressions.
Getting Started
Provide a JAR on the classpath (or Daffodil classpath) that contains at least two kinds of classes:
a provider class and its associated user-defined function (UDF) class(es). All providers must be
registered in the file
META-INF/services/org.apache.daffodil.api.udf.UserDefinedFunctionProvider
, regardless of how many
providers or UDFs are included.
UDF Implementation
User Defined Function Provider Classes
The provider class must extend Daffodil's UserDefinedFunctionProvider
. It must implement the
getUserDefinedFunctionClasses()
abstract method and return every User Defined Function the provider supplies. The base provider offers
createUserDefinedFunction(namespaceURI, name)
to look up and instantiate UDFs that have a no‑argument
constructor. If a UDF requires constructor arguments, override the lookup to construct it appropriately.
Providers participate in Java’s ServiceLoader
mechanism and therefore must include
a file named META-INF/services/org.apache.daffodil.api.udf.UserDefinedFunctionProvider
listing the
fully qualified names of the provider class(es) contained in the JAR. Without this file, neither the provider nor
its UDFs will be visible to Daffodil.
User Defined Function Classes
Each UDF class must extend Daffodil's UserDefinedFunction
. It contains the functionality to be used in DFDL
expressions and must be annotated with UserDefinedFunctionIdentification
, supplying the UDF invocation
name
and namespaceURI
. A method named evaluate(...)
must be implemented; it is what Daffodil
calls to execute the UDF. Overloaded or void evaluate
methods are not
supported.
User Defined Function Exceptions
UserDefinedFunctionProcessingError
: throw to request backtracking during parsing.UserDefinedFunctionFatalException
: throw to abort processing entirely.
Any other exception type is treated as UserDefinedFunctionFatalException
.
UDF Registration
Typical project layouts:
Scala (sbt-style):
src/
main/
scala/
org/
sgoodudfs/
example/
StringFunctions/
StringFunctionsProvider.scala // UDF provider (may contain UDF classes or define them separately)
resources/
META-INF/
services/
org.apache.daffodil.api.udf.UserDefinedFunctionProvider
Java (generic):
src/
org/
jgoodudfs/
example/
StringFunctions/
StringFunctionsProvider.java // UDF provider
Compare.java // UDF class
Replace.java // UDF class
META-INF/
services/
org.apache.daffodil.api.udf.UserDefinedFunctionProvider
Each UDF is registered by listing the provider’s fully qualified class name in the text file
META-INF/services/org.apache.daffodil.api.udf.UserDefinedFunctionProvider
. The META-INF
folder must be discoverable from the classpath root or the ServiceLoader will not find it.
UDF Usage
In your DFDL schema, define an xsd namespace or set the default namespace to match the UDF’s annotation namespaceURI
, then
invoke using the annotated name
. For example:
// annotation on the UDF class
UserDefinedFunctionIdentification(
name = "replace",
namespaceURI = "http://example.com/ext/stringfunctions")
// within the schema tag
xmlns:sdf="http://example.com/ext/stringfunctions"
// within the DFDL expression
..."{ sdf:replace(., ' ', '_') }"...
Supported Types
- BigDecimal (Java)
- BigInteger (Java)
- Boolean (boxed and primitive)
- Byte (boxed, primitive, array of primitive)
- Double (boxed and primitive)
- Float (boxed and primitive)
- Integer (boxed and primitive)
- Long (boxed and primitive)
- Short (boxed and primitive)
- String
Restrictions
- Overloading unsupported
- Void
evaluate
functions unsupported
-
ClassDescriptionInterface that all User Defined Functions classes must implement.Annotation that must be applied to every UDF in order for it to be considered valid.Abstract class used by ServiceLoader to poll for UDF providers on classpath.