In Grails, services are singletons by default. Can I keep it that way and still create an instance of an inner class of that service from a controller?
//by default grails makes MyTestService a singlton
class MyTestService{
public class InnerTest{
String msg;
def addMsg(String str){
this.msg=str;
}
def printMsg(){
println this.msg;
}
}
}
In controller "MyController"...
def m=myTestService.getInstance().new InnerTest();
//produces " MyTestService.InnerTest cannot be cast to MyTestService.InnerTest"
def m=myTestService.new InnerTest();
//No signature of method:MyController.InnerTest()
You should be able to do something like:
class MyTestService{
public class InnerTest{
String msg;
def addMsg(String str){
this.msg=str;
}
def printMsg(){
println this.msg;
}
}
def InnerTestFactory() {
new InnerTest()
}
}
And use it from your controller:
def m=myTestService.InnerTestFactory();
Related
Grails 2.4.4 here. All of my controllers were generated using the standard grails create-controller ... command:
class FizzController {
def index() {
// ...
}
}
class BuzzController {
def index() {
// ...
}
}
...etc.
At the top of each action method, in each controller, I need to call a method doSomething(String). This method needs to have access to redirect(...) so that it can redirect the user if need be. Ideally, I could create an abstract base controller class and have all my controllers extend it:
abstract class BaseController {
void doSomething(String cmd) {
if(cmd == 'Yee haw!') {
redirect(controller: 'foo', action: 'baz')
return false
}
}
}
class FizzController extends BaseController {
def index() {
String cmd = getCmdSomehow()
doSomething(cmd)
// ...etc.
}
}
class BuzzController extends BaseController {
def index() {
String cmd = getCmdSomehow()
doSomething(cmd)
// ...etc.
}
}
However I'm not sure Grails will allow this, since it's doing "Groovy magic" under the hood to make sure there is access to things like redirect(...) and render(...), etc. It would also be wonderful if I could put all this in a closure and just have it executed implicitly (without having to call doSomething() at the beginning of each and every controller action.
What is my best option/solution here? Please use a concrete code example!
Use Filter instead:
class ExampleFilters {
def filters = {
logFilter(controller: '*', action: '*') {
before = {
}
after = { Map model ->
}
afterView = {
}
}
}
}
I have the two domain clases:
class Persona {
String nombre
String apellidos
static hasMany = [pertenencias: Pertenencia]
static constraints = {
}
static mapping = {
pertenencias cascade: "all-delete-orphan"
}
}
class Pertenencia {
String nombre
static belongsTo = [persona:Persona]
static constraints = {
}
}
The service:
class MembresiaService {
#Transactional
def saveAll() {
def p = new Persona(nombre: 'carlos', apellidos: 'gm')
p.addToPertenencias(nombre: 'auto')
p.addToPertenencias(nombre: 'computadora')
p.addToPertenencias(nombre: 'casa')
p.save()
}
#Transactional
def deletePertenencias() {
def p = Persona.get(1)
p.pertenencias?.clear()
}
}
And the controller:
class TestController {
def membresiaService
def index() {}
def saveAll() {
membresiaService.saveAll()
redirect(action: "index")
}
def deletePertenencias() {
membresiaService.deletePertenencias()
redirect(action: "index")
}
}
When I execute saveAll() method from controller it saves the data in the database, when I execute deletePertenencias() from controller it deletes the "pertenecias" collection of Persona from the database (as expected).
I have installed the Grails console plugin , first time I execute the lines of saveAll() service method in the console, the result is the "persona" and its "pertenencias" in database. Then I execute the lines of deletePertenencias() service method in console but it doesn't delete the data of database and the "persona" object mantains the "pertenencias" (as if I had not run deletePertenencias() code).
Anyone kwnow why the code executed from console gives unexpected results?
I expect the result was the same from controller and console but the behaviour is different.
I have a Grails service,
Parent Class:
class BarService{
def fetchData(params) {
return fooData.toString()
}
}
Child Class:
class FooService extends BarService{
def fetchData(params) {
def fooData = super.fetchData(params) //this will call the BarService method
return fooData
}
}
Is this the right groovy way of doing it? Because to me this looks like Java
Thanks
As per your example, there is not much that can be done, except maybe removing the optional return keyword:
// Parent Class:
class BarService{
def fetchData(params) {
params.fooData.toString()
}
}
// Child Class:
class FooService extends BarService{
def fetchData(params) {
super.fetchData params
}
}
assert new FooService().fetchData([fooData: 900]) == "900"
The "return" keyword isn't the problem (as U can see here - https://groovyconsole.appspot.com/edit/5158539458772992). If You're getting a "null", the problem is the code at:
return fooData.toString()
Should be like the #WillP said (with "return" keywork optionally):
return param.fooData.toString()
I have a Grails project with multiple Domain Classes, and I want to make a persistence service as reusable as possible by only having one save() inside of it. To try and achieve this I have done the following in my project.
//PersistenceService.groovy
#Transactional
class PersistenceService {
def create(Object object) {
object.save flush: true
object
}
//BaseRestfulController
class BaseRestfulController extends RestfulController {
def persistenceService
def save(Object object) {
persistenceService.create(object)
}
//BookController
class BookController extends BaseRestfulController {
private static final log = LogFactory.getLog(this)
static responseFormats = ['json', 'xml']
BookController() {
super(Book)
}
#Transactional
def save(Book book) {
log.debug("creating book")
super.save(book)
}
So basically I have a bunch of domains for example Author etc, each with their own controller similar to the bookController. So is there a way to reuse the service for persistence like I am trying above?
Thank you
I'm doing something similar, but mainly because all my entities are not actually removed from the database but rather "marked" as removed. For several apps you need such an approach since it's critical to prevent any kind of data loss.
Since most databases do not provide support for this scenario, you can't rely on foreign keys to remove dependent domain instances when removing a parent one.
So I have a base service class called GenericDomainService which has methods to save, delete (mark), undelete (unmark).
This service provides a basic implementation which can be applied to any domain.
class GenericDomainService {
def save( instance ) {
if( !instance || instance.hasErrors() || !instance.save( flush: true ) ) {
instance.errors.allErrors.each {
if( it instanceof org.springframework.validation.FieldError ) {
log.error "${it.objectName}.${it.field}: ${it.code} (${it.rejectedValue})"
}
else {
log.error it
}
}
return null
}
else {
return instance
}
}
def delete( instance, date = new Date() ) {
instance.dateDisabled = date
instance.save( validate: false, flush: true )
return null
}
def undelete( instance ) {
instance.dateDisabled = null
instance.save( validate: false, flush: true )
return null
}
}
Then, in my controller template I always declare two services: the generic plus the concrete (which may not exist):
def ${domainClass.propertyName}Service
def genericDomainService
Which would translate for a domain called Book into:
def bookService
def genericDomainService
Within the controller methods I use the service like:
def service = bookService ?: genericDomainService
service.save( instance )
Finally, the service for a given domain will inherit from this one providing (if needed) the custom logic for these actions:
class BookService extends GenericDomainService {
def delete( instance, date = new Date() ) {
BookReview.executeUpdate( "update BookReview b set b.dateDisabled = :date where b.book.id = :bookId and b.dateDisabled is null", [ date: date, bookId: instance.id ] )
super.delete( instance, date )
}
def undelete( instance ) {
BookReview.executeUpdate( "update BookReview b set b.dateDisabled = null where b.dateDisabled = :date and b.book.id = :bookId", [ date: instance.dateDisabled, bookId: instance.id ] )
super.undelete( instance )
}
}
Hope that helps.
i'm caught in a strange question about grails injection any service annotated with #Transactional into any controller in 1.3.7.
SyncSpInfoService:
package test
import org.springframework.transaction.annotation.*
class SyncSpInfoService {
static transactional = false
#Transactional
def syncSpInfoData(def dataSource)throws RuntimeException{
...
}
Controller:
package test
class SyncSpInfoController {
def syncSpInfoService
def dataSource
def index = {
try{
syncSpInfoService.syncSpInfoData(dataSource)
render "Success"
return
}catch(RuntimeException e){
e.printStackTrace()
render "Error:"+e.getMessage()
return
}
}
}
And run the controller,if the SyncSpInfoService is caugth in error,then i modify it,and run it again,there are errors as following:
Error:test.SyncSpInfoService cannot be cast to test.SyncSpInfoService
i don't why? Pls help me,thx a lot...
Try removing the 'def' in your service method parameter:
def syncSpInfoData(datasource) {} // and you don't need the throws