Package org.apache.daffodil.api.udf


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