|
1 | 1 | <!-- |
2 | 2 | { |
3 | | - "title": "Dynamic Proxy Enhancements in Lucee 7", |
| 3 | + "title": "Dynamic Proxy Enhancements", |
4 | 4 | "id": "dynamic-proxy-enhancements", |
5 | | - "description": "Learn about the improvements to dynamic proxy creation in Lucee 7, including automatic inclusion of component functions and properties when implementing Java interfaces.", |
| 5 | + "since": "7.0", |
| 6 | + "description": "Lucee 7 improvements to dynamic proxy creation - all component functions and properties are now always included when implementing Java interfaces.", |
6 | 7 | "keywords": [ |
7 | 8 | "dynamic proxy", |
8 | 9 | "java", |
|
24 | 25 | } |
25 | 26 | --> |
26 | 27 |
|
27 | | -# Dynamic Proxy Enhancements in Lucee 7 |
| 28 | +# Dynamic Proxy Enhancements |
28 | 29 |
|
29 | | -All component functions and properties are now always included in dynamic proxies, making Java interoperability more predictable. |
| 30 | +When you pass a CFML component to Java code, Lucee creates a *proxy* - a wrapper that makes your component look like a Java object. In Lucee 7, proxies now include **all** your component's functions and properties, not just the interface methods. |
30 | 31 |
|
31 | | -## What Changed in Lucee 7 |
| 32 | +**Java terms:** A *Java interface* is a contract defining method signatures a class must implement (like CFML's `implements` attribute). A *proxy* wraps your component so Java sees it as implementing that interface. |
32 | 33 |
|
33 | | -### Component Functions and Properties Always Included |
| 34 | +## What Changed |
34 | 35 |
|
35 | | -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. |
| 36 | +Previously, custom methods you added beyond the interface weren't consistently available through the proxy. Now they always are (LDEV-5421). |
36 | 37 |
|
37 | | -This enhancement (LDEV-5421) makes dynamic proxies behave more predictably and eliminates subtle issues where component methods might not be accessible through the proxy. |
38 | | - |
39 | | -## Basic Usage |
40 | | - |
41 | | -When you create a component that implements a Java interface, you can use `createDynamicProxy()` to get a Java proxy object: |
| 38 | +## Example |
42 | 39 |
|
43 | 40 | ```cfml |
44 | | -// Define a component implementing java.util.Map |
45 | 41 | myComponent = new component implements="java:java.util.Map" { |
46 | | -
|
47 | | - function size(){ |
48 | | - return 42; |
49 | | - } |
50 | | -
|
51 | | - function isEmpty(){ |
52 | | - return false; |
53 | | - } |
| 42 | + function size() { return 42; } |
| 43 | + function isEmpty() { return false; } |
| 44 | + function get( key ) { return "value"; } |
| 45 | + function put( key, value ) { return null; } |
| 46 | + // ... other Map methods |
54 | 47 |
|
55 | 48 | // Custom function (not part of Map interface) |
56 | | - function customMethod(){ |
57 | | - return "This is now always included in the proxy!"; |
58 | | - } |
59 | | -
|
60 | | - // Additional required Map methods... |
61 | | - function get( key ){ |
62 | | - return "value"; |
| 49 | + function customMethod() { |
| 50 | + return "Now always included in the proxy!"; |
63 | 51 | } |
64 | | -
|
65 | | - function put( key, value ){ |
66 | | - return null; |
67 | | - } |
68 | | -
|
69 | | - // ... other Map interface methods |
70 | 52 | }; |
71 | 53 |
|
72 | | -// Create the dynamic proxy |
73 | 54 | proxy = createDynamicProxy( myComponent, [ "java.util.Map" ] ); |
74 | 55 |
|
75 | | -// All component methods are accessible through the proxy |
76 | | -systemOutput( proxy.size() ); // 42 |
77 | | -systemOutput( proxy.customMethod() ); // Works in Lucee 7! |
| 56 | +systemOutput( proxy.size() ); // 42 |
| 57 | +systemOutput( proxy.customMethod() ); // Works in Lucee 7! |
78 | 58 | ``` |
79 | 59 |
|
80 | | -## Automatic Proxy Creation with getClass() |
| 60 | +## getClass() Shorthand |
81 | 61 |
|
82 | | -Lucee 7 also introduces the ability to call `.getClass()` directly on components that implement Java interfaces, automatically creating a dynamic proxy if needed: |
| 62 | +Components with `implements="java:..."` can call `.getClass()` directly - Lucee creates the proxy automatically: |
83 | 63 |
|
84 | 64 | ```cfml |
85 | 65 | myComponent = new component implements="java:java.util.Map" { |
86 | | - function size(){ |
87 | | - return 42; |
88 | | - } |
89 | | - // ... other methods |
| 66 | + // ... methods |
90 | 67 | }; |
91 | 68 |
|
92 | | -// New in Lucee 7 - automatic proxy creation |
93 | 69 | classInfo = myComponent.getClass(); |
94 | 70 |
|
95 | | -// Previously required explicit proxy creation: |
| 71 | +// Equivalent to: |
96 | 72 | // classInfo = createDynamicProxy( myComponent, [ "java.util.Map" ] ).getClass(); |
97 | 73 | ``` |
98 | 74 |
|
99 | | -See [[component-getclass-method]] for more details on this feature. |
100 | | - |
101 | | -## Use Cases |
| 75 | +See [[component-getclass-method]] for details. |
102 | 76 |
|
103 | | -These enhancements are particularly valuable when: |
| 77 | +## Runnable Example |
104 | 78 |
|
105 | | -- **Building Java library integrations** - Your component methods are reliably accessible through the proxy |
106 | | -- **Extending Java interfaces** - Add custom functionality beyond the interface contract |
107 | | -- **Framework development** - Create components that implement Java interfaces with additional CFML-specific methods |
108 | | -- **Working with callbacks** - Pass components to Java libraries that expect interface implementations |
109 | | - |
110 | | -## Example: Implementing java.lang.Runnable |
| 79 | +A practical use case - implementing Java's `Runnable` interface to run code in a thread: |
111 | 80 |
|
112 | 81 | ```cfml |
113 | | -// Create a component implementing Runnable |
114 | 82 | task = new component implements="java:java.lang.Runnable" { |
115 | | -
|
116 | 83 | variables.executionCount = 0; |
117 | 84 |
|
118 | | - function run(){ |
| 85 | + function run() { |
119 | 86 | variables.executionCount++; |
120 | 87 | systemOutput( "Task executed ##variables.executionCount## times" ); |
121 | 88 | } |
122 | 89 |
|
123 | | - // Custom method to check execution count |
124 | | - function getExecutionCount(){ |
| 90 | + // Custom method - now accessible through proxy |
| 91 | + function getExecutionCount() { |
125 | 92 | return variables.executionCount; |
126 | 93 | } |
127 | 94 | }; |
128 | 95 |
|
129 | | -// Create proxy and pass to Java's ExecutorService |
130 | 96 | proxy = createDynamicProxy( task, [ "java.lang.Runnable" ] ); |
131 | 97 |
|
132 | | -// Create a Java thread |
133 | 98 | thread = createObject( "java", "java.lang.Thread" ).init( proxy ); |
134 | 99 | thread.start(); |
135 | 100 | thread.join(); |
136 | 101 |
|
137 | | -// Access custom methods through the original component |
138 | 102 | systemOutput( "Total executions: " & task.getExecutionCount() ); |
139 | 103 | ``` |
140 | 104 |
|
141 | | -## Key Benefits |
142 | | - |
143 | | -1. **Predictable behavior** - All component methods are consistently available through the proxy |
144 | | -2. **Simplified code** - Automatic proxy creation with `.getClass()` |
145 | | -3. **Better Java integration** - Seamlessly mix CFML and Java functionality |
146 | | -4. **Enhanced flexibility** - Add custom methods beyond interface requirements |
147 | | - |
148 | | -## See Also |
| 105 | +## When You'd Use This |
149 | 106 |
|
150 | | -- [[component-getclass-method]] - Using getClass() for automatic proxy creation |
151 | | -- [[java-class-interaction]] - General Java interoperability in Lucee |
152 | | -- [[function-createdynamicproxy]] - createDynamicProxy() function reference |
| 107 | +- **Java library callbacks** - pass components to Java code expecting interface implementations |
| 108 | +- **Custom methods on proxies** - add CFML-specific helpers alongside interface methods |
| 109 | +- **Threading** - implement Runnable, Callable, or other Java concurrency interfaces |
0 commit comments