Java Scripting with Lucee
Java Scripting with Lucee
Lucee provides comprehensive support for JSR-223 (Java Scripting API), enabling CFML to be used as a scripting language in any environment that supports the Java platform. This opens up powerful integration scenarios where you can leverage CFML's expressive syntax and built-in functions across diverse technology stacks, build tools, serverless platforms, and automation frameworks.
Overview
Through JSR-223 support, Lucee can be used as a scripting engine in any environment that runs on the Java platform. This includes build tools like Ant and Maven, serverless platforms like AWS Lambda, CI/CD pipelines, data processing workflows, and standalone scripts. The integration requires only adding Lucee JAR files to your classpath - no complex setup or application server needed.
AI-Optimized Technical Reference
For developers using AI assistance or requiring structured technical data, see the companion specification: Java Scripting Technical Spec
This YAML document contains pure technical facts optimized for:
- AI systems generating code implementations
 - Quick reference lookup of engine names, dependencies, and system properties
 - Tool consumption and automated integration
 - Developers already familiar with JSR-223 who need only Lucee-specific details
 
Requirements
- Java 11 or higher
 - Lucee 5.0 or higher (lucee.jar)
 - Servlet API implementation (javax.servlet or jakarta.servlet)
 - Optional: Additional Lucee extensions as needed
 
How It Works
- Lucee registers itself as a JSR-223 ScriptEngine via 
META-INF/services/javax.script.ScriptEngineFactory - The Java application discovers Lucee through the standard ScriptEngineManager
 - CFML code can be executed directly from Java strings or files
 - Variables and objects can be passed bidirectionally between Java and CFML
 - CFML functions and features work as expected within the scripting context
 
Basic Setup
Adding Lucee to Your Project
Maven Dependencies
<dependencies>
    <!-- Lucee Core -->
    <dependency>
        <groupId>org.lucee</groupId>
        <artifactId>lucee</artifactId>
        <version>6.0.0.677-SNAPSHOT</version>
    </dependency>
    <!-- Servlet API (choose javax or jakarta based on your environment) -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
</dependencies>
Gradle Dependencies
dependencies {
    implementation 'org.lucee:lucee:6.0.0.677-SNAPSHOT'
    implementation 'javax.servlet:javax.servlet-api:4.0.1'
}
Simple Java Integration
import javax.script.*;
public class LuceeScriptingExample {
    public static void main(String[] args) throws ScriptException {
        // Get the script engine manager
        ScriptEngineManager manager = new ScriptEngineManager();
        // Get the CFML script engine
        ScriptEngine engine = manager.getEngineByName("CFML");
        if (engine == null) {
            System.err.println("CFML script engine not found!");
            return;
        }
        // Execute simple CFML code
        String cfmlCode = """
            name = "World";
            message = "Hello, " & name & "!";
            writeOutput(message);
        """;
        Object result = engine.eval(cfmlCode);
        System.out.println("Script executed successfully");
    }
}
Basic Examples
Example 1: Variable Exchange
import javax.script.*;
public class VariableExchange {
    public static void main(String[] args) throws ScriptException {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("CFML");
        // Pass variables from Java to CFML
        engine.put("javaVariable", "Hello from Java!");
        engine.put("numbers", new int[]{1, 2, 3, 4, 5});
        // Execute CFML that uses Java variables
        engine.eval("""
            writeOutput("Java sent: " & javaVariable & "<br>");
            
            total = 0;
            for(num in numbers) {
                total += num;
            }
            
            result = "Sum of numbers: " & total;
            writeOutput(result);
        """);
        // Get results back from CFML
        String result = (String) engine.get("result");
        System.out.println("CFML result: " + result);
    }
}
Example 2: Build Automation
Simple build script processing with Ant:
<!-- build.xml -->
<project name="DataProcessor" default="process">
    <target name="process">
        <script language="CFML">
            <![CDATA[
            // Read configuration
            configFile = "config.json";
            if(fileExists(configFile)) {
                config = deserializeJSON(fileRead(configFile));
                
                // Process based on configuration
                writeOutput("Processing " & config.environment & " build...<br>");
                
                // Simple file operations
                if(config.cleanBuild) {
                    if(directoryExists("./dist")) {
                        directoryDelete("./dist", true);
                    }
                    directoryCreate("./dist");
                }
                
                // Update version
                config.buildNumber++;
                config.lastBuild = dateTimeFormat(now(), "iso8601");
                
                // Write back configuration
                fileWrite(configFile, serializeJSON(config));
                
                writeOutput("Build " & config.buildNumber & " completed!<br>");
            }
            ]]>
        </script>
    </target>
