|
1 | 1 | --- |
2 | | -title: APIs extendibility of .NET suite for Java™/JVM™ |
3 | | -_description: Describes how to extend available APIs with .NET suite for Java™/JVM™ |
| 2 | +title: API Extensibility in JNet |
| 3 | +_description: Describes how to extend available APIs with the .NET suite for Java™/JVM™ |
4 | 4 | --- |
5 | 5 |
|
6 | | -# JNet: APIs extendibility |
| 6 | +# JNet: API extensibility |
7 | 7 |
|
8 | | -What to do if an API was not yet implemented? The simplest answer is: help us to make this product reacher :smile: |
9 | | -There is another answer which is not available with other products: Dynamic code and programmatically API access. |
| 8 | +If a Java™ API has not yet been mapped in JNet, there are two options: contribute a mapping upstream, |
| 9 | +or use JCOBridge's **direct and dynamic access** mechanisms to call any JVM™ class or method at |
| 10 | +runtime — without waiting for a ready-made wrapper. |
10 | 11 |
|
11 | | -With **JCOBridge** a developer can use some properties to manage objects in the JVM™. |
12 | | -Each JNet class implemented contains some methods and two properties: a direct and a dynamic accessor able to analyze the JVM™ class and executes the code. |
13 | | -So it is not necessary at all to have the methods be ready to be used. |
| 12 | +Every JNet class exposes two accessor properties alongside its ready-made methods, which can |
| 13 | +introspect and invoke the JVM™ class directly: |
14 | 14 |
|
15 | | -Let's go to show some possible conditions analyzing the `Hashtable` class (code at https://github.com/masesgroup/JNet/blob/master/src/net/JNet/Java/Util/Hashtable.cs). |
| 15 | +* **`JVM`** — a typed interface exposing properties and methods to interact with the JVM™ in a |
| 16 | + structured way. |
| 17 | +* **`DynJVM`** — returns a `dynamic` object, enabling fluent method calls without explicit typing. |
| 18 | + |
| 19 | +Let's look at some concrete scenarios using the `Hashtable` class |
| 20 | +(source at https://github.com/masesgroup/JNet/blob/master/src/net/JNet/Java/Util/Hashtable.cs). |
16 | 21 |
|
17 | 22 | ## When a method is not available |
18 | 23 |
|
19 | | -The class has a single ready made method: |
| 24 | +The class has a single ready-made method: |
20 | 25 |
|
21 | | -```C# |
| 26 | +```csharp |
22 | 27 | public void Put(K key, V value) => IExecute("put", key, value); |
23 | 28 | ``` |
24 | 29 |
|
25 | | -This is a void method, using **IExecute** the user of the library can invoke the `Put` method on the class and execute the Java™ counterpart. |
26 | | -The developer can, anyway, invoke the `put` method directly from the instance of the `Hashtable` class using two different paradigms: **direct** or **dynamic** access. |
27 | | -The `put` method can be replaced with any method (with or without parameters) of the `Hashtable` class. |
| 30 | +This is a void method — using `IExecute`, the library invokes the `put` method on the JVM™ counterpart. |
| 31 | +Any method of the `Hashtable` class (with or without parameters) can be called the same way, |
| 32 | +using either **direct** or **dynamic** access. |
28 | 33 |
|
29 | 34 | ### Direct access |
30 | 35 |
|
31 | | -The `IExecute` method is public and can be executed using the instance of the `Hashtable` class. |
| 36 | +`IExecute` is public and can be called directly on any JNet instance: |
32 | 37 |
|
33 | | -```C# |
| 38 | +```csharp |
34 | 39 | Hashtable<string, string> data = new Hashtable<string, string>(...); |
35 | 40 |
|
36 | 41 | data.IExecute("put", "a", "b"); |
37 | 42 | ``` |
38 | 43 |
|
39 | | -Anyway other methods can be accessed like in the following example where an overload of `IExecute` method returns a **bool** value: |
| 44 | +Other methods can also be accessed this way. An overload of `IExecute` accepts a type parameter |
| 45 | +to capture the return value: |
40 | 46 |
|
41 | | -```C# |
| 47 | +```csharp |
42 | 48 | Hashtable<string, string> data = new Hashtable<string, string>(...); |
43 | 49 |
|
44 | 50 | bool isEmpty = data.IExecute<bool>("isEmpty"); |
45 | 51 | ``` |
46 | 52 |
|
47 | 53 | ### Dynamic access |
48 | 54 |
|
49 | | -```C# |
| 55 | +```csharp |
50 | 56 | dynamic data = new Hashtable<string, string>(...); |
51 | 57 |
|
52 | 58 | data.put("a", "b"); |
53 | 59 | var isEmpty = data.isEmpty(); |
54 | 60 | ``` |
55 | 61 |
|
56 | | -The `Hashtable`, and any other ready made class of the library, supports the **dynamic** access to the methods available in Java™ side. |
57 | | -The previous example demostrates the behavior. |
| 62 | +Every ready-made JNet class supports `dynamic` access to all methods available on the Java™ side. |
| 63 | +The example above demonstrates this behavior. |
58 | 64 |
|
59 | 65 | ## When a class is not available |
60 | 66 |
|
61 | | -In a more complex scenario the method can return back objects or can accept input of not ready made classes: no problem, there is a solution. |
| 67 | +In more complex scenarios, a method may return an object or accept a parameter of a type that has |
| 68 | +not yet been mapped in JNet. There is a solution for each case. |
62 | 69 |
|
63 | 70 | ### Return class is not available |
64 | 71 |
|
65 | | -To discuss this case we use another class: the [AWT Panel](https://docs.oracle.com/javase/8/docs/api/java/awt/Panel.html), implemented in [Java.Awt.Panel](https://github.com/masesgroup/JNet/blob/master/src/net/JNet/Java/Awt/Panel.cs). |
66 | | -The .NET class does not have any implemented method: we discuss about [createVolatileImage](https://docs.oracle.com/javase/8/docs/api/java/awt/Component.html#createVolatileImage-int-int-) inherited from the base class `Component`. |
67 | | -The method returns a [VolatileImage](https://docs.oracle.com/javase/8/docs/api/java/awt/image/VolatileImage.html) which is not yet implemented; a solution on this problem is to use directly the `createVolatileImage` Java™ method like the following code snippet does: |
| 72 | +To illustrate this, consider the [AWT Panel](https://docs.oracle.com/javase/8/docs/api/java/awt/Panel.html), |
| 73 | +implemented in [Java.Awt.Panel](https://github.com/masesgroup/JNet/blob/master/src/net/JNet/Java/Awt/Panel.cs). |
| 74 | +The .NET class has no mapped methods. The example below calls |
| 75 | +[createVolatileImage](https://docs.oracle.com/javase/8/docs/api/java/awt/Component.html#createVolatileImage-int-int-) |
| 76 | +(inherited from `Component`), which returns a |
| 77 | +[VolatileImage](https://docs.oracle.com/javase/8/docs/api/java/awt/image/VolatileImage.html) — a class |
| 78 | +not yet mapped in JNet: |
68 | 79 |
|
69 | | -```C# |
| 80 | +```csharp |
70 | 81 | Java.Awt.Panel panel = new(); |
71 | | -var volImage = panel.IExecute("createVolatileImage", 100, 100); // the returned object is a dynamic object which reference the VolatileImage object in Java |
72 | | -var snapshot = volImage.getSnapshot(); // the returned object is a dynamic object reference of the BufferedImage object in Java |
73 | | -var isContentLost = volImage.contentsLost(); // the returned object is a bool representing the Java counterpart |
74 | 82 |
|
| 83 | +// Returns a dynamic reference to the VolatileImage object in the JVM™ |
| 84 | +var volImage = panel.IExecute("createVolatileImage", 100, 100); |
| 85 | +// Returns a dynamic reference to the BufferedImage object in the JVM™ |
| 86 | +var snapshot = volImage.getSnapshot(); |
| 87 | +// Returns a bool — the Java boolean is automatically converted |
| 88 | +var isContentLost = volImage.contentsLost(); |
75 | 89 | ``` |
76 | 90 |
|
77 | | -The example above uses the classes `VolatileImage` and `BufferedImage` which are not implemented yet: the classes exists in JVM™ and can be accessed. |
| 91 | +`VolatileImage` and `BufferedImage` are not mapped in JNet, but they exist in the JVM™ and are |
| 92 | +fully accessible as `dynamic` references. |
78 | 93 |
|
79 | | -### Input and Return class are not available |
| 94 | +### Input and return class are not available |
80 | 95 |
|
81 | | -If even the input class is not available the solution is like the following: |
| 96 | +If the input class is also not mapped, use the `JVM` property to instantiate it directly in the JVM™: |
82 | 97 |
|
83 | | -```C# |
| 98 | +```csharp |
84 | 99 | Java.Awt.Panel panel = new(); |
85 | | -var dynImageCapabilities = panel.JVM.New("java.awt.ImageCapabilities", true); // the returned object is a dynamic object which is a reference of the ImageCapabilities object in Java |
86 | | -var volImage = panel.IExecute("createVolatileImage", 100, 100, dynImageCapabilities); // the returned object is a dynamic object which reference the VolatileImage object in Java |
87 | | -var snapshot = volImage.getSnapshot(); // the returned object is a dynamic object reference of the BufferedImage object in Java |
88 | | -var isContentLost = volImage.contentsLost(); // the returned object is a bool representing the Java counterpart |
89 | 100 |
|
| 101 | +// Creates a new ImageCapabilities instance in the JVM™; returns a dynamic reference |
| 102 | +var dynImageCapabilities = panel.JVM.New("java.awt.ImageCapabilities", true); |
| 103 | +// Returns a dynamic reference to the VolatileImage object in the JVM™ |
| 104 | +var volImage = panel.IExecute("createVolatileImage", 100, 100, dynImageCapabilities); |
| 105 | +// Returns a dynamic reference to the BufferedImage object in the JVM™ |
| 106 | +var snapshot = volImage.getSnapshot(); |
| 107 | +// Returns a bool — the Java boolean is automatically converted |
| 108 | +var isContentLost = volImage.contentsLost(); |
90 | 109 | ``` |
91 | 110 |
|
92 | | -In the above example the class `ImageCapabilities` is not implemented yet. Since it exists in the JVM™ it can be allocated and used. |
93 | | -Each object, like `Panel` instance, exposes (hidden in the editor) two properties: |
94 | | -* **JVM** which access the JVM™ using methods; |
95 | | -* **DynJVM** which access the JVM™ using the Dynamic engine. |
96 | | - |
97 | | -Using the listed properties it is possible to instruct the JVM™ about the action to be done. |
| 111 | +`ImageCapabilities` is not mapped in JNet, but since it exists in the JVM™ it can be instantiated |
| 112 | +and passed as an argument without any additional setup. |
98 | 113 |
|
99 | | -### Anything is not available |
| 114 | +Each JNet object exposes two properties for direct JVM™ interaction (intentionally hidden in editor |
| 115 | +autocompletion to reduce noise): |
100 | 116 |
|
101 | | -If no classes are available the solution comes from the global accessor available in JCOBridge and the code snippet is like the following one: |
| 117 | +* **`JVM`** — a typed interface with properties and methods for structured JVM™ access; use this |
| 118 | + when you need explicit control (e.g. `JVM.New(...)` to instantiate a class). |
| 119 | +* **`DynJVM`** — returns a `dynamic` object bound to the JVM™ instance; use this for fluent, |
| 120 | + untyped method calls. |
102 | 121 |
|
103 | | -```C# |
104 | | -var panel = JNetCore.New("java.awt.Panel"); // the returned object is a dynamic object reference of the Panel object in Java |
105 | | -var dynImageCapabilities = JNetCore.New("java.awt.ImageCapabilities", true); // the returned object is a dynamic object which is a reference of the ImageCapabilities object in Java |
106 | | -var volImage = panel.createVolatileImage(100, 100, dynImageCapabilities); // the returned object is a dynamic object which reference the VolatileImage object in Java |
107 | | -var snapshot = volImage.getSnapshot(); // the returned object is a dynamic object reference of the BufferedImage object in Java |
108 | | -var isContentLost = volImage.contentsLost(); // the returned object is a bool representing the Java counterpart |
| 122 | +### Anything is not available |
109 | 123 |
|
| 124 | +If no classes are mapped at all, use the global accessor available on `JNetCore`: |
| 125 | + |
| 126 | +```csharp |
| 127 | +// Creates a new Panel instance in the JVM™; returns a dynamic reference |
| 128 | +var panel = JNetCore.New("java.awt.Panel"); |
| 129 | +// Creates a new ImageCapabilities instance in the JVM™; returns a dynamic reference |
| 130 | +var dynImageCapabilities = JNetCore.New("java.awt.ImageCapabilities", true); |
| 131 | +// Returns a dynamic reference to the VolatileImage object in the JVM™ |
| 132 | +var volImage = panel.createVolatileImage(100, 100, dynImageCapabilities); |
| 133 | +// Returns a dynamic reference to the BufferedImage object in the JVM™ |
| 134 | +var snapshot = volImage.getSnapshot(); |
| 135 | +// Returns a bool — the Java boolean is automatically converted |
| 136 | +var isContentLost = volImage.contentsLost(); |
110 | 137 | ``` |
111 | 138 |
|
112 | | -The example above consider that even the class `Panel` is not implemented yet. Since it exists in the JVM™ it can be allocated and used. |
113 | | -In previous chapter the tutorial reports about two hidden properties in each object; the properties on each class are just an useful reference to the real one available in `JCOBridge.Global`: |
114 | | -* **JVM** which access the JVM™ using methods; |
115 | | -* **DynJVM** which access the JVM™ using the Dynamic engine. |
| 139 | +This example assumes even `Panel` is not mapped. Since it exists in the JVM™, it can be instantiated |
| 140 | +and used via `JNetCore.New(...)`. |
116 | 141 |
|
117 | | -Using the properties it is possible to instruct the JVM™ about the action to be done. |
| 142 | +The `JVM` and `DynJVM` properties on each object are convenience references to the underlying |
| 143 | +`JCOBridge.Global` accessor: |
118 | 144 |
|
119 | | -### Call a method dynamically |
| 145 | +* **`JVM`** — typed interface with properties and methods for structured JVM™ access. |
| 146 | +* **`DynJVM`** — returns a `dynamic` object for fluent, untyped calls. |
120 | 147 |
|
121 | | -Look at the simple example below: |
| 148 | +### Call a method dynamically |
122 | 149 |
|
123 | | -```C# |
| 150 | +The `DynJVM` property also exposes `DynInstance`, which allows dynamic invocation on the specific |
| 151 | +object instance: |
124 | 152 |
|
| 153 | +```csharp |
125 | 154 | Java.Awt.Panel panel = new(); |
126 | | -var result = panel.DynInstance.getLayout(); // this line invokes dynamically the getLayout method on the instance of the Panel |
127 | 155 |
|
| 156 | +// Dynamically invokes getLayout() on the Panel instance |
| 157 | +var result = panel.DynInstance.getLayout(); |
128 | 158 | ``` |
129 | 159 |
|
130 | | -As exposed before, each object, like `Panel` instance, exposes (hidden in the editor) two properties. |
131 | | - |
132 | 160 | Explaining the code: |
133 | | -* The first line creates a JVM™ object in C# style: `Container` lives in the CLR and has its counterpart in the JVM™. |
134 | | -* The `result` is a **dynamic** object that can be used to extract data or invokes other methods on the result of `getLayout` which is an object of type `LayoutManager`. |
| 161 | +* The first line creates a JVM™ object in C# style: `Container` (the base class of `Panel`) lives |
| 162 | + in the CLR and has its counterpart in the JVM™. |
| 163 | +* `result` is a `dynamic` object representing a `LayoutManager` instance in the JVM™. It can be |
| 164 | + used to read properties or invoke further methods. |
| 165 | + |
| 166 | +## API extensibility limitations |
| 167 | + |
| 168 | +JCOBridge does not perform any code injection or compilation on the JVM™ side. The only hard |
| 169 | +limitation is therefore related to **callbacks**: a callback requires a concrete class in the JVM™ |
| 170 | +that implements the target interface and calls back into the CLR. |
| 171 | + |
| 172 | +**If no such concrete class exists in the JVM™, the callback cannot be used from JNet.** |
135 | 173 |
|
136 | | -## API exendibility limitation |
| 174 | +See the [JVM™ Callbacks](jvm_callbacks.md) article for a full explanation of how callbacks work |
| 175 | +and how to implement them. |
137 | 176 |
|
138 | | -Starting from the assumption that JCOBridge does not make any code injection, or compilation, within JVM™ side, the actual limitation is related to something missing within the JVM™. |
139 | | -In the [JVM™ callbacks](jvm_callbacks.md) article there is an explanation of how works callbacks. |
140 | | -**The callback feature needs a concrete class in the JVM™ and if it does not exist there is no way to use it from JNet.** |
| 177 | +> [!NOTE] |
| 178 | +> If you need a callback against a Java™ interface that has no concrete JVM™ implementation in |
| 179 | +> JNet yet, consider contributing one following the patterns described in |
| 180 | +> [JVM™ Callbacks](jvm_callbacks.md). |
0 commit comments