Rick

Rick
Rick

Tuesday, September 16, 2014

Boon JSON: Custom object serializer now works with super classes, and interfaces. (Example of using Guava HashCode)



related to
https://github.com/RichardHightower/boon/issues/242
https://github.com/RichardHightower/boon/issues/231



Boon JSON: Custom object serializer works with super classes, and interfaces (and example of using HashCodeGuava). 




Let's say you want to write a custom object serializer to work with Guava HashCode thingy or whatever else you need.
    public static String toJson(Object obj) {

        return createSerializer().serialize(obj).toString();
    }

    private static JsonSerializer createSerializer() {
        JsonSerializerFactory factory = new JsonSerializerFactory()
                .addTypeSerializer(HashCode.class, new HashCodeSerializer()
                );
        return factory.create();
    }


    private static class HashCodeSerializer implements CustomObjectSerializer<HashCode> {
        @Override
        public Class<HashCode> type() {
            return HashCode.class;
        }

        @Override
        public void serializeObject(JsonSerializerInternal serializer, HashCode instance, CharBuf builder) {
            serializer.serializeString(instance.toString(), builder);
        }
    }
You can use it as an object like so:
    @Test
    public void test() {
        Hasher hasher = md5().newHasher();
        hasher.putString("heisann", Charset.defaultCharset());
        HashCode hash = hasher.hash();
        String actualJson = toJson(hash);

        ok = actualJson.equals("\"86c7c929d73e1d91c268c9f18d121212\"") || die(actualJson);

        puts(actualJson);
    }
Or you can use it from a field like so:
The above works now.
It also works for fields.
    public static class Employee {
        String firstName = "Rick".intern();
        HashCode password = md5().newHasher().putString("BACON!", Charset.defaultCharset()).hash();

    }


    @Test
    public void testWithField() {
        Employee rick = new Employee();
        String actualJson = toJson(rick);
        puts(actualJson);


        /* Convert it back to an employee. */
        Map<String, Object> fromJson = (Map<String, Object>) fromJson(actualJson);

        /* Grab the password an convert it into a HashCode. */
        String password = idxStr(fromJson, "password");
        fromJson = Maps.copy(fromJson);
        /* Convert and shove it back into the map. */
        idx(fromJson, "password", HashCode.fromString(password));

        /* Now convert the map into an Employee. */
        Employee rick2 = fromMap(fromJson, Employee.class);


        ok = rick.firstName == rick2.firstName.intern() || die();

        ok = rick.password.equals(rick2.password) || die(rick2.password);

    }

Also...
Example of Using BOON JSON Java, Example of using Guava HashCode, Example of doing custom field conversion in Boon, Example of being awesome. etc. 

Sunday, September 14, 2014

Added pretty print JSON to Boon

    puts(Maps.asPrettyJsonString(map));
    puts(Boon.toPrettyJson(map));
Boon.toPrettyJson works with Set, Map, instances, etc.

(
)
Maps.asPrettyJsonString
BeanUtils.asPrettyJsonString (can pass custom mapper)
Lists.asPrettyJsonString 
Sets.asPrettyJsonString
Most people will want to use Boon.toPrettyJson
I am sure there are bugs, but it works mostly now. More testing needed of course.
{
    "name" : "Rick",
    "age" : 45,
    "wife" :         {
            "name" : "Diana"
        },
    "children" : [        {
            "name" : "Whitney"
        },        {
            "name" : "Maya"
        },        {
            "name" : "Lucas"
        },        {
            "name" : "Ryan"
        },        {
            "name" : "Noah"
        }],
    "fruit" : ["apple","orange","strawberry"]
} 

How do I amend an object that is stored in DataRepo? (Boon)


From issue https://github.com/RichardHightower/boon/issues/224 (which is fixed in boon in git but not released)
Can I just change it's properties or should I call one of the update/modify methods ?
What's the difference between them?
Just updating an indexed property on an object did not update the repo.
Calling modify and update seemed to do the same thing - there was a new entry for the new value, but the index for the old value still seemed to include it.

My answer...

I fixed this. I also added some optimizations and an example just for you.
It is been more well tested with domain object than maps and lists. 
It needs a major overhaul. I gave it a minor overhaul but it the whole thing needs a revisit. 
It was written before many of the utilities that exists in boon, and it does things its own way instead of the boon way as the boon way did not exist. I digress. So much improved... But could use more.

So here is the example...
Create the repo.
        puts("Create the repo");
        Repo<String, Map<String, String>> dbRepo = (Repo<String, Map<String, String>>)(Object) Repos.builder()
                .primaryKey("name")
                .lookupIndex("sport")
                .lookupIndex("job")
                .lookupIndex("colour")
                .build(String.class, Map.class);

Maps.map just creates a map.
        puts("just add some object");

        dbRepo.add(Maps.map( //Rick
                "job", "manager",
                "name", "Rick",
                "sport", "soccer"
        ));
        dbRepo.add(Maps.map( //Bob
                "job", "clerk",
                "name", "Bob",
                "sport", "soccer"
        ));
        dbRepo.add(Maps.map( //Sam
                "job", "clerk",
                "name", "Sam",
                "sport", "soccer"
        ));
        dbRepo.add(Maps.map( //Joe
                "job",  "clerk",
                "name", "Joe",
                "sport", "soccer"
        ));


Now... expect stuff...
        puts("Expect to be 1 manager:", dbRepo.query(eq("job", "manager")).size());
        puts("Expect to be 3 clerks:",  dbRepo.query(eq("job", "clerk")).size());

        equalsOrDie("Should be one manager", 1, dbRepo.query(eq("job", "manager")).size());
        equalsOrDie("Should be 3 clerks", 3, dbRepo.query(eq("job", "clerk")).size());


        Map<String, Object> manager = dbRepo.results(eq("job", "manager")).expectOne(Map.class).firstMap();

Well you get the idea... There is a full example as part of Bug224. Follow the comments in puts they tell the story. P.S. You misspelled color again. 
You need the latest boon. So git pull it and build it.
        puts("Create the repo");
        Repo<String, Map<String, String>> dbRepo = (Repo<String, Map<String, String>>)(Object) Repos.builder()
                .primaryKey("name")
                .lookupIndex("sport")
                .lookupIndex("job")
                .lookupIndex("colour")
                .build(String.class, Map.class);


        puts("just add some object");

        dbRepo.add(Maps.map( //Rick
                "job", "manager",
                "name", "Rick",
                "sport", "soccer"
        ));
        dbRepo.add(Maps.map( //Bob
                "job", "clerk",
                "name", "Bob",
                "sport", "soccer"
        ));
        dbRepo.add(Maps.map( //Sam
                "job", "clerk",
                "name", "Sam",
                "sport", "soccer"
        ));
        dbRepo.add(Maps.map( //Joe
                "job",  "clerk",
                "name", "Joe",
                "sport", "soccer"
        ));

        puts("Expect to be 1 manager:", dbRepo.query(eq("job", "manager")).size());
        puts("Expect to be 3 clerks:",  dbRepo.query(eq("job", "clerk")).size());

        equalsOrDie("Should be one manager", 1, dbRepo.query(eq("job", "manager")).size());
        equalsOrDie("Should be 3 clerks", 3, dbRepo.query(eq("job", "clerk")).size());

        Map<String, Object> manager = dbRepo.results(eq("job", "manager")).expectOne(Map.class).firstMap();


        manager = Maps.copy(manager); //We can't change the original object.
        // Or we will not be able to remove it from the old indexes.
        // There is an option to copy all objects on the way in. I think. Or there was one planned. :)

        //Now we modify the object.
        manager.put("job", "clerk");


        puts("The repo does not know about the change yet. We have not told it.");
        puts("Expect to be 1 manager:", dbRepo.query(eq("job", "manager")).size());
        puts("Expect to be 3 clerks:",  dbRepo.query(eq("job", "clerk")).size());

        equalsOrDie("Should be one manager", 1, dbRepo.query(eq("job", "manager")).size());
        equalsOrDie("Should be 3 clerks", 3, dbRepo.query(eq("job", "clerk")).size());




        puts("We call update so the repo can update its indexes");
        dbRepo.update( (Map) manager);
        puts("Expect to be 0 manager:", dbRepo.query(eq("job", "manager")).size());
        puts("Expect to be 4 clerks:",  dbRepo.query(eq("job", "clerk")).size());


        equalsOrDie("Should be 0 manager", 0, dbRepo.query(eq("job", "manager")).size());
        equalsOrDie("Should be 4 clerks", 4, dbRepo.query(eq("job", "clerk")).size());


        //Now let's promote Joe
        dbRepo.update("Joe", "job", "manager"); //This does an in place edit, and updates the indexes for us
        puts("Example of in place edit to promote Joe");
        puts("Expect to be 1 manager:", dbRepo.query(eq("job", "manager")).size());
        puts("Expect to be 3 clerks:",  dbRepo.query(eq("job", "clerk")).size());


        equalsOrDie("Should be 1 manager", 1, dbRepo.query(eq("job", "manager")).size());
        equalsOrDie("Should be 3 clerks", 3, dbRepo.query(eq("job", "clerk")).size());


Kafka and Cassandra support, training for AWS EC2 Cassandra 3.0 Training