</project>
Example 3: Command Line Utility
// SimpleProcessor.java
import javax.script.*;
public class SimpleProcessor {
    public static void main(String[] args) throws ScriptException {
        if (args.length == 0) {
            System.out.println("Usage: java SimpleProcessor <command>");
            return;
        }
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("CFML");
        engine.put("command", args[0]);
        engine.put("arguments", args);
        engine.eval("""
            switch(command) {
                case "hash":
                    if(arrayLen(arguments) > 1) {
                        result = hash(arguments[2], "SHA-256");
                        writeOutput("SHA-256: " & result);
                    }
                    break;
                    
                case "uuid":
                    result = createUUID();
                    writeOutput("UUID: " & result);
                    break;
                    
                case "date":
                    result = dateTimeFormat(now(), "yyyy-mm-dd HH:nn:ss");
                    writeOutput("Current time: " & result);
                    break;
                    
                default:
                    writeOutput("Unknown command: " & command);
            }
        """);
    }
}
Real-World Scenarios
CI/CD Pipeline Processing
# GitHub Actions example
- name: Process Release Data
  run: |
    java -cp "lucee.jar:servlet-api.jar" \
         lucee.runtime.script.CFMLScriptEngineFactory \
         eval "
         version = '${{ github.event.release.tag_name }}';
         writeOutput('Processing release: ' & version);
         
         // Generate release notes
         notes = {
           'version': version,
           'date': dateTimeFormat(now(), 'yyyy-mm-dd'),
           'build': '${{ github.run_number }}'
         };
         
         fileWrite('release-info.json', serializeJSON(notes));
         "
