Deep dive into Javonet.io!

Tags

In this post, I want to dive deeper into how the already generated (with Javonet.io) Java wrapper of the .NET dll works and show the differences in usage between .NET and JAVA.

If you want to learn more about the basics, such as how to generate and use the wrapper, go to this post. As in the previous post, I’ll be using a project available on GitHub, https://github.com/lberwid/JIODotnetSampleProject, which contains all the things I’ll describe.

If you want, you can download it and test it yourself. Just remember that to make the wrapper work, you will need a Javonet account (if you don’t have any, go to https://my.javonet.com/signup/ to get a free trial license).

The topics that will be discussed are:

  • Events and delegates
  • Generics
  • Arrays

EVENTS
Let’s begin with subscribing to .NET Events from JAVA code.

I’ve created a simple AlarmClock class, which is available in the Events folder in the repository:

public class AlarmClock 
{
 public void Start()
 {
   AlarmEventArgs e = new AlarmEventArgs(false, 0);
   OnAlarm(e);
 }

 

public class AlarmClock 
{
 public void Start()
 {
   AlarmEventArgs e = new AlarmEventArgs(false, 0);
   OnAlarm(e);
 }

public event AlarmEventHandler Alarm;

 protected virtual void OnAlarm(AlarmEventArgs e)
 {
  if (Alarm != null) 
  Alarm(this, e); 
 }
}
public class AlarmEventArgs
{
 private string text = "The alarm is ringing!";
        
 public string AlarmText {  
 get { return text; }
 }
}

public delegate void AlarmEventHandler(object sender, AlarmEventArgs e);

Let’s compare the way we subscribe to events from .NET and from JAVA:

.NET

var clock = new AlarmClock();
     clock.Alarm += (sender, e) => Console.WriteLine(e.AlarmText);
     clock.Start();

JAVA

AlarmClock clock = new AlarmClock();
clock.addAlarm((o, alarmEventArgs) -> System.out.println(alarmEventArgs.getAlarmText()));
clock.Start();

Clearly, the only difference is in the syntax of both languages, but the method invocation is virtually the same. In both cases, we’ll get the same result.

ARRAYS
Let’s see how to use .NET arrays in JAVA. I’ve created a simple class that contains two methods, one creating a range of numbers and one summing the elements of an array:

public class ArrayClass
{
 public int SumArray(int[] a)
 {
  return a.Sum();
 }

 public int[] Sequence(int n)
 {
  return Enumerable.Range(0, n).ToArray();
 }
}

Let’s compare how to use it from .NET and from JAVA:

.NET

var a = new ArrayClass();
      var s = a.Sequence(3);
      Console.WriteLine(a.SumArray(s));

JAVA

ArrayClass a=  new ArrayClass();
Integer[] x = a.Sequence(10, Integer.class);
System.out.println(a.SumArray(x));

By default, Javonet handles every type of array as an array of objects. Because we are converting to a concrete type, we need to specify the type of array element we expect. In both cases, the result will be:

Later, you can work with native JAVA arrays in the way you normally do. Just remember that you use boxed types instead of simple types.

Generics
The last topic of today’s post is how to use .NET generics in JAVA. Because one of the best examples of using generics from .NET is the use of generic collections, I’ll show how to work with a .NET collection in JAVA. What’s more, I’ll show you that you can use a .NET collection as a JAVA inerrable collection, utilizing, for example, a Foreach loop. The following is a class that returns a generic dictionary:

public class ClassUsingCollections
{
 public Dictionary<int, List> GetDictionary()
 {
  var l = Enumerable.Range(1, 10).ToList();
  var res = new Dictionary<int, List>();

 for (int i = 0; i < l.Count(); i++)
 {
  res.Add(i, l);    
 }

 return res;
 }
}

Let’s compare how to use it from .NET and from JAVA:

.NET

var a = new ClassUsingCollections();
var dict = a.GetDictionary();
foreach (var elem in dict)
{
 Console.WriteLine(elem.Key + " : " + string.Join(",", elem.Value));
}

JAVA

ClassUsingCollections a = new ClassUsingCollections();
Dictionary<Integer, List> dict = a.GetDictionary();

for (KeyValuePair<Integer, List> z : dict) {
      System.out.println(z.get_Key(Integer.class) +
" : " +
             JoinString(z.get_Value(List.class)));
}

As you can see, the code becomes slightly different now. That’s because of the big difference in the way .NET and JAVA handle generic types. If our method returns a generic type, we need to specify the type in the function call. But as you can see, in both cases we can use complex .NET collections, such as Dictionary<T,K> or List, directly from the JAVA code. In both cases, the output is the same.

For the purpose of the example above, I’ve created a helper method to aggregate a list of integers:

static public String JoinString(List list)
{
 StringBuilder sb = new StringBuilder();
 boolean first = true;
 for (Integer item : list)
 {
  if (first)
  first = false;
 else
  sb.append(",");
  sb.append(item);
 }
 return sb.toString();
}

For now, our wrapper classes don’t inherit from the BaseStream JAVA interface. On the other hand, we are also not embedding support in the wrappers for all the .NET goodies, such as LINQ or in this case the string.Join function, but both of these will surely be dealt with in the future. The first one because it’s necessary, and the second one just because we can ?

Hope you liked this post. Thanks for staying with me so far. Please go to Javonet.io and test the wrapper yourself!