Skip to content

Instantly share code, notes, and snippets.

@javajosh
Created June 18, 2013 17:37
Show Gist options
  • Save javajosh/5807560 to your computer and use it in GitHub Desktop.
Save javajosh/5807560 to your computer and use it in GitHub Desktop.
Doing groovy stuff
//Groovy has some nice features that make constructing new objects from maps.
//This file explores some of the ways we can get to collections, and nested collections of correctly typed objects.
class Player{
String name
int seat
}
Player alice = [name: "alice", seat: 3] as Player
assert (alice instanceof Player)
//That's great.
// Now let's see if we can instantiate a list of players.
List<Player> players = [[name: "alice", seat: 3], [name: "bob", seat: 4]] as List<Player>
assert (players instanceof List<Player>) //this is true
assert !(players.first() instanceof Player) //this is false, alas :(
//Can we fix this type problem in code?
players = players.collect(new ArrayList<Player>()) {it as Player}
assert (players instanceof List<Player>) //this is true
assert (players.first() instanceof Player) //yay!
// Now we want to define a Game that has a bunch of players. How does that work?
class Game1{
int id
List<Player> players
}
Game1 game1a = [id: 1, players:[[name: "alice", seat: 3], [name: "bob", seat: 4]]] as Game1
assert (game1a instanceof Game1)
assert (game1a.players.first() instanceof LinkedHashMap) //boo
//So, we can construct the Game, but the players member is not of the correct type. How do we make it a list of players?
//Let's try using a nested 'as' Keyword.
Game1 game1b = [id: 1, players:[[name: "alice", seat: 3], [name: "bob", seat: 4]] as List<Player>] as Game1
assert (game1b.players.first() instanceof LinkedHashMap)
//No, that had no effect. And for our use case it's not very helpful anyway even if it did work.
//Let's use our trick from above on the game.players member...
game1b.players = players.collect(new ArrayList<Player>()) {it as Player}
assert (game1b.players.first() instanceof Player) //sweet
//Unfortunately, we can't put that code in a constructor AND get the nice automatic property matching. So we resort to
//an init() method.
class Game2{
int id
List<Player> players
void init(){
players = players.collect(new ArrayList<Player>()) {it as Player}
}
}
Game2 game2 = [id: 1, players:[[name: "alice", seat: 3], [name: "bob", seat: 4]]] as Game2
assert (game2 instanceof Game2)
game2.init()
assert (game2.players.first() instanceof Player)
//That's nice, except we have that annoying method call! Is there any way to avoid that?
//With this we'll use a Map constructor...
class Game3{
int id
String name
List<Player> players
Game3(Map m){
this.id = m.id
this.name = m.name
players = m.players.collect(new ArrayList<Player>()) {it as Player}
}
}
Game3 game3 = [id: 1, players:[[name: "alice", seat: 3], [name: "bob", seat: 4]]] as Game3
assert (game3 instanceof Game3)
assert (game3.players.first() instanceof Player)
//Very cool! But we don't want to have to make constructors like that. Can we do better?
//The answer is "maybe" with some fancy meta programming involving accessing fields programmatically.
//But I think the better solution is to just bite the bullet and make a map constructor.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment