In my first entry about what to add to DJN 2.1+, I though I had a pretty complete list of “important” features. But I forgot this one…
Important features
-
Be able to receive hererogenous data in Java methods
What do I mean? Sometimes it happens that you really truly have to handle data of an unknown type, much like
myFunction
does:MyRemoteThing.myFunction( 55, .... ); MyRemoteThing.myFunction( "hello", ... ); MyRemoteThing.myFunction( {value1:33, value2:"Unknown"}, ... ); MyRemoteThing.myFunction( [5, "bye"] ); MyRemoteThing.myFunction( [1, "anyway", {value1:33, [33, null, 5], value2:"Unknown"}], ... );
Here,
myFunction
has to handle a number, then aString
, an object, then an array, and finally an array containing numbers, strings and even an object that contains itself another array. Yuk!How are we going to handle this monster in the Java side? Well, up until now you had to write a method to receive the almost raw json (a
JsonArray
parameter), as generated by Gson, and process it on your own.My proposal is to write a Java method with this signature:
@DirectMethod public void myFunction( Object param ) { // ... }
Now, what will DJN pass to the poor
myFunction
method? Let’s dive into each case:-
myFunction( 55, ...)
Here
param
will be aDouble
set to55.0
.Not an
Integer
, mind you, because we need to honour the fact that json numbers can have fractional part. There is no separated integral numeric type in json. -
myFunction( "hello", ... )
Here
param
will be aString
set to"hello"
. -
myFunction( {value1:33, value2:"Unknown"}, ... )
Hereparam
will be aMap<String,Object>
with two entries, a"value1"
key with aDouble
value set to33.0
, and a"value2
” key with aString
value set to"unknown"
. -
myFunction( [5, "bye"] )
Hereparam
will be an array of objects (Object[]
), with two elements: aDouble
set to5.0
and aString
set to"bye"
.I think that arrays will be used most of the time to pass elements of the same type: always numbers, always strings, etc.
This contrived example just illustrates the whole potential -that includes potential for mess, of course.
-
myFunction( [1, "anyway", {value1:33, [33, null, 5], value2:"Unknown"}], ... )
You’ve got the idea by now. Here the method will receive an array of objects, the third one will be a
Map<String,Object>
, etc.I do not think this last scenario will be very popular, but it shows how far we can go if we need to.
But this is *dirty* Java…!
Agreed!
Yes, this function is not a very good Java-world citizen, what the hell does
myFunction
think it is doing? Since when is working withObject
a good idea? Because anObject
is just an alias for whatever, right?And, in fact, a very important goal for DirectJNgine was to provide and almost enforce a degree of type safety at the server side, and that’s why I have not implemented this kind of functionality up until now: if you write a server function that receives an
Object
, it will not work because DJN considers there is not much one can meaningfully do with whatever, so it almost forces you to devise a class that organizes your data.Even then, I provided the JSonArray backdoor to allow the server side to receive whatever, because sometimes you have very special needs.
…so, why allow this level of exposure?
Have I changed my mind? Is untyped data good nowadays?
No, not at all. It just happens that my mind has expanded. Well, maybe I have changed my mind -but just a tiny bit 🙂
Here is my reasoning.
Firstly, having to handle the json itself is not too difficult, but neither is it very easy. For example, for moderately complex structures you will need a bit of recursion to process the JsonArray with the underlying json. I know people will like me better if I write that code for them.
Secondly, a guy might tell me this: “ok, I understand you are making it difficult for me to mess with data in the whatever format. Limits can be good. But sometimes I inherit the mess. In fact, I’ve got that nice UI component from Joe: it allows end users to edit multiple items easily…but it will handle me data of whatever type. Sometimes the user will edit a string, sometimes a number, etc. And *I* don’t want to have to rearrange the data to make it fit a type-safe but uber-complex class I have to invent to make Java happy just once”.
Well, that seems reasonable.
Besides, one might think that, if there is a need to massage very complex data to make it amenable to complex processing, it might be better to massage it at the Java side, where you have all those Java utility libraries that have no Javascript equivalent. In that scenario, it might be better to pass raw data to the Java side and clean the mess there.
That said, let me tell you that I still feel it will be bad style to allow highly unstructured data to get deep into the business core (unless it is just to be stored as-is and handled back the same way), and that most of the time you can be well served by defining a handful of helper data-only classes to structure the information.
Yes, that’s me: I am a quality code bigot that enjoys Test Driven Development like there is no tomorrow.
A pair of little details to take into account
I expect two scenarios to be very common:
- Handling arrays, essentially acting as a collection of items of the same type, whatever that might be.
- Handling objects as bags of properties, probably of different types.
To enforce those scenarios you will find it nice to be able to write your Java function so that it takes anObject[]
(scenario 1) orMap<String,Object>
(scenario 2), not a rawObject
. That makes the intent clear and helps with type safety.Caveat emptor & more to come
Of course, I’m just thinking aloud, though I would very much like to implement this given some spare time. Maybe in DJN 2.3.
There are still other features that, if not important, would be nice to have. So a third entry about post 2.1 DJN future is guaranteed.
-