Dynamic Proxy Enhancements in Lucee 7
Dynamic Proxy Enhancements in Lucee 7
Lucee 7 introduces significant improvements to dynamic proxy creation, making Java interoperability more seamless and predictable when components implement Java interfaces.
What Changed in Lucee 7
Component Functions and Properties Always Included
In previous versions, when creating a dynamic proxy from a component that implements Java interfaces, not all component functions and properties were consistently included in the proxy. Lucee 7 ensures that all component functions and properties are always included in the dynamic proxy.
This enhancement (LDEV-5421) makes dynamic proxies behave more predictably and eliminates subtle issues where component methods might not be accessible through the proxy.
Basic Usage
When you create a component that implements a Java interface, you can use createDynamicProxy()
to get a Java proxy object:
// Define a component implementing java.util.Map
myComponent = new component implements="java:java.util.Map" {
function size(){
return 42;
}
function isEmpty(){
return false;
}
// Custom function (not part of Map interface)
function customMethod(){
return "This is now always included in the proxy!";
}
// Additional required Map methods...
function get( key ){
return "value";
}
function put( key, value ){
return null;
}
// ... other Map interface methods
};
// Create the dynamic proxy
proxy = createDynamicProxy( myComponent, [ "java.util.Map" ] );
// All component methods are accessible through the proxy
systemOutput( proxy.size() ); // 42
systemOutput( proxy.customMethod() ); // Works in Lucee 7!
Automatic Proxy Creation with getClass()
Lucee 7 also introduces the ability to call .getClass()
directly on components that implement Java interfaces, automatically creating a dynamic proxy if needed:
myComponent = new component implements="java:java.util.Map" {
function size(){
return 42;
}
// ... other methods
};
// New in Lucee 7 - automatic proxy creation
classInfo = myComponent.getClass();
// Previously required explicit proxy creation:
// classInfo = createDynamicProxy( myComponent, [ "java.util.Map" ] ).getClass();
See getClass() Method for Components for more details on this feature.
Use Cases
These enhancements are particularly valuable when:
- Building Java library integrations - Your component methods are reliably accessible through the proxy
- Extending Java interfaces - Add custom functionality beyond the interface contract
- Framework development - Create components that implement Java interfaces with additional CFML-specific methods
- Working with callbacks - Pass components to Java libraries that expect interface implementations
Example: Implementing java.lang.Runnable
// Create a component implementing Runnable
task = new component implements="java:java.lang.Runnable" {
variables.executionCount = 0;
function run(){
variables.executionCount++;
systemOutput( "Task executed ##variables.executionCount## times" );
}
// Custom method to check execution count
function getExecutionCount(){
return variables.executionCount;
}
};
// Create proxy and pass to Java's ExecutorService
proxy = createDynamicProxy( task, [ "java.lang.Runnable" ] );
// Create a Java thread
thread = createObject( "java", "java.lang.Thread" ).init( proxy );
thread.start();
thread.join();
// Access custom methods through the original component
systemOutput( "Total executions: " & task.getExecutionCount() );
Key Benefits
- Predictable behavior - All component methods are consistently available through the proxy
- Simplified code - Automatic proxy creation with
.getClass()
- Better Java integration - Seamlessly mix CFML and Java functionality
- Enhanced flexibility - Add custom methods beyond interface requirements
See Also
- getClass() Method for Components - Using getClass() for automatic proxy creation
- Java Class Interaction - General Java interoperability in Lucee
- CreateDynamicProxy() - createDynamicProxy() function reference