Data Migration Scripts
// MigrationRunner.java
ScriptEngine engine = manager.getEngineByName("CFML");
engine.put("sourceDB", dataSource1);
engine.put("targetDB", dataSource2);
engine.eval("""
    // Simple data transformation
    sourceData = queryExecute("SELECT * FROM old_table", {}, {datasource: sourceDB});
    
    for(row in sourceData) {
        transformedData = {
            id: row.id,
            name: uCase(row.name),
            created_date: dateFormat(row.date_created, "yyyy-mm-dd")
        };
        
        queryExecute("
            INSERT INTO new_table (id, name, created_date) 
            VALUES (:id, :name, :created_date)
        ", transformedData, {datasource: targetDB});
    }
    
    writeOutput("Migrated " & sourceData.recordCount & " records");
""");
Configuration Processing
// ConfigProcessor.java - For deployment automation
engine.put("environment", System.getProperty("env", "dev"));
engine.put("configTemplate", Files.readString(Paths.get("config.template")));
engine.eval("""
    config = deserializeJSON(configTemplate);
    
    // Environment-specific settings
    switch(environment) {
        case "prod":
            config.database.host = "prod-db.company.com";
            config.cache.enabled = true;
            break;
        case "staging":
            config.database.host = "staging-db.company.com";
            config.debug = false;
            break;
        default:
            config.database.host = "localhost";
            config.debug = true;
    }
    
    finalConfig = serializeJSON(config);
""");
String result = (String) engine.get("finalConfig");
Files.writeString(Paths.get("application.json"), result);
Log Analysis
// LogAnalyzer.java
engine.put("logContent", Files.readString(Paths.get("app.log")));
engine.eval("""
    lines = listToArray(logContent, chr(10));
    
    stats = {
        total: arrayLen(lines),
        errors: 0,
        warnings: 0,
        timeRange: {}
    };
    
    for(line in lines) {
        if(findNoCase("ERROR", line)) stats.errors++;
        if(findNoCase("WARN", line)) stats.warnings++;
    }
    
    // Extract first and last timestamps
    if(arrayLen(lines) > 0) {
        firstLine = lines[1];
        lastLine = lines[arrayLen(lines)];
        
        // Simple timestamp extraction (adjust pattern as needed)
        timestampPattern = "\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}";
        firstTimestamp = reMatch(timestampPattern, firstLine);
        lastTimestamp = reMatch(timestampPattern, lastLine);
        
        if(arrayLen(firstTimestamp)) stats.timeRange.start = firstTimestamp[1];
        if(arrayLen(lastTimestamp)) stats.timeRange.end = lastTimestamp[1];
    }
    
    summary = "Log Analysis: " & stats.total & " lines, " & 
              stats.errors & " errors, " & stats.warnings & " warnings";
    writeOutput(summary);
""");
Test Data Generation
// TestDataGenerator.java
engine.put("recordCount", 1000);
engine.eval("""
    testData = [];
    
    for(i = 1; i <= recordCount; i++) {
        record = {
            id: i,
            name: "User" & i,
            email: "user" & i & "@test.com",
            created: dateAdd("d", -randRange(1, 365), now()),
            active: (i % 3 != 0) // ~66% active
        };
        arrayAppend(testData, record);
    }
    
    // Convert to CSV
    csvData = "id,name,email,created,active" & chr(10);
    for(record in testData) {
        csvData &= record.id & "," & 
                  record.name & "," & 
                  record.email & "," & 
                  dateFormat(record.created, "yyyy-mm-dd") & "," &
                  record.active & chr(10);
    }
    
    writeOutput("Generated " & arrayLen(testData) & " test records");
""");
String csvData = (String) engine.get("csvData");
Files.writeString(Paths.get("test-data.csv"), csvData);
Docker Container Scripts
# Dockerfile example
FROM openjdk:11-jre-slim
COPY lucee.jar servlet-api.jar /app/lib/
COPY process-script.cfm /app/
WORKDIR /app
CMD ["java", "-cp", "lib/*", "lucee.runtime.script.CFMLScriptEngineFactory", \
     "eval", "include 'process-script.cfm';"]
Kubernetes Job Processing
# k8s-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: data-processor
spec:
  template:
    spec:
      containers:
      - name: processor
        image: openjdk:11
        command:
        - java
        - -cp
        - /app/lucee.jar:/app/servlet-api.jar
        - lucee.runtime.script.CFMLScriptEngineFactory
        - eval
        - |
          writeOutput("Processing started at: " & dateTimeFormat(now(), "iso8601"));
          // Your processing logic here
          env = server.system.environment;
          writeOutput("Environment: " & env.NODE_NAME ?: "unknown");
          // Process data from mounted volumes or environment variables
          if(structKeyExists(env, "DATA_SOURCE")) {
              writeOutput("Processing data from: " & env.DATA_SOURCE);
          }
          writeOutput("Processing completed successfully");
        env:
        - name: DATA_SOURCE
          value: "/data/input.json"
        volumeMounts:
        - name: data-volume
          mountPath: /data
      restartPolicy: Never
Advanced Integration Scenarios
AWS Lambda Integration
Simple serverless function entry point:
// LuceeLambdaHandler.java
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import javax.script.*;
import java.util.Map;
public class LuceeLambdaHandler implements RequestHandler<Map<String, Object>, Map<String, Object>> {
    private static ScriptEngine engine;
    static {
        ScriptEngineManager manager = new ScriptEngineManager();
        engine = manager.getEngineByName("CFML");
    }
    @Override
    public Map<String, Object> handleRequest(Map<String, Object> input, Context context) {
        try {
            engine.put("inputData", input);
            engine.put("requestId", context.getAwsRequestId());
            engine.eval("""
                // Your business logic here
                result = {
                    "message": "Hello from Lucee!",
                    "requestId": requestId,
                    "timestamp": dateTimeFormat(now(), "iso8601"),
                    "processed": true
                };
                
                // Process input data
                if(structKeyExists(inputData, "name")) {
                    result.greeting = "Hello, " & inputData.name & "!";
                }
            """);
            @SuppressWarnings("unchecked")
            Map<String, Object> result = (Map<String, Object>) engine.get("result");
            return result;
        } catch (Exception e) {
            return Map.of("error", e.getMessage());
        }
    }
}
Spring Boot Integration
Basic service integration:
@Service
public class LuceeScriptService {
    private final ScriptEngine engine;
    public LuceeScriptService() {
        ScriptEngineManager manager = new ScriptEngineManager();
        this.engine = manager.getEngineByName("CFML");
    }
    public Object processRequest(String script, Map<String, Object> variables) throws ScriptException {
        if (variables != null) {
            variables.forEach(engine::put);
        }
        return engine.eval(script);
    }
}
@RestController
public class ScriptController {
    private final LuceeScriptService scriptService;
    @PostMapping("/api/process")
    public ResponseEntity<Object> process(@RequestBody Map<String, Object> request) {
        try {
            String script = """
                result = {
                    "processed": true,
                    "data": inputData,
                    "timestamp": dateTimeFormat(now(), "iso8601")
                };
            """;
            scriptService.processRequest(script, Map.of("inputData", request));
            return ResponseEntity.ok(scriptService.engine.get("result"));
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
        }
    }
}
Performance and Best Practices
Engine Reuse
public class EngineManager {
    private static final ScriptEngineManager manager = new ScriptEngineManager();
    private static final ScriptEngine engine = manager.getEngineByName("CFML");
    public static Object execute(String script, Map<String, Object> variables) throws ScriptException {
        // Set variables
        if (variables != null) {
            variables.forEach(engine::put);
        }
        return engine.eval(script);
    }
}
Error Handling
public static class ScriptResult {
    private final boolean success;
    private final Object result;
    private final String errorMessage;
    public static ScriptResult execute(String script, Map<String, Object> variables) {
        try {
            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("CFML");
            if (variables != null) {
                variables.forEach(engine::put);
            }
            // Add error handling in CFML
            engine.eval("""
                try {
                    // Your script here
                    scriptSuccess = true;
                    errorMsg = "";
                } catch(any e) {
                    scriptSuccess = false;
                    errorMsg = e.message;
                }
            """);
            engine.eval(script);
            Boolean success = (Boolean) engine.get("scriptSuccess");
            if (!success) {
                String error = (String) engine.get("errorMsg");
                return new ScriptResult(false, null, error);
            }
            Object result = engine.get("result");
            return new ScriptResult(true, result, null);
        } catch (Exception e) {
            return new ScriptResult(false, null, e.getMessage());
        }
    }
    // Constructor and getters...
}
Thread Safety
public class ThreadSafeScriptExecutor {
    private static final ThreadLocal<ScriptEngine> engineThreadLocal = 
        ThreadLocal.withInitial(() -> {
            ScriptEngineManager manager = new ScriptEngineManager();
            return manager.getEngineByName("CFML");
        });
    public static Object executeInThread(String script, Map<String, Object> variables) 
            throws ScriptException {
        ScriptEngine engine = engineThreadLocal.get();
        if (variables != null) {
            variables.forEach(engine::put);
        }
        return engine.eval(script);
    }
    public static void cleanup() {
        engineThreadLocal.remove();
    }
}
This comprehensive recipe provides everything needed to successfully integrate Lucee as a scripting engine in Java applications, from simple examples to complex enterprise scenarios like AWS Lambda and Spring Boot integration.