Is it possible to metaprogram named queries onto a grails domain class? - grails

Is it possible to metaprogram named queries onto a grails domain class? If so, how?
Thanks

Domain classes have a namedQueries property that you can use to add your own named queries. If you want to do this using metaprogramming from within a plugin (rather than by editing the domain class directly), you should do it in the doWithDynamicMethods closure of the plugin's descriptor file.
Something like this should work:
class MyPlugin {
def doWithDynamicMethods = { applicationContext ->
application.domainClasses.each { domainClass ->
boolean domainClassFilter = domainClass as Boolean
if (domainClassFilter) {
domainClass.metaClass.static.myNamedQuery = {->
// implementation of your named query goes here. Here is an example implementation
// that returns all instances with status == 'ready'
String simpleClassName = domainClass.simpleName
domainClass.findAll("from $simpleClassName where status = ?", ['ready'])
}
}
}
}
}
This will add myNamedQuery to every domain class in the application that the plugin is installed in. If you only want to add it to some domain classes, then replace the value of domainClassFilter with a more appropriate test.

Related

Grails Domain Object Includes Class Attribute

I'm using a domain object to interface with a database in Grails.
When I use the list() method on a domain object to get all of the rows from a database it works great except for one thing. The object that comes back for each row also includes an attribute called "class". I've read some things about creating a custom marshaller that would allow me to remove that attribute from the object. Is that really the best way to not have to return the class attribute?
Thanks!
You can also use JSON.registerObjectMarshaller as below:
// BootStrap.groovy
JSON.registerObjectMarshaller( YourDomain ) {
it.properties.findAll { it.name != 'class' }
}
Refer here for a similar example.
Here's a link to change the way Grails renders JSON by default:
http://grails.org/doc/2.4.4/guide/single.html#defaultRenderers
Just change "NameOfDomainClass" to the class you want to render differently. In this case, the Domain Class.
import grails.rest.render.json.*
beans = {
bookRenderer(JsonRenderer, NameOfClass) {
excludes = ['class']
}
}

How to dynamically inject services into a grails custom artefact

So I created a plugin that introduces a custom artefact "Guard" (guard classes resides in: /grails-app/guards). Right now my plugin works by making the grailsApplication aware of the new artefact. So if I call grailsApplication.getGuardClasses() the behavior performs as expected.
My problem is that I want to be able to dynamically inject services into my guard classes, like so:
Class ExampleGuard {
def exampleService
}
I have found solutions on this website that give a static solution, that either goes of Holders, or the application context to get the bean by name. This is not what I want because I essentially want this to be autowired up to that when people use my plugin they can use dynamic injection of services in the guard classes.
UPDATE:
This is how I was accessing my Guard class.
def guard = grailsApplication.getArtefact("Guard","marketplace.TestGuard").newInstance()
Calling .newInstance() nullifies all fields on the class including the injected spring beans which is why injected classes will be null:
assert guard.sampleService == null
If your plugin discovers all of the Guard classes and adds them to the spring application context, those beans will automatically be subject to dependency injection. This is how all of the built in artifacts work and how artifacts provided by plugins work, Quartz Jobs for example.
EDIT:
As an exmaple...
class GuardsPlugin {
// ...
def doWithSpring = {
application.guardClasses.each { guardClass ->
"${guardClass.propertyName}"(guardClass.clazz) { bean ->
bean.autowire = "byName"
}
}
}
}
Then if you have a class like MySpecialGuard and you reference if from a controller (for example) with something like this...
class MyController {
def mySpecialGuard
def someAction() {
// mySpecialGuard should be DI'd into this
// controller and mySpecialGuard should itself
// have been subjected to DI
}
}
I hope that helps.

grails - tell me if anything is dirty?

Grails provides an isDirty method that can be called on domain objects. How would one modify the Grails domain model system, such that one could simply call a method, to find out if any domain objects are dirty.
I'm struggling with some "unsaved transient instance" errors that I haven't been able to nail down, and it'd be great to know what's dirty. Is there an elegant way to do this with groovy?
Add this to BootStrap.groovy:
import org.hibernate.Session
Session.metaClass.isDirty = { ->
delegate.persistenceContext.entitiesByKey.values().any { it.isDirty() }
}
This adds an isDirty() method to Hibernate sessions that checks that top-level instances or instances in collections are dirty and you can use it with withSession, e.g.
boolean dirty = SomeDomainClass.withSession { session -> session.isDirty() }
or if you have access to the sessionFactory bean (e.g. from a def sessionFactory dependency injection)
boolean dirty = sessionFactory.currentSession.isDirty()
Based on Burt's answer, one might also do:
Session.metaClass.whatsDirty = { ->
def everythingDirty = []
delegate.persistenceContext.entitiesByKey.values().each { if (it.isDirty()) everythingDirty.add(it) }
return everythingDirty
}

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.

Using grails service in domain class

I want to use a service in my Grails application. However, it is always null. I am using Grails version 1.1. How can I solve this problem?
Sample code:
class A{
String name;
def testService;
static transients=['testService']
}
Can I use a service inside a domain class?
That should work. Note that since you're using 'def' you don't need to add it to the transients list. Are you trying to access it from a static method? It's an instance field, so you can only access it from instances.
The typical use case for injecting a service into a domain class is for validation. A custom validator gets passed the domain class instance being validated, so you can access the service from that:
static constraints = {
name validator: { value, obj ->
if (obj.testService.someMethod(value)) {
...
}
}
}
Short answer is. Yes you can use service inside domain class.
Here is an sample code where domain class gets access to the authenticate service from acegi plugin. It works without problems.
class Deal {
def authenticateService
def afterInsert() {
def user = authenticateService.userDomain();
....
}
....
}
To summarize Burt and Remis' answers:
In the domain custom validator, you have to use obj.testService rather than use testService directly. If you wanna use service in the domain custom validator:
static constraints = {
name validator: { value, obj ->
if (obj.testService.someMethod(value)) {
...
}
}
}
But in other methods, including afterInsert and other private/public methods, use testService is fine.
def someMethod() {
def user = testService.serviceMethod();
....
}

Resources