In Grails can we access methods without creation of objects? - grails

as I am new to grails but I am familiar with Java.In the following code I have Artist domain class and ArtistController class. In controller class the Artist accessing the findByName(...) directly I mean its not creating the object to access the method (or) is findByName(..) a static method so that it can be accessed using the className.staticMethodName as in Java.
class ArtistController {
def show() {
def artist = Artist.findByName(params.artistName)
// do whatever is appropriate with the artist...
}
}

You are referring to static methods. It has nothing to do with Grails vs Java, as static is present in Java also. You may want to check out the docs, but in a nutshell, a static method belongs to the class, and not an instance of that class, which is why you are able to invoke the method without a new object.

Related

What is best way to update domain class object with large number of variables

Suppose I have Employee domain class, I want to create object of domain class from params map coming from UI side.
I can create object in two ways as follows
Normal way
Employee employee = new Employee(name: params.name, rollNo:
params.rollNo)
and so on. If domain class has 20 variables, then we need to write all variables in above constructor.
Following is best way to create object
Employee employee = new Employee(params)
Above constructor will populate object with matching params. Right.
Now my question comes here.
If suppose I have existing domain class object fetched from DB, Now I want to update this object from params map coming from UI.
What is best way to do this (like we do in above second option).
I think it is best to use command objects and bind it to the Employee.
here is sample pseudo code:
class EmployeeMgmtController {
def editEmp(EmployeeCmd cmd){
Employee editEmp = Employee.get(1)
editEmp.properties = cmd
editEmp.save()
}
}
class EmployeeCmd{
String id
static constraints = {
id blank:false,nullable:false
}
}
or,
you if your on controller, and still want to use params (and exclude any fields that you don't want to bind):
bindData(editEmp, params, [exclude:['firstName', 'lastName']])
If you want to achieve that in a service class, make your service implement grails.web.databinding.DataBinder then use the bindData method as demonstrated below.
import grails.web.databinding.DataBinder
class MyAwesomeService implements DataBinder {
/**
* Updates the given instance of a domain class to have attribute values specified
* in "newData" map.
*/
MyDomain updateMyDomainAttributes(MyDomain myDomianInstance, Map newData) {
bindData(myDomianInstance, newData)
myDomianInstance.save(flush: true)
}
}

How can you structure Grails Services so superclass methods are non-transactional and subclass methods are transactional?

I have the following super class grails service:
abstract class SuperClassService {
public def execute(def payload) {
def tracker = new TrackerDomain().save()
doWork()
tracker.status = 'done'
tracker.save()
}
protected abstract doWork(def payload);
}
and seveeral child class grails services that follow this pattern:
class SubClassService extends SuperClassService {
protected doWork(def payload){
new SomeDomain().save()
}
}
In my controllers I kick off a call to the 'execute' method of the various child classes.
What I want is for the SubClass services to follow the traditional Service pattern where any problems get rolled back, but I want the domains created int he parent class code to both NOT be rolled back and be committed immediately (so that they can be viewed on a tracking page while the subclass service code is still executing. I would PREFER not to set everything as non-transactional and only set the functions in the subclass as transactional but if that's the only option here I would like to know that too.
Have you tried annotating your subclasses service method with a #Transactional(propagation = Propagation.REQUIRES_NEW)? I think that it should do the trick, regardless of whether the outside service code is transactional or not.

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.

Retrieving a list of GORM persistent properties for a domain

What's the best/easiest way to get a list of the persistent properties associated with a given GORM domain object? I can get the list of all properties, but this list contains non-persistent fields such as class and constraints.
Currently I'm using this and filtering out the list of nonPersistent properties using a list I created:
def nonPersistent = ["log", "class", "constraints", "properties", "errors", "mapping", "metaClass"]
def newMap = [:]
domainObject.getProperties().each { property ->
if (!nonPersistent.contains(property.key)) {
newMap.put property.key, property.value
}
}
There seems like there must be a better way of getting just the persistent properties.
Try this:
import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
...
def d = new DefaultGrailsDomainClass(YourDomain.class)
d.persistentProperties
Here's a link to the Grails API for GrailsDomainClass (it's a link to an older version; I couldn't find a newer one after some quick searches). It's got a getPersistentProperties() (used in the code snippet above). You can traverse the API documentation to see what other methods might be useful to you.
If you want an example, do a grails install-templates and then look at src/templates/scaffolding/create.gsp. There's a block in there where it iterates over the persistent domain properties.
Now (strarting Grails 2.x) you don't even have to instantiate new DefaultGrailsDomainClass(...) and avoid unnecessary code executions. All domain class objects have injected property domainClass:
def domainObject = new YourDomain()
domainObject.domainClass.persistentProperties
Or, if you haven't domain class object, you can get DefaultGrailsDomainClass from application context by domain class name - each domain class has a DefaultGrailsDomainClass registered as a Spring bean. So you can use, for example, Holders (assuming your domain class name is 'Foo'):
def defaultGrailsDomainClass = Holders.applicationContext.getBean("FooDomainClass")
defaultGrailsDomainClass.persistentProperties
As of grails 3.3.0
All code that uses the GrailsDomainClass or GrailsDomainClassProperty classes should be re-written to use the mapping context api.
To get started, inject the grailsDomainClassMappingContext bean. See the api documentation for more information on the MappingContext, PersistentEntity (GrailsDomainClass), and PersistentProperty(GrailsDomainClassProperty)
For example:
class MyService {
def grailsDomainClassMappingContext //inject
def accessDomainProperties(Class clazz) {
PersistentEntity entityClass = grailsDomainClassMappingContext.getPersistentEntity(clazz.name)
List<PersistentProperty> persistentPropertyList = entityClass.persistentProperties
persistentPropertyList.each { property ->
println property.name
}
}
}
Hope this helps someone.

Groovy metaprogramming

In a Service of a Grails project, I like to find, at run time, the arguments of Dynamic Methods in order to inform callers.
Also, I like to call the method and if doesn't exist to return an error,
I will appeciate any help.
You can configure URLMappings in grails to get the value of the dynamic method and call it against your object for example you can do the following
In your urlMappings.groovy define a mapping with two embedded variables object and method
"/$object/$method" (controller:"api",action:"invoke")
Define a 'api' controller with an invoke action. See code below with the logic on how to invoke the method on the object
import org.codehaus.groovy.grails.commons.ApplicationHolder as AH
class ApiController {
def invoke = {
def object = params.object
def method = params.method
def args
if(object) {
def domainClass = AH.application.domainClasses.find{it.name == method}?.clazz
if(domainClass.metaClass.getStaticMetaMethod(method,args)) {
domainClass.metaClass.invokeStaticMethod(target,input.method,args)
}
}
}
}
In my example, I assumed that you're calling a static dynamic finder on the domain class. You can generalize this to handle instance methods as well. You need however to provide more information such as the object id, in your request to load the object and call the method against it.
"/$object/$id/$method" (controller:"api",action:"invoke")
-Ken
Not sure I understand your question, but the last part about checking if you can call a method on an object, this can be done by checking the meta class of the object you are dealing with like this.
obj.metaClass.respondsTo(obj, 'theMethodYouWantToCall')
obj is the object you want to call the method on, and theMethodYouWantToCall is the name of the method you want to call.
respondsTo will return an empty list [] if the method you are trying to call is not found

Resources