1. Getting started
- 1.1. Installing Javonet
- 1.2. Activating Javonet
- 1.3. Adding References to .NET Libraries
- 1.4. XML Configuration File
- 1.5. Using the Javonet Fluent Interface
- 1.7. Introduction to Using .NET Back-end and UI Components in Java
2. Calling methods
- 2.1. Invoking Static Methods
- 2.2. Creating Instance and Calling Instance Methods
- 2.3. Calling Generic Methods
3. Working with .NET Objects
- 3.1. Creating Instance Of Generic Object
- 3.2. Extending the .NET Class in Java and Wrapping .NET Methods
4. Fields and Properties
- 4.1. Get/Set Values for Static Fields and Properties
- 4.2. Get/Set Values for Instance Fields and Properties
5. Methods Arguments
- 5.1. Passing Reference-Type Arguments
- 5.2. Passing Arguments by Reference with “ref” and “out” Keywords
- 5.3. Passing typeof(Type) as Method Argument
- 5.4. Calling Overloaded Method Passing Null Argument
6. Nested Types
7. Enums
8. Arrays and Collections
- 8.1. Arrays: Using Value-Type and Reference-Type Arrays
- 8.2. Working with .NET arrays and collections from Java with Javonet
9. Embeding UI controls
10. Referencing libraries
11. Off-line activation
12. Events and Delegates
13. Disposing and Garabage Collection
14. .NET Configuration Files (AppConfig, WebConfig)
15. Exceptions, Debugging and Testing
- 15.. Handling Activation Issues
- 15.1. Handling .NET Exceptions
- 15.2. How to debug .NET code called from Java
- 15.3. Debugging Javonet Enabled Application
16. Strongly-Typed Wrappers
17. Advanced Activation and Licensing
- 17.1. Runtime vs. Offline vs. Compile Time Activation
- 17.2. Project Activation Tool
- 17.6. Delegating Activation Server
18 Other usage scenarios
Working with .NET arrays and collections with Javonet
Data structures are one of the essential aspects of every piece of software that has ever been written. Any
application, from simple command line util to scalable enterprise systems, constantly process various
information, that very often require specific grouping and access strategies. This aspect is addressed by
arrays and more advanced collection types available both in Java and .NET environments. By using the
Javonet framework, Java users gain ability to easily and effectively work with data structures originating
from .NET platform.
Workspace
For better readability, I’ll present respective code fragments, as we need them. From the perspective of the
Java program, that I’ll be using throughout the examples, the main method’s skeleton is as follows:
public static void main(String[] args) throws JavonetException { Javonet.activate(License.EMAIL, License.LICENSE_KEY, JavonetFramework.v45); Javonet.reference(Constants.DLL_FILE_PATH); useIntArrayExample(); getIntArrayExample(); getArrayOfIntArraysExample(); useCustomObjectArrayExample(); getCustomObjectArrayExample(); getArrayOfCustomObjectArraysExample(); useListExample(); getListExample(); useSetExample(); getSetExample(); useDictionaryExample(); getDictionaryExample(); }
My aim here is to extract code for Javonet framework activation and referencing our .NET library as a
common part of all the examples.
Working with Arrays
During the array part of this tutorial, I’ll be working with the following pseudo-service class, which main
purpose is to produce and consume various array-typed objects.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ArraysAndCollections { class ArrayService { public int[] GetIntArray() { return new int[]{ 1, 2, 3, 4 }; } public void UseIntArray(int[] intArray) { Console.WriteLine("[.NET] Contents of primitive-type array:"); foreach (int intVal in intArray) { Console.WriteLine("{0} ", intVal); } } public int[][] GetArrayOfIntArrays() { int[][] arrayOfIntArrays = new int[2][]; arrayOfIntArrays[0] = new int[4] { 1, 2, 3, 4 }; arrayOfIntArrays[1] = new int[4] { 11, 22, 33, 44 }; return arrayOfIntArrays; } public CustomObject[] GetCustomObjectArray() { return new CustomObject[]{ new CustomObject("A",1), new CustomObject("B", 2), new CustomObject("C", 3)}; } public void UseCustomObjectArray(CustomObject[] cuArray) { Console.WriteLine("[.NET] Contents of the reference-type array:"); foreach (CustomObject cu in cuArray) { Console.WriteLine("{0}[{1}] ", cu.Name, cu.Value); } } public CustomObject[][] GetArrayOfCustomObjectArrays() { CustomObject[][] arrayOfCustomObjectArrays = new CustomObject[2][]; arrayOfCustomObjectArrays[0] = new CustomObject[]{ new CustomObject("A1",1), new CustomObject("A2", 2), new CustomObject("A3", 3)}; arrayOfCustomObjectArrays[1] = new CustomObject[]{ new CustomObject("B1",1), new CustomObject("B2", 2), new CustomObject("B3", 3)}; return arrayOfCustomObjectArrays; } } class CustomObject { public String Name { get; set; } public int Value { get; set; } public CustomObject(String name, int value) { this.Name = name; this.Value = value; } } }
Retrieving and handling .NET array
Javonet framework allows for simple retrieval of arrays of objects from .NET code, as presented in the
following examples. Such objects are treated as usual Java arrays, therefore all the standard Java
programming techniques apply. Although examples present objects’ retrieval in result to method calls, the
same approach is applicable for getting class properties, direct member access etc.
It’s worth mentioning that, when dealing with primitive, value-typed .NET arrays, Javonet framework
automatically translates them to respective Java primitive type. In such cases, it is necessary to keep in
mind, that the returned array will contain boxing-type objects, otherwise we might face an
InvalidClassCastException.
static void getIntArrayExample() throws JavonetException{ NObject arrayService = Javonet.New("ArrayService"); Integer[] intArray = arrayService.invoke("GetIntArray"); System.out.format("[Java] Contents of primitive-type array: %n"); for (int intVal : intArray){ System.out.format("%d%n", intVal); } }
As for .NET arrays containing reference-type objects, we’re simply dealing with an NObject array. Working
with such object is no different that for any other NObject provided by the framework from the .NET code.
static void getCustomObjectArrayExample() throws JavonetException{ NObject arrayService = Javonet.New("ArrayService"); NObject[] coArray = arrayService.invoke("GetCustomObjectArray"); System.out.format("[Java] Contents of reference-type array: %n"); for (NObject co : coArray){ System.out.format("%s[%d]%n", co.get("Name"), co.get("Value")); } }
In the previous examples, we’ve been retrieving a single-dimensional arrays. It is possible however, to get
an array of arrays, either for primitive- and reference-type objects. Here are the examples:
Value-typed nested arrays:
static void getArrayOfIntArraysExample() throws JavonetException{ NObject arrayService = Javonet.New("ArrayService"); NObject[] arrayOfIntArrays = arrayService.invoke("GetArrayOfIntArrays"); System.out.format("[Java] Contents of primitive-type array of arrays: %n"); for (NObject intArray : arrayOfIntArrays){ for (int i = 0; i < intArray.<Integer>get("Length"); i++){ System.out.format("%s ", intArray.<Integer>getIndex(i)); } System.out.println(); } }
Reference-type nested arrays:
static void getArrayOfCustomObjectArraysExample() throws JavonetException{ NObject arrayService = Javonet.New("ArrayService"); NObject[] arrayOfCOArrays = arrayService.invoke("GetArrayOfCustomObjectArrays"); System.out.format("[Java] Contents of reference-type array of arrays: %n"); for (NObject coArray : arrayOfCOArrays){ for (int i = 0; i < coArray.<Integer>get("Length"); i++){ NObject co = coArray.getIndex(i); System.out.format("%s[%d] ", co.get("Name"), co.get("Value")); } System.out.println(); } }
Unfortunately, current version of Javonet framework does not support retrieval of arrays containing arraytype
objects, nested more than once. Also, the multidimensional arrays (in the .NET way of things) are not
supported either. Thankfully, despite the fact, that such cases are not that common and/or easy
workarounds exist, it is considered as viable enhancement, which most probably will be shipped in one of
the upcoming versions.
Passing .NET array
Being aware of the automatic type conversion for value-typed arrays, it is absolutely safe to pass regular
Java arrays as arguments to the .NET code. Similarily as when retrieving primitive arrays, it is necessary to
work with the boxed wrappers.
static void useIntArrayExample() throws JavonetException{ NObject arrayService = Javonet.New("ArrayService"); Integer[] intArray = { 1, 2, 3, 4}; arrayService.invoke("UseIntArray", new Object[]{intArray}); }
In case we need to send a reference-type array, all we need to do is create an array of NObjects and
populate it, as shown in the next example.
static void useCustomObjectArrayExample() throws JavonetException{ NObject arrayService = Javonet.New("ArrayService"); NObject[] cuArray = { Javonet.New("CustomObject", "D", 1), Javonet.New("CustomObject", "E", 2) }; arrayService.invoke("UseCustomObjectArray", new Object[]{cuArray}); }
Unlike the array-retrieval scenario, sending nested arrays is not supported at the moment, it is however
considered for shipment, depending on the demand for such feature.
Working with collections
For the collection part of this tutorial, I’ll be using the following .NET class. Similarily as in the previous
section, this code’s main responsibility is to produce and consume various collection types.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ArraysAndCollections { class CollectionService { public IList<string> GetList() { return new List<string> { "strings", "in", "list", "from", ".NET" }; } public void UseList(List<string> list) { Console.WriteLine("[.NET] List contents:"); foreach (string element in list) { Console.WriteLine("{0} ", element); } } public <string> GetSet() { return new HashSet<string>{"strings", "in", "set", "from", ".NET"}; } public void UseSet(ISet<string> set) { Console.WriteLine("[.NET] Set contents:"); foreach (string element in set) { Console.WriteLine("{0} ", element); } } public IDictionary<string, string> GetDictionary() { return new Dictionary<string, string>() { {"key1","value1"}, {"key2","value2"}, {"key3","value3"} }; } public void UseDictionary(IDictionary<string, string> dictionary) { Console.WriteLine("[.NET] Dictionary contents:"); foreach (string key in dictionary.Keys) { Console.WriteLine("'{0}' = '{1}'", key, dictionary[key]); } } } }
Retrieving and handling .NET collections
As it is easy to guess, .NET collection-type objects retrieved by the Javonet framework, are accessible via
the NObject class instances on the Java side. Therefore working with these objects is really simple, as I’ll
show in the next few examples.
Thefollowing code retrieves an instance of a Set<String> class by invoking the parameterless “GetSet”
method of the CollectionService object. We can access various attributes of our set with the
NObject.get(String propertyName, Object… args) or invoke any of its availablbe methods using
NObject.invoke(String methodName, Object… args). It’s worth mentioning that the result type of
these methods can be parametrized, relieving us from manual type-checking-and-casting steps.
In the example below, we’re using this approach to check the size of the received Set<String> object, as
well as use the collection enumerator object, to iterate over the contained strings. Unfortunately, as the
NObject class doea not implement Java Iterable interface, it is not possible to simply use the NObject in
the for-each loop. Also, since set does not allow for index-based access to the contained elements, using
enumerator can be considered primary method of collection traversal.
static void getSetExample() throws JavonetException{ NObject collectionService = Javonet.New("CollectionService"); NObject list = collectionService.invoke("GetSet"); // check size System.out.format("[Java] Set size: %d%n", list.<Integer>get("Count")); // iterate over contents System.out.format("[Java] Set contents:%n"); NObject enumerator = list.invoke("GetEnumerator"); while (enumerator.<Boolean>invoke("MoveNext")){ String current = enumerator.get("Current"); System.out.format("%s%n", current); } }
In contrast to sets, lists and dictionaries do allow its users for selective access to the contained objects. For
this purpose, we’ll be using the NObject.getIndex(Object index) method, which is only applicable for
NObjects representing .NET types allowing for such access. In case you would try to invoke this method
on a non-indexed .NET object, Javonet framework will throw a JavonetException, stating that given .NET
class does not provide indexed values.
The following two examples present usage of this approach against List<String> and
Dictionary<String, String> objects retrieved from .NET code.
static void getListExample() throws JavonetException{ NObject collectionService = Javonet.New("CollectionService"); NObject list = collectionService.invoke("GetList"); // check size System.out.format("[Java] List size: %d%n", list.<Integer>get("Count")); // get arbitrary value assigned to given key System.out.format("[Java] Second element: %s%n", list.<String>getIndex(1)); // iterate over contents System.out.format("[Java] List contents:%n"); NObject enumerator = list.invoke("GetEnumerator"); while (enumerator.<Boolean>invoke("MoveNext")){ String current = enumerator.get("Current"); System.out.format("%s%n", current); } }
static void getDictionaryExample() throws JavonetException{ NObject collectionService = Javonet.New("CollectionService"); NObject dictionary = collectionService.invoke("GetDictionary"); // check size System.out.format("[Java] Dictionary size: %d%n", dictionary.<Integer>get("Count")); // get arbitrary value assigned to given key System.out.format("[Java] Value for '%s' key: %s%n", "key1", dictionary.getIndex("key1")); // iterate over contents System.out.format("[Java] Dictionary contents:%n"); NObject enumerator = dictionary.invoke("GetEnumerator"); while (enumerator.<Boolean>invoke("MoveNext")){ NObject current = enumerator.get("Current"); System.out.format("'%s' = '%s'%n", current.get("Key"), current.get("Value")); } }
Passing .NET collections
Sending collection-type objects from Java to .NET is no different from passing any other object. All we are
required to do is grab the NObject instance, representing specific .NET collection object and use it in the
method call. In the following example, we’ll instantiate, populate and send a simple .NET list of strings as
an argument to the “UseList” method of our .NET CollectionService object. This should result in printing
all of the list’s contents to standard output stream.
As I’ll be using parametrized versions of .NET collection types, I am assuming you are familiar with the
Javonet-way of instantiating such objects. In case you’re not, I strongly encourage you to have a look at
respective section of Quick Guide, available on the Javonet home page.
Similarily as when retrieving collections from .NET, the approach for sending NObject instances as
arguments of method calls, can also be applied for setting .NET object’s properties etc.
static void useListExample() throws JavonetException{ // get generic type with a single type-parameter NType listType = Javonet.getType("List`1", "String"); // instantiate new object of that type NObject list = listType.create(); // use object, to add dictionary entries list.invoke("Add", "Strings"); list.invoke("Add", "in"); list.invoke("Add", "the"); list.invoke("Add", "list"); list.invoke("Add", "from"); list.invoke("Add", "Java"); NObject collectionService = Javonet.New("CollectionService"); collectionService.invoke("UseList", list); }
Here’s another example in which we’re creating a Dictionary<String,String> object, populate it and
pass it as an argument to our .NET CollectionService object’s “UseDictionary” method. Exactly as in
previous example, we should get contents of our dictionary object in the standard output stream.
static void useDictionaryExample() throws JavonetException{ // get generic type with two type-parameters NType dictionaryType = Javonet.getType("Dictionary`2","String","String"); // instantiate new object of that type NObject dictionary = dictionaryType.create(); // use object, to add dictionary entries dictionary.invoke("Add", "key1","value1"); dictionary.invoke("Add", "key2","value2"); dictionary.invoke("Add", "key3","value3"); NObject collectionService = Javonet.New("CollectionService"); collectionService.invoke("UseDictionary", dictionary); }
Summary
In this article we’ve focused on working with .NET arrays and collections in Java code using Javonet
framework. As for array objects, differences of handling arrays of value- and reference-type objects have
been discussed, as well as framework’s current limitations have been presented. We’ve briefly explained
basic techniques of handling .NET collection objects, covering retrieval, enumeration- and index-based
access to their contents, as well as instantiation and usage as arguments in the method calls.