I was wondering if it\'s possible to create a service interface on Grails and I can\'t find a proper way of doing it. This explanation isn\'t satisfactory, since it seems to mix
Its not a design flaw. Groovy is different than java in that it is a dynamic language that uses 'duck-typing'. Whats interesting in groovy is that there are also interfaces. So if you follow @don's suggestion, you can make sure that your service conforms to the interface, but the way you do DI with grails is to just specify the service implementation. i.e. you do not get the compile time check where you use the service implementation, like you do in java.
Note that there is no tight coupling here. Coupling implies that something is bound to a type. But with groovy's loose typing system, types are essentially dynamic creatures. So in java, if you declare a type to be a specific implementation, the code might not compile if you change the type later. In groovy, the code will always compile if you use the 'def'...(I think this is correct)
You can have an interface, but actually you don't need one. If I understand you correctly you would like to have two implementations of a service and be able to choose which one to use.
Simply implement two services named for example MyService1
and MyService2
, then in grails-app/conf/spring/resource.groovy
you can specify:
beans = {
...
// syntax is beanId(implementingClassName) { properties }
myService(MyService1)
...
}
or even:
beans = {
...
if (someConfigurationOption) {
myService(MyService1)
} else {
myService(MyService2)
}
}
This is how you tell Spring which service to actually inject for myService
. Now you will be able to use myService
like:
public MyController {
def myService
...
}
and Spring will auto wire a proper implementation. This allows you to configure which service implementation to use based for example on some configuration.
com.mycompany.mypackage.MyInterface.groovy
stored under src/groovy
Define the service implementation stored under grails-app/services
class MyService implements MyInterface {
// service implementation goes here
}
The best solution I found for this is using Spring bean aliases. Basically you need to:
1) Create an interface in src/groovy ( MyService.groovy
)
2) Inject your service wherever you need it:
class MyController {
MyService myService
}
3) Create your regular services implementing that interface ( ImplOneService.groovy
, ImplTwoService.groovy
)
4) Add an entry to resources.groovy where you define which implementation to use (eventually, testing for environment, or anything else you need):
beans = {
if (...development, useFTP, etc...) {
springConfig.addAlias 'myService', 'ImplOneService'
} else {
springConfig.addAlias 'myService', 'ImplTwoService'
}
}
Complete sources here
My comments: Using interfaces in groovy really seems like some kind of "I want to stick with some java stuff I'm more comfortable with". In this case, strong-typing. But it's exactly the nice part of groovy saying "No worries, you can keep the java way if you want".