groovytypingjsonslurper

Add strong typing to objects from JsonSlurper


I'm having some trouble getting typing to work with the JsonSlurper in Groovy. I'm fairly new to Groovy, and even newer to adding strong types to it - bear with me.

Right now I've created a trait which defines the general shape of my JSON object, and I'm trying to cast the results of parseText to it.

import groovy.json.JsonSlurper

trait Person {
    String firstname
    String lastname
}

def person = (Person)(new JsonSlurper().parseText('{"firstname": "Lando", "lastname": "Calrissian"}'))

println person.lastname

This throws

Exception in thread "main" org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '{firstname=Lando, lastname=Calrissian}' with class 'org.apache.groovy.json.internal.LazyMap' to class 'Person' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: Person(org.apache.groovy.json.internal.LazyMap)
    ...

I can see why my code doesn't make sense, I'm not trying to change the type of the data (casting), I'm just trying to let my IDE know that this is what's inside of my object.

Is it possible to at least add code completion to my JSON objects? I'd love to get runtime type checking, as well, but it's not necessary.


Solution

  • you could try to use delegate

    this allows to wrap class around map

    import groovy.json.JsonSlurper
    
    class Person {
        @Delegate Map delegate
        String getFirstname(){ delegate.get('firstname') }
        String getLastname(){ delegate.get('lastname') }
    }
    
    def person = new Person(delegate:new JsonSlurper().parseText('{"firstname": "Lando", "lastname": "Calrissian"}'))
    
    println person.lastname
    

    or for example use Gson for parsing:

    @Grab(group='com.google.code.gson', module='gson', version='2.8.5')
    
    import com.google.gson.Gson
    
    class Person {
        String firstname
        String lastname
    }
    
    def person = new Gson().fromJson('{"firstname": "Lando", "lastname": "Calrissian"}', Person.class)
    
    assert person instanceof Person
    println person.lastname