Is it a Message, JsonObject or HashMap in Groovy?

1,003 views
Skip to first unread message

bytor99999

unread,
Oct 8, 2012, 5:04:58 PM10/8/12
to ve...@googlegroups.com
So one of the biggest issues with a dynamic language like Groovy and I suspect maybe JavaScript is that you don't type things and expect that passing stuff around just works. Like I have a closure/function that takes two parameters and if on another line I call that closure/function passing two parameters that it would get called without any exception saying "wrong type"

But for some reason I am getting such exceptions. And it is a bit frustrating to figure how to make your Groovy code dynamic with just "def" or just parameter names in closures and getting those methods called.

Example

def someMethod(data) {
    def someClosure = {lookupResults ->
        if ("ok".equals(lookupResults.status)) {
            def document = lookupResults.result
            documentManipulator.joinDataToDocument(document, data)
        }
    }
    commonActionClosure data, someClosure
}

and the definition of documentManipulator.joinDataToDocument(document, data) looks like

    JsonObject joinDataToDocument(document, dataRequest) {
        // do some work here
    }

So the joinDataToDocument parameters aren't typed, but now when I try to run the code I get.

Exception in Groovy verticle 
groovy.lang.MissingMethodException: No signature of method: com.site.transformer.DocumentManipulator.joinDataToDocument() is applicable for argument types: (java.util.HashMap, java.util.HashMap) values: [[spectators:[count:0], _id:09971b6e-5745-4f29-aa59-67e6d5a7d754, ...], ...]
Possible solutions: joinDataToDocument(org.vertx.java.core.json.JsonObject, java.lang.Object)

Now a big part of this is just how Groovy works. But I also find that I am creating these methods expecting the object type from receiving off the eventBus to be JsonObject, since that is the type that I passes to the send() method. I know when I receive from NetSocket, that is always a Buffer. But internally when I use the bus to pass data between verticles, I want them to be JsonObject type. But sometimes when I pass JsonObject I get on the receive side a HashMap, sometimes I get Message, and sometimes I actually get JsonObject and I can't figure out why it is different.

Thanks

Mark

bytor99999

unread,
Oct 8, 2012, 5:27:49 PM10/8/12
to ve...@googlegroups.com
A lilttle more in context. What is actually happening is I send a find message to the MongoDBPersister, and pass in a closure/callback that get the "lookupResults" This is coming back (sent to the callback) as a HashMap, not as a JsonObject or Message.

Mark

Tim Fox

unread,
Oct 9, 2012, 4:31:00 AM10/9/12
to ve...@googlegroups.com
Some languages have natural support for JSON in the form of literals.

The obvious case is JavaScript where a JSON object is just a standard object, and therefore it maps to an object literal, e.g.:

var someJson = { foo: "bar"};

Ruby, Groovy, and Python have support for Map (Hash) Literals, so that's a natural way to express Json objects in those languages

{ 'foo' => 'bar'}  # Ruby - this is a Hash

{ foo: 'bar'} // Groovy - this is a Map

{ 'foo': 'bar'} // Python - this is a Hash

Unfortunately Java has no support for Map literals (or anything similar). So if we mapped a Json object to a Map in Java you'd have to do something like this:

Map<String, Object> map = new HashMap<>();
map.put("foo", "bar");

Which I think you agree is pretty ugly.

For this reason, I created the class JsonObject. The idea behind this is its a more natural way to represent a JsonObject when you're programming in Java (it has typed methods for putting etc).

JsonObject is only really intended for use in Java verticles, and is automatically converted back and forth to to the more natural types when passed to other languages.

So if you're sending a JsonObject from Java you should expect to receive it as a Map in Groovy, an object in Java, an object in Python etc. And if you send an object from Java or a Map in Groovy you should receive it as a JsonObject in Java.

Brian Lalor

unread,
Oct 9, 2012, 5:25:06 AM10/9/12
to ve...@googlegroups.com
On Oct 9, 2012, at 4:31 AM, Tim Fox <timv...@gmail.com> wrote:

For this reason, I created the class JsonObject. The idea behind this is its a more natural way to represent a JsonObject when you're programming in Java (it has typed methods for putting etc).

About that: since you're using Jackson behind the scenes, why not use Jackson's ObjectNode and ArrayNode classes instead of your home-grown versions?  It could be those only came about from Jackson 2 and Vert.x uses 1.something…

Tim Fox

unread,
Oct 9, 2012, 6:41:19 AM10/9/12
to ve...@googlegroups.com
Because I didn't want to expose any 3rd party libraries through the Vert.x API. It's the same reason we don't use Netty buffers directly, and have our own buffer construct.

bytor99999

unread,
Oct 10, 2012, 1:39:52 PM10/10/12
to ve...@googlegroups.com
OK, that helps explain a bit about JsonObject versus it being a HashMap. But why sometimes it ends up being a vertx Message instead. And I can't quite seem to see a pattern of when I get Message over the Map/JsonObject stuff.

Thanks

Mark

Gyula Szalai

unread,
Oct 10, 2012, 2:00:32 PM10/10/12
to ve...@googlegroups.com
As far as I know, in Groovy verticles all handler closures get a Message<Map> parameter, like this:

import org.vertx.groovy.core.eventbus.Message

eventBus
.send("mongo-persistor", mongoRequest) { Message<Map> mongoReplyEvent ->
   
Map mongoReply = mongoReplyEvent.body
}

Of course, you don't have to specify the closure argument type, but it comes handy as you get code completion.
BTW, Groovy uses LinkedHashMap by default if you create a Map literal, so field order is preserved.

Hope this helps.

Gyula

bytor99999

unread,
Oct 10, 2012, 3:04:33 PM10/10/12
to ve...@googlegroups.com
Yes that helps a lot. So on the bus everything in Groovy is a Message. I see that now, based on the code I needed to do in all callbacks to get .body.

Thanks

Mark

Tim Fox

unread,
Oct 11, 2012, 3:10:00 AM10/11/12
to ve...@googlegroups.com
In Groovy the thing you receive in a handler is a Message, and the body
is a HashMap.

This is because you need some way of replying to the message, and the
reply method is on the Message object.

It's very similar in Java and Ruby.

In JS a function is passed in as an extra parameter which enables you to
reply, this is more natural as JS supports first class functions.
> --
> You received this message because you are subscribed to the Google
> Groups "vert.x" group.
> To view this discussion on the web, visit
> https://groups.google.com/d/msg/vertx/-/H27-89AR1pIJ.
> To post to this group, send an email to ve...@googlegroups.com.
> To unsubscribe from this group, send email to
> vertx+un...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/vertx?hl=en-GB.


--
Tim Fox

Vert.x - effortless polyglot asynchronous application development
http://vertx.io
twitter:@timfox

Reply all
Reply to author
Forward
0 new messages