Rick

Rick
Rick

Thursday, February 13, 2014

Boon fromList, fromMap and fromJson



Boon gets some inspiration from Groovy and Python when dealing with maps and lists. It addition to adding slice notation and such.
Boon has first class support for converting between MapsListJSON and Java objects.

Overview of Employee object

Let me explain the best way I know how by showing you some code:
Let's say you have an Employee class like so:

Basic employee java object

    public static Class<Employee> employee = Employee.class;

    public static class Employee {
        String name;
        int age;
        Employee boss;
        List<Employee> reports;

This is a pretty run of the mill Java class. An employee has a name, an age, a boss and a list of direct reports (employees who report to him).

Employees in other formats (list, map, JSON)

When you are integrating with other systems via messaging, reading CSV files, getting data from the filesystem, etc. not everyone will express employees in the same way. The rise of XML and JSON is mainly due to the need to share data between disparate systems that might not have the exact same concept as you do of an employee.
Let's express the same employee data but this time lets just use vanilla List and Maps.
This employee is called Rick and we will store his info in rickList and rickMap as follows:

List rick and Map rick

        List<Object> rickList;
        Map<String, Object> rickMap;
Employee as a list:

Employee as a list

        /** Creating a list. */
        rickList = list( "Rick", 29, list( "Jason", 21 ) );

Employee as a map:

Employee as a map

        /** Creating a map. */
        rickMap = map(
                "name", "Rick",
                "age", 29,
                "boss", map( "name", "Jason", "age", 21 ) );

The function map and list are part of the Boon core lib. They help you create maps (java.util.Map) and lists (java.util.List) easily. It is not exactly map and list literals like Groovy, Perl, Python, Dart, Ruby, etc., but as close as you can get in Java land.
Let's just show these as follows:

Printing list and map employee out (System.out)

        /** Showing the list and map. */
        puts( "Rick List", rickList );
        puts( "Rick Map ", rickMap );

The puts function is a nice helper function that is a bit easier to use than printf, et al. There is also an sputs if yo want to quickly create a string. The puts function gets its inspiration from Ruby.
The output of the above is as follows:
Rick List [Rick, 29, [Jason, 21]] 
Rick Map  {name=Rick, age=29, boss={name=Jason, age=21}} 
Just to show that there is no funny business, lets also print out the class info.

No really.. they are just java.util.Map and java.util.List

code
        /** Showing the list and map with type info. */
        puts( "Rick List    ", rpad(rickList, 60),  rickList.getClass() );
        puts( "Rick Map     ", rpad(rickMap,  60),  rickMap.getClass()  );

output
Rick List     [Rick, 29, [Jason, 21]]                            class java.util.ArrayList 
Rick Map      {name=Rick, age=29, boss={name=Jason, age=21}}     class java.util.LinkedHashMap 
The rpad function puts padding on the right. It was inspired from Python. So now we have an easy way to work with lists and maps, but what about accessing fields.

Slicing and dicing lists and maps

Boon implements slice notation and indexing so you can easily traverse a map of map of lists of maps.

indexing lists and maps with idx, idxMap, idxList, idxBoolean, idxString, etc.

code
        /** Indexing the list and map with boon slice index operator. */
        puts( "Rick's Name",  idx( rickList,     0 ), "     from", rickList );
        puts( "Rick's Name",  idx( rickMap, "name" ), "     from", rickMap  );

        puts( "Boss Name",    idx( idxList( rickList,    2 ),      0 ) );
        puts( "Boss Name",    idx( idxMap( rickMap, "boss" ), "name" ) );
output
Rick's Name Rick      from [Rick, 29, [Jason, 21]] 
Rick's Name Rick      from {name=Rick, age=29, boss={name=Jason, age=21}} 
Boss Name Jason 
Boss Name Jason 
Now to convert list and maps into JSON in Boon is easy (and very fast). (There is also a path notation like GPATH, and sorting, criteria, filtering but I don't want to get too far off track.)

Converting lists and maps to JSON

        String rickJsonList = toJson( rickList );
        String rickJsonMap  = toJson( rickMap );
Let's see what the JSON data looks like:

Size matters (sometimes)

code
        puts( "Rick JSON List", rpad( rickJsonList, 60 ), "len", rickJsonList.length() );
        puts( "Rick JSON Map ", rpad( rickJsonMap,  60 ), "len", rickJsonMap.length()  );

        puts ( "LEFT PAD really shows the difference");
        puts( "Rick JSON List", lpad( rickJsonList, 60 ), "len", rickJsonList.length() );
        puts( "Rick JSON Map ", lpad( rickJsonMap,  60 ), "len", rickJsonMap.length()  );

output
Rick JSON List ["Rick",29,["Jason",21]]                                     len 24 
Rick JSON Map  {"name":"Rick","age":29,"boss":{"name":"Jason","age":21}}    len 57 
I found to really highlight the difference in size that using lpad instead of rpad works.
output with lpad
LEFT PAD really shows the difference 
Rick JSON List                                     ["Rick",29,["Jason",21]] len 24 
Rick JSON Map     {"name":"Rick","age":29,"boss":{"name":"Jason","age":21}} len 57 
The JSON list is less than half the size of the JSON map. Now this may or may not matter. If you are doing large batch and ETL, then it does matter. It matters a lot. If you are handling 100,000 WebSocket connections and trying to push out 1,000,000 messages per second, then it matters. The trick is to use lists when payload size matters. JSON List + GZIP = a pretty damn small payload and probably pretty close to binary. JSON lists also are nice when you want to send around large batch payloads and still work with readable text.

I actually know a thing or two about this subject and how to make JSON faster and have some real life experience with making REST and Websockets scale into the cloud. The Boon JSON parser is the fastest way to parse and serialize to/from Java on the JVM (at least faster then any mainstream JSON parser, much faster... up to 2x sometimes as much as 5x).
You can convert lists and maps into Java objects as follows:

Converting lists and maps into Employee objects

        /** Converting from List to objects */
        Employee rickEmployee =  fromList( rickList,  employee);

        /** Converting Maps to objects */
        rickEmployee =           fromMap( rickMap, employee );
Let's see what that actually looks like:

Inspecting the employees

        puts (                   "Rick Employee From List      ", rickEmployee);
        puts (                   "Rick Employee From Map       ", rickEmployee);
output
Rick Employee From List       Employee{name='Rick', age=29, boss=Employee{name='Jason', age=21, boss=executive}} 
Rick Employee From Map        Employee{name='Rick', age=29, boss=Employee{name='Jason', age=21, boss=executive}} 
If the arguments match it does the conversion. A match could mean we are checking a sub list or a sub map as well. Lists and Maps are interchangeable for conversion (but map conversion is older and better tested).
In order for the above to work. I added a toString method to the Employee class.

Update to Employee class toString and some constructors

    public static Class<Employee> employee = Employee.class;

    public static class Employee {
        String name;
        int age;
        Employee boss;

        List<Employee> reports;

        public Employee( String name, int age ) {
            this.name = name;
            this.age = age;
        }

        public Employee( String name, int age, Employee boss ) {
            this.name = name;
            this.age = age;
            this.boss = boss;
        }


        public Employee( String name, int age, Employee boss, List<Employee> reports ) {
            this.name = name;
            this.age = age;
            this.boss = boss;
            this.reports = reports;
        }

        @Override
        public String toString() {
            return "Employee{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", boss=" + (boss == null ? "executive" : boss) +
                    ", reports=" + reports +
                    '}';
        }
    }
I also added constructors to guide the JSON mapper how to convert a JSON list into this Employee Java object. The conversion process tries to match the constructor args (first length of args and then ability to convert to arguments), if it cannot then it will attempt to map directly to fields based on field order. If there is any mismatch it fails.
In addition to converting java.util.Lists and java.util.Maps into Java objects, you can also convert JSON Lists and JSON Maps into Java objects as follows:

Reading JSON map and list into Employee

        /** Converting from JSON List to objects */
        rickEmployee =  fromJson( rickJsonList, employee );
        puts (                   "Rick Employee From JSON LIST ", rickEmployee);


        /** Converting from JSON Map to objects */
        rickEmployee =  fromJson( rickJsonList,  employee);
        puts (                   "Rick Employee From JSON LIST ", rickEmployee);
output
Rick Employee From JSON LIST  Employee{name='Rick', age=29, boss=Employee{name='Jason', age=21, boss=executive}} 
Rick Employee From JSON LIST  Employee{name='Rick', age=29, boss=Employee{name='Jason', age=21, boss=executive}} 
The fromJson works just like you expect with both lists and maps (and if it does not let me know). If the arguments or fields match it does the conversion. A match could mean we are checking a sub list or a sub map. Lists and Maps are interchangeable for conversion.
Boon JSON support has @JsonIgnore@JsonView@JsonProperty (from Jackson),** @Expose**@SerializedName (from GSON), as well as support for @Inject, @In, reading config files in JSON, excluding properties, relaxed mode JSON, direct binary UTF-8 mode, and so much more. We will not cover any of that in this article. And Boon JSON is wicked, wicked fast. Faster (sometimes 2 to 3x faster) commonly used JSON libs.
This concludes longer drawn out conversations. Let's cover some edge cases of toListtoMaptoJsonfromListfromMap, and fromJson.

Cookbook for using toList, toMap, toJson, etc.

Let's do a bit of a cookbook of fromList and toList

Basic test

    @Test
    public void testBasicFromList() {
        Employee emp = fromList( Lists.list( ( Object ) "Rick", 29 ), Employee.class );

        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();

    }
The die function was inspired from Perl. THAT IS RIGHT: Perl. There are things about Perl and Ruby that I do like. 
The above test ends up calling this constructor.

Constructor that gets called

    public static class Employee {

        ...
        public Employee( String name, int age ) {
            this.name = name;
            this.age = age;
        }
You can also do the conversion from a map instead of a list which is the more common case for JSON mapping.

Basic map conversion

    @Test
    public void testBasicFromMaps() {
        Employee emp = fromMap( map( "name", ( Object ) "Rick", "age", 29 ), Employee.class );
        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();
    }

When using maps you do not use a constructor and technically you don't need one when using fields, but you should have one. By default the mapping happens with the fields for maps and constructors for lists. You do not need to define a constructor at all for maps, and you do not have to have a no arg constructor. It just works. :)
It is recommended that you define a constructor for lists because without it you are relying on field order. So if you do not use a constructor with lists to object conversion, please for the love of all that is holy have a serialization test to validate that someone does not add a field and screw everything up. In short, if you do list to object conversion, please, please, please define a constructor for each type of list you handle.
You can mix and match list of maps or maps of lists as shown by this test:

Turning a map with a list into an Employee with an Employee boss

    @Test
    public void testFromMapWithAList() {
        List<Object> list = list( ( Object ) "Jason", 21 );
        Employee emp = fromMap( map( "name", ( Object ) "Rick", "age", 29, "boss", list ), Employee.class );
        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();

    }
This we did earlier in the tutorial section. Notice I use die instead of asserts. The nice thing about die is that it is always on. :) I use asserts when I want to compile something out for prod and I use die everywhere else.

Turning a list with a list into an Employee with an Employee boss

    @Test
    public void testListWithSubList() {

        List<Object> list = list( ( Object ) "Jason", 21 );
        Employee emp = fromList( list( ( Object ) "Rick", 29, list ), Employee.class );

        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();

        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();

    }
The above calls this constructor.

This constructor gets called

        public Employee( String name, int age, Employee boss ) {
            this.name = name;
            this.age = age;
            this.boss = boss;
        }

Did you also know that you could do this?

Creating an Employee from a list that has a boss list and a reports list made up of lists

    @Test
    public void testListWithSubListWithSubList() {

        List<Object> boss = list( ( Object ) "Jason", 21 );
        List<Object> report = list( ( Object ) "Lucas", 10 );


        List<Object> reports = new ArrayList<>();
        reports.add( report );

        Employee emp = fromList( list( "Rick", 29, boss, reports ), Employee.class );

        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();

        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();


        ok = emp.reports != null || die();

        ok = emp.reports.size() == 1 || die();
        ok = emp.reports.get( 0 ).name.equals( "Lucas" ) || die();
        ok = emp.reports.get( 0 ).age == 10 || die();

    }


The above calls this constructor.

        public Employee( String name, int age, Employee boss, List<Employee> reports ) {
            this.name = name;
            this.age = age;
            this.boss = boss;
            this.reports = reports;
        }
Think about that for a moment. Let that gel. Not only is the boss list converted into the boss employee arg, but the reports list of lists is converted into the parameter List reports.
You can also use a list or opt not to use a constructor at all:

Look mom. No constructors!

    @Test
    public void testListNotUsingConstructor() {

        List<Object> boss = Lists.list( ( Object ) "Jason", 21 );
        List<Object> report = Lists.list( ( Object ) "Lucas", 10 );


        List<Object> reports = new ArrayList<>();
        reports.add( report );

        Employee emp = MapObjectConversion.fromListUsingFields( Lists.list( "Rick", 29, boss, reports ), Employee.class );

        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();

        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();


        ok = emp.reports != null || die();

        ok = emp.reports.size() == 1 || die();
        ok = emp.reports.get( 0 ).name.equals( "Lucas" ) || die();
        ok = emp.reports.get( 0 ).age == 10 || die();

    }

I do not recommend the above unless you have a lot of serialization tests to ensure that no one comes along and adds a field in a super class that messes everything up. DO NOT DO THIS WITHOUT A LOT OF TESTS FOR SERIALIZATION. MORE THAN USUAL.
I am showing these with java.util.List and java.util.Map but they work easily as well with JSON lists and maps.
Never believe me or anybody without proof. :) The proof you need is in the unit tests.
Here we take a map of lists and maps and convert them into json then back to a map of lists and then into Employee.

Mixed set of maps and lists from from Map to JSON, back into Map and then into Employee

    @Test
    public void testFromJsonMapWithAList() {
        List<Object> list = list( ( Object ) "Jason", 21 );
        Employee emp = fromJson( toJson( map ( "name",  "Rick", "age", 29, "boss", list )), Employee.class );
        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();

    }

Here we take a list of list of lists of maps and lists them into json then back to a map of lists and then into Employee.

Mixed set of lists and from List to JSON, and back into Map and then into Employee

    @Test
    public void testListWithSubListWithSubListUsingJson() {

        List<Object> boss = list( ( Object ) "Jason", 21 );
        List<Object> report = list( ( Object ) "Lucas", 10 );


        List<Object> reports = new ArrayList<>();
        reports.add( report );

        String str = toJson(list( "Rick", 29, boss, reports));

        Employee emp = fromJson( str, Employee.class );

        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();

        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();


        ok = emp.reports != null || die();

        ok = emp.reports.size() == 1 || die();
        ok = emp.reports.get( 0 ).name.equals( "Lucas" ) || die();
        ok = emp.reports.get( 0 ).age == 10 || die();

    }
The ability to go from a map or JSON map to a Java object has been in boon for a long time. The ability to go from a list or JSON list into a Java object was added oh… let me think.. let me think… yesterday. If you have issues with the list to map / list, whatever, let me know. File an issue. I will add a test case and fix it.
Here is the complete code listing for this example:
package org.boon.core.reflection;

import org.boon.Lists;
import org.boon.Maps;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


import static org.boon.Boon.puts;
import static org.boon.Lists.*;
import static org.boon.Maps.*;
import static org.boon.json.JsonFactory.*;


import static org.boon.Exceptions.die;
import static org.boon.Str.lpad;
import static org.boon.Str.rpad;

/**
 * Created by Richard on 2/12/14.
 */
public class MapConversionTest {

    public static Class<Employee> employee = Employee.class;

    public static class Employee {
        String name;
        int age;
        Employee boss;

        List<Employee> reports;

        public Employee( String name, int age ) {
            this.name = name;
            this.age = age;
        }

        public Employee( String name, int age, Employee boss ) {
            this.name = name;
            this.age = age;
            this.boss = boss;
        }


        public Employee( String name, int age, Employee boss, List<Employee> reports ) {
            this.name = name;
            this.age = age;
            this.boss = boss;
            this.reports = reports;
        }

        @Override
        public String toString() {
            return "Employee{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", boss=" + (boss == null ? "executive" : boss) +
//                    ", reports=" + reports +
                    '}';
        }
    }

    @Test
    public void testMain() {
        MapConversionTest.main();
    }

    public static void main( String... args ) {
        List<Object> rickList;
        Map<String, Object> rickMap;


        /** Creating a list. */
        rickList = list( "Rick", 29, list( "Jason", 21 ) );
        /** Creating a map. */
        rickMap = map(
                "name", "Rick",
                "age", 29,
                "boss", map( "name", "Jason", "age", 21 ) );

        /** Showing the list and map. */
        puts( "Rick List", rickList );
        puts( "Rick Map ", rickMap  );



        /** Showing the list and map with type info. */
        puts( "Rick List    ", rpad(rickList, 50), rickList.getClass() );
        puts( "Rick Map     ", rpad(rickMap,  50),  rickMap.getClass() );


        /** Indexing the list and map with boon slice index operator. */
        puts( "Rick's Name",  idx( rickList,     0 ), "from", rickList );
        puts( "Rick's Name",  idx( rickMap, "name" ), "from", rickMap  );

        puts( "Boss Name",    idx( idxList( rickList,    2 ),      0 ) );
        puts( "Boss Name",    idx( idxMap( rickMap, "boss" ), "name" ) );




        String rickJsonList = toJson( rickList );
        String rickJsonMap  = toJson( rickMap );
        puts( "Rick JSON List", rpad( rickJsonList, 60 ), "len", rickJsonList.length() );
        puts( "Rick JSON Map ", rpad( rickJsonMap,  60 ), "len", rickJsonMap.length()  );
        puts ( "LEFT PAD really shows the difference");
        puts( "Rick JSON List", lpad( rickJsonList, 60 ), "len", rickJsonList.length() );
        puts( "Rick JSON Map ", lpad( rickJsonMap,  60 ), "len", rickJsonMap.length()  );

        /** Converting from List to objects */
        Employee rickEmployee =  fromList( rickList,  employee);
        puts (                   "Rick Employee From List      ", rickEmployee);

        /** Converting Maps to objects */
        rickEmployee =  fromMap( rickMap, employee );
        puts (                   "Rick Employee From Map       ", rickEmployee);



        /** Converting from JSON List to objects */
        rickEmployee =  fromJson( rickJsonList, employee );
        puts (                   "Rick Employee From JSON LIST ", rickEmployee);

        /** Converting from JSON Map to objects */
        rickEmployee =  fromJson( rickJsonList,  employee);
        puts (                   "Rick Employee From JSON LIST ", rickEmployee);

    }

    @Test
    public void testBasicFromList() {
        Employee emp = fromList( list( ( Object ) "Rick", 29 ), Employee.class );

        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();

    }


    @Test
    public void testBasicFromMaps() {
        Employee emp = fromMap( map( "name", ( Object ) "Rick", "age", 29 ), Employee.class );
        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();
    }


    @Test
    public void testFromMapWithAList() {
        List<Object> list = Lists.list( ( Object ) "Jason", 21 );
        Employee emp = fromMap( Maps.map( "name", ( Object ) "Rick", "age", 29, "boss", list ), Employee.class );
        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();

    }


    @Test
    public void testListWithSubList() {

        List<Object> list = Lists.list( ( Object ) "Jason", 21 );
        Employee emp = fromList( Lists.list( ( Object ) "Rick", 29, list ), Employee.class );

        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();

        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();

    }


    @Test
    public void testListWithSubListWithSubList() {

        List<Object> boss = list( ( Object ) "Jason", 21 );
        List<Object> report = list( ( Object ) "Lucas", 10 );


        List<Object> reports = new ArrayList<>();
        reports.add( report );

        Employee emp = fromList( list( "Rick", 29, boss, reports ), Employee.class );

        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();

        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();


        ok = emp.reports != null || die();

        ok = emp.reports.size() == 1 || die();
        ok = emp.reports.get( 0 ).name.equals( "Lucas" ) || die();
        ok = emp.reports.get( 0 ).age == 10 || die();

    }


    @Test
    public void testListNotUsingConstructor() {

        List<Object> boss = list( ( Object ) "Jason", 21 );
        List<Object> report = list( ( Object ) "Lucas", 10 );


        List<Object> reports = new ArrayList<>();
        reports.add( report );

        Employee emp = MapObjectConversion.fromListUsingFields( list( "Rick", 29, boss, reports ), Employee.class );

        boolean ok = emp != null || die();
        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();

        ok = emp.age == 29 || die();

        ok = emp.name != null || die();
        ok = emp.name.equals( "Rick" ) || die();
        ok = emp.age == 29 || die();

        ok = emp.boss != null || die();
        ok = emp.boss.name.equals( "Jason" ) || die();
        ok = emp.boss.age == 21 || die();


        ok = emp.reports != null || die();

        ok = emp.reports.size() == 1 || die();
        ok = emp.reports.get( 0 ).name.equals( "Lucas" ) || die();
        ok = emp.reports.get( 0 ).age == 10 || die();

    }
}

The code example will work with snapshot 11 and beyond or derivations thereof.

Thoughts

Thoughts? Write me at richard high tower AT g mail dot c-o-m (Rick Hightower).

Further Reading:

If you are new to boon start here:

Why Boon?

Easily read in files into lines or a giant string with one method call. Boon has Slice notation for dealing with Strings, Lists, primitive arrays, etc. If you are from Groovy land, Ruby land, Python land, or whatever land, and you have to use Java then Boon might give you some relief. If you are like me, and you like to use Java, then Boon is for you too.

Core Boon Philosophy

Core Boon will never have any dependencies. It will always be able to run as a single jar.

Contact Info
JMeter vs. Gatling: Fact Checking: SHILL! ASTROTURFING SHILL!