Reputation: 168
Given the Grails Domain Classes "Apple.groovy" and "Orange.groovy", not strictly related, and the following Grails Service invoked from the Controllers:
package test
import grails.transaction.Transactional
import javax.servlet.http.HttpServletRequest
@Transactional
class UploadService {
def uploadApple(HttpServletRequest request, Apple o) {
def file = request.getFile('payload')
o.payload = file.getBytes()
o.filename = file.originalFilename
o.contentType = file.contentType
o.save(flush:true)
}
def uploadOrange(HttpServletRequest request, Orange o) {
def file = request.getFile('payload')
o.payload = file.getBytes()
o.filename = file.originalFilename
o.contentType = file.contentType
o.save(flush:true)
}
}
How would one go about unifying this code under a common method? I was hoping Groovy's optional types would handle this for me, but I can't seem to be able invoke .save()
successfully if I remove the types from the method signature.
Thanks in advance
Upvotes: 0
Views: 529
Reputation: 766
Avoid passing request
to service and pass File
to service. Did you try it this way?
def upload(file, obj) {
obj.payload = file.getBytes()
obj.filename = file.originalFilename
obj.contentType = file.contentType
obj.save(flush:true)
}
Unlike Java, Groovy does duck typing. Typing is concerned with assigning a type to any object. Duck typing is concerned with establishing the suitability of an object for some purpose.
Now you have to be careful because this will not work for every object. The reason that it works for Apple
and Orange
is because both have exactly the same set of attributes and attribute types.
One would wonder, why you would have two different domain that behave exactly the same, but that's obviously is a different discussion.
Upvotes: 3
Reputation: 9885
In Grails 3, domain classes implement the GormEntity trait, which is where the save()
method comes from. But that doesn't solve the issue with the payload
, filename
, and contentType
properties.
What you can do is create an interface which declares the methods and properties common to both domain classes and also implements org.grails.datastore.gorm.GormEntity
. Then, have the domain classes implement the interface:
interface Uploadable extends GormEntity {
byte [] payload
String filename
String contentType
}
class Apple implements Uploadable {
byte [] payload
String filename
String contentType
}
Then, you can use the interface in your service.
@Transactional
class UploadService {
def upload(HttpServletRequest request, Uploadable o) {
def file = request.getFile('payload')
o.payload = file.getBytes()
o.filename = file.originalFilename
o.contentType = file.contentType
o.save(flush:true)
}
}
Note: Since Grails injects the GormEntity
trait into the domain classes automatically, I don't know what happens if you use it explicitly as shown.
Upvotes: 2