How do I get the type (class) of a property of a Grails domain object?

21,572

Solution 1

Grails allows you to access some meta-information of your domain model via the GrailsApplication instance. You can look it up that way:

import org.codehaus.groovy.grails.commons.ApplicationHolder
import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler

def grailsApplication = ApplicationHolder.application
def domainDescriptor = grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, "PhysicalSiteAssessment")

def property = domainDescriptor.getPropertyByName("site")
def type = property.getType()
assert type instanceof Class

API:

Solution 2

You can use GrailsClassUtils.getPropertyType(clazz, propertyName)

Solution 3

The answer above provided by Siegfried became obsolete somewhere around Grails 2.4. ApplicationHolder is obsolete.

Now, you can get real type names from the domainClass property that every domain class has.

entityClass.domainClass.getProperties().each() {
    println "Property '${it.name}' is of type '${it.type}'"
}
Share:
21,572
Peter Becker
Author by

Peter Becker

Updated on July 15, 2020

Comments

  • Peter Becker
    Peter Becker almost 4 years

    I'm trying to dynamically create domain objects in Grails and encountered the problem that for any property referencing another domain object the metaproperty tells me its type is "java.lang.Object" and not the expected type.

    For example:

    class PhysicalSiteAssessment {
        // site info
        Site site
        Date sampleDate
        Boolean rainLastWeek
        String additionalNotes
        ...
    

    is the beginning of a domain class, which references another domain class "Site".

    If I try to dynamically find the property types for this class by using this code (in a service):

    String entityName = "PhysicalSiteAssessment"
    Class entityClass
    try {
        entityClass = grailsApplication.getClassForName(entityName)
    } catch (Exception e) {
        throw new RuntimeException("Failed to load class with name '${entityName}'", e)
    }
    entityClass.metaClass.getProperties().each() {
        println "Property '${it.name}' is of type '${it.type}'"
    }
    

    then the result is that it recognizes the Java classes, but not the Grails domain class. The output contains the following lines:

    Property 'site' is of type 'class java.lang.Object'
    Property 'siteId' is of type 'class java.lang.Object'
    Property 'sampleDate' is of type 'class java.util.Date'
    Property 'rainLastWeek' is of type 'class java.lang.Boolean'
    Property 'additionalNotes' is of type 'class java.lang.String' 
    

    The problem is that I would like to use the dynamic lookup to find matching objects, e.g. do a

    def targetObjects = propertyClass."findBy${idName}"(idValue)
    

    where the propertyClass is retrieved via introspection, idName is the name of the property to look up (not necessarily the database ID) and idValue is the value to find.

    It all ends in:

    org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingMethodException: No signature of method: static java.lang.Object.findByCode() is applicable for argument types: (java.lang.String) values: [T04]
    

    Is there a way to find the actual domain class for the property? Or maybe some other solution to the problem of finding an instance of a domain class whose type is not given (only a property name that has the type)?

    It works if I use the convention that the type name is the property name capitalized ("site"->"Site") to look up the class via the grailsApplication instance, but I would like to avoid that.

  • Peter Becker
    Peter Becker about 15 years
    Thanks, that works. Is there some overview of this API somewhere? I had been looking for something like this but couldn't find it.
  • Ted Naleid
    Ted Naleid about 15 years
    There aren't any good references that I've ever seen besides the javadocs (grails.org/doc/1.1/api/org/codehaus/groovy/grails/commons/…‌​). I also find looking at the Grails sourcecode very helpful. I also use this kind of stuff heavily in the build-test-data plugin to inspect domain object constraints and automatically generate test objects that pass the constraints if you're looking for examples (bitbucket.org/tednaleid/grails-test-data/wiki/Home).
  • digz6666
    digz6666 over 11 years
    Thanks, its neat and short way.
  • Ko-Chih Wu
    Ko-Chih Wu about 11 years
    I'm calling getDomainClass instead. grailsApplication.getDomainClass(PhysicalSiteAssessment).get‌​PropertyByName('site‌​').type