creating a grails domain class from its class name - grails

I am trying to use the Class.forName('com.mypack.MyDomain').newInstance()
to create an instance of the grails domain from its qualified name.
But Its throwing a ClassNotFoundException.
I assume this is because the .forName('') expects the class to be a java class instead of a groovy class?
How to make this work in grails, or is there another method to create the domain object from the class name in String format.
Thanks
Priyank

Another route to try would be to do:
GrailsDomainClass dc = grailsApplication.getDomainClass( 'com.mypack.MyDomain' )
def newDomainObject = dc.clazz.newInstance()

Try
GrailsClass clazz = grailsApplication.getArtefactByLogicalPropertyName(DomainClassArtefactHandler.TYPE, className)
clazz.clazz.newInstance()

Related

How to autowire a service in grails (2.5.5) with multiple capital letters at front

I have a domain class named ABCDCode and created a service for the this ABCDCodeService. Now I want to use this service in controllers so I wrote it like below:
class TestController{
ABCDCode abcdCode
def index(int id){
abcdCode.getData(id) //Here I am getting NullPOinterException
}
}
I am suspecting something wrong with the autowiring by name.
class TestController{
ABCDCode aBCDCode
}
should work
You have multiple issues.
1) You assign a member variable but it is never initialized, therefore you get a NullPointerException. You need to get the instance from your database by id first.
2) Be aware that the controller needs to be thread-safe, by assigning the member variable in the controller scope it will be used for many calls at the same time with unpredictible outcome.
3) Names like ABCDCode are against grails naming conventions. Use AbcdCode for the domain and AbcdCodeService for the service and all is well.
This would be the correct approach with the domain class AbcdCode and the corresponding service AbcdCodeService:
// if not in the same module
import AbcdCode
class TestController {
// correct injection of the service
def abcdCodeService
// ids are Long, but you could omit the type
def index(Long id) {
// get instance from database by id, moved to method scope
def abcdCode = AbcdCode.get(id)
// note the "?." to prevent NullpointerException in case
// an abcdCode with id was not found.
def data = abcdCode?.getData()
}
}
Grails looks first two characters for beans naming. If the second character of the controller/service is capital then Grails did not convert the first character to lower case.
e.g., TestService bean name is testService and TEstService bean name is TEstService.
So, your code becomes
ABCDCode ABCDCode
def index(int id){
ABCDCode.getData(id)
}
But if you want to user abcdCode as bean name, then you can do this with the help of resources.groovy. Add the following to your resources.groovy file--
beans = {
springConfig.addAlias 'abcdCode', 'ABCDCode'
}

Why doesn't Class.forName work on grails domain classes

I know that using Class.forName to load a grails domain class does not work, but I'm not sure why that is. I'm guessing there is some sort of grails magic happening but it would be nice to understand what it is.
I ended up using
GrailsDomainClass dc = grailsApplication.getDomainClass('mypack.myclass' )
def newDomainObject = dc.clazz.newInstance()
But I'm not sure why just doing Class.forName('mypack.myclass') doesn't work.
Grails uses custom classloaders, so you need to use the 3-arg variant with the classloader that Grails uses and registers as the context classloader:
Class clazz = Class.forName('mypack.myclass', true, Thread.currentThread().contextClassLoader)
def newDomainObject = clazz.newInstance()

How to access the g.-namespace in a Domain Class

I would like to make use of the g.message() functionality in the toString method of my domain class, but the g.-namespace is not accessible by default.
I doubt that a import g.* will do the trick.
I already know that I can use the messageSource functionality, but it would be nicer to use the same syntax as in the views.
You can use:
class MyDomain {
def someMethod() {
def g = ApplicationHolder.application.mainContext.getBean( 'org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib' )
return g.message(....)
}
}
or else you can get messageSource directly: ApplicationHolder.application.mainContext.getBean('messageSource')
Using g.render in a grails service has some hints how to use "g:" in a service. I have not tested this, but it should work mostly the same in domain classes, with one important exception: a domain class cannot use InitializingBean since it's not a bean residing in the application context.

How do I determine if a class is a Grails domain object?

For an arbitrary object what is the easiest way to determine if the type of the object is a Grails domain class?
You can use the GrailsApplication for that. Add a dependency injection to your controller or service:
def grailsApplication
and then you can use it like this:
def foo = ...
if (grailsApplication.isDomainClass(foo.getClass()) {
...
}
Found the following snippet at https://svn.intuitive-collaboration.com/RiskAnalytics/trunk/riskanalytics-grails/src/java/org/codehaus/groovy/grails/web/binding/GrailsDataBinder.java
DomainClassArtefactHandler.isDomainClass(clazz)
The javadoc is here: http://grails.org/doc/latest/api/org/codehaus/groovy/grails/commons/DomainClassArtefactHandler.html#isDomainClass(java.lang.Class)

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

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.
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:
GrailsApplication
GrailsDomainClass
GrailsDomainClassProperty
You can use GrailsClassUtils.getPropertyType(clazz, propertyName)
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}'"
}
Note: this answer is not directly to the question but relates enough IMO.
I was banging my head to the wall, ground and surrounding trees when trying to resolve the "generic type" of a collection association:
class A {
static hasMany = {
bees: B
}
List bees
}
Turned out the easiest and yet sound way was mere (and which I did not try but after 3 hours):
A.getHasMany()['bees']

Resources