-
Introduction to the DTO plugin
Posted on October 6th, 2009 48 commentsData transfer objects: you either hate them or you loathe them. They give off that kind of smell that sets the alarm bells ringing and has you reaching for the disinfectant. DRY? Sorry, not today m’am. Let’s face it, anything that has you duplicating fields and performing straight copies between objects is deeply suspicious.
Despite that, DTOs still persist (pardon the pun). When you want to serialise data over RPC, they’re often one of the few options available to you. GWT-RPC is a case in point, and the reason for the Grails DTO plugin. Gilead allows you to transparently serialise Hibernate domain instances, but this only works if the domain class can be loaded by the client. Since GORM domain classes are typically Groovy, that’s not an option with GWT. Your typical Grails domain class also includes a bunch of stuff that the client is hardly going to be interested in, like the custom mappings. So we need a set of Java classes that the client can access – in other words, DTOs.
So what are the main issues with DTOs? First of all, you have to write them. In fact, you pretty much end up duplicating your domain classes! There’s little that’s more depressing. Second, you have to write code to copy the data from your domain instances to DTO instances. When done manually, this can be particularly error-prone as well as laborious.
What if we can mitigate those issues? That’s what the DTO plugin is for. It provides two features that can eliminate the labour involved with creating and maintaining DTOs. Let’s look at the first one.
Creating DTO classes
Your average DTO class is a copy of its corresponding domain class, minus all the mapping information and non-transient data. So the plugin provides a command that does this for you:
The above will not only create a MyDomainDTO class for you that has the same persistent fields as MyDomain, but it will also create DTO classes for all related classes, such as those declared via hasMany or belongsTo. In fact, if you’re not careful you can end up with DTOs for your whole domain model!
grails generate-dto org.example.MyDomain
Alternatively, if that’s what you want (DTOs for your whole domain model), then you can use
More control can be exercised with the --non-recursive option, which disables the default behaviour and means that the command will only create DTOs for the named domain classes. In other words, it doesn’t follow the relations.
grails generate-dto --all
Of course, once you have generated the DTO classes, you don’t have to stop there. If you want to limit the amount of information that will be transferred to a client, simply edit the classes and remove any fields or relationships you want. Or replace relations with a different field. For example, you may not want to return a whole user object associated with a blog post, but you might want to send the user ID or the username.
Generating the DTO classes is only half the story, though. You have to actually convert the domain instances returned by queries and the like into DTO instances.
Converting domain instances to DTOs
It’s possible to do the conversion manually if you want. You could even use Apache Commons or Spring to copy the fields from one object to another. But why? The plugin makes it easy to do the conversion by applying some Groovy magic. Given a domain instance, simply use one of the following options:
def post = Post.get(somePostId) def dto = post as DTO // or dto = post.toDTO()
The first option, as DTO, fits in nicely with the look and feel of Grails converters, but you do have to remember to import the grails.plugins.dto.DTO class. The second option doesn’t require the import, but doesn’t look quite as funky either.
With the soon-to-be-released version 0.1.2 of the plugin, you can also serialise collections and maps of domain classes:
def posts = Post.findAllByCategory("music") def dto = posts as DTOThat’s all there is to it. However, one thing to bear in mind is that things get more complicated if you edit the DTO classes. In such cases, you probably need to provide some custom mappings to ensure that the data is copied correctly. I’ve not tried it myself, but since the domain instance -> DTO mapping is done by Dozer, you should be able to provide a Dozer mapping file. Once thing I would like to add in future is easy custom mappings using Groovy instead of the Dozer XML files. ‘Til then, it’s XML I’m afraid.
For those people who find themselves in need of DTOs for whatever reason, I hope this plugin makes your lives just a bit easier. Happy coding!
48 responses to “Introduction to the DTO plugin”
-
Hi Peter,
Nice, I always thought I was doing something wrong having to copy the domain structure for the client. This seems like a must for GWT development. I tried out the plugin this morning and noticed a couple of things:Should the classes be generated in the client package so they are available to GWT? At the moment they are created in com.myApp.myDomainPackage in the java/src
Secondly I have an enum as a property in a domain. It seems the plugin tries to create DTO’s for this too and an exception is thrown:
Cannot get property ‘clazz’ on null object
at GenerateDto$_run_closure1_closure3.doCall(GenerateDto:39)
at GenerateDto$_run_closure1.doCall(GenerateDto:38)
at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)That be all!
John -
Hi John,
1. The DTO plugin isn’t just for GWT, so I didn’t want to make it do anything GWT-specific out-of-the-box. But it is an issue, yes.
2. I’ll take a look. I have an enum in my own project, so I’m surprised I haven’t run into that yet.
I have only just started using the DTO plugin with my GWT project today, and there is at least one problem worse than the above: GWT really doesn’t like the grails.plugins.dto.DTO class and creating a module for it is a pain. There are definitely plenty of kinks to work out, so there will probably be new versions of the GWT and DTO plugins by the end of next week.
-
OK, I can open JIRA’s in future if the blog is too informal. Thanks for the response
-
I’m in the process of releasing version 0.2 of the plugin. Check out the latest documentation to find out how to do package substitution/transformation.
-
Peter –
Great plugin and looking to use it in a pure-services application(i.e. no UI) that will be exposed through the Grails Remoting plugin.
This pure-services application will be used by another grails UI application, and probably something like Mule for handling integration traffic for message normalization and routing rules. My preference would be to expose only the DTO objects in the services layer, thereby leaving clients ignorant to domain objects and GORM/Groovy.
Your plugin seems to be working great for finder methods, i.e. :
class UserService implements UserServiceIF {
static expose = [ "cxf", "httpinvoker" ]boolean transactional = true
UserDTO findUserById(long id) {
User.get(id) as DTO
}
}But, I don’t see how to implement updates/creates using the DTO classes, i.e. :
UserDTO updateUser(UserDTO user) {
user.save()
}This updateUser(..) obviously fails because “user” is not a GORM domain object. How do you covert the UserDTO to a domain object?
I will admit to being new to both Groovy and Grails. So, if this is an ignorant question, I apologize. Or, is there a better way than using DTOs as an argument to the create/update methods that I am overlooking?
Sorry for the long-winded question and thanks for any help you can provide.
Steve Ardis
-
@Steve As you’ve discovered, the plugin and it’s methods are currently geared towards the domain object -> DTO conversion. It’s possible to go the other way, but there are no special methods. Here’s how it might work:
class UserService { // Inject the Dozer mapper def dozerMapper ... User updateUser(UserDTO userDTO) { def user = User.get(userDTO.id) dozerMapper.map(userDTO, user) } }However, this probably doesn’t work awfully well when it comes to relations. In fact, it will probably fall over, but I just don’t know.
It may be possible to use the code that Grails has to map parameter data to domain objects, but it would be a fair bit of work and I personally don’t have a need for it yet.
Hmmm…I’ve just thought: perhaps the code user.properties = userDTO.properties might work? I’m pretty sure it doesn’t handle relations, but it might do enough for you.
Cheers,
Peter
-
Peter,
Curious why you thought your example wouldn’t work for relations.
I was thinking about the following code and, from what I know about Dozer, it should have no problem going both ways:
private addDtoMethods(final MetaClass mc, final ApplicationContext ctx) {
…// Then the fromDTO() method.
mc.fromDTO = { Object dto ->
return mapDTOInstance(ctx, dto)
}…
}private mapDTOInstance(ctx, obj) {
// Get the appropriate domain class for this DTO instance.
def dtoClass = obj.getClass()
def dtoClassName = dtoClass.name
def domainClassName = dtoClassName.substring(0, dtoClassName.lastIndexOf(“DTO”))
def domainClass = dtoClass.classLoader.loadClass(domainClassName)// Now convert the DTO instance to a domain object.
def mapper = ctx.getBean(“dozerMapper”)
return mapper.map(obj, domainClass)
}This is untested and I’m not even really sure how to integrate this into your DtoGrailsPlugin.groovy file for testing. If I get some time, I’ll figure it out.
Steve Ardis
-
@Steve I’m simply unsure whether Dozer will update the domain objects and add new ones in a way that means the changes will be persisted correctly. It may very well work in most, if not all cases, but I just have a nagging feeling that Hibernate objects are a bit too different for it all to work smoothly. I hope I’m wrong!
To test your fromDTO() method, add an integration test to either test/projects/default or test/projects/appWithConfig, or preferably both. Start with the default test project – you’ll find an integration test already there that tests the toDTO() method.
-
>> Data transfer objects: you either hate them or you loathe them. They give off that kind of smell that sets the alarm bells ringing and has you reaching for the disinfectant.
Is it any less smelly to tightly couple the business domain model to the UI (especially fat client UI’s)?
The whole issue of interfacing the domain model to the presentation layer (similar to the issue of ORM’s in my opinion), is messy with no perfect solution i can see.
Remoting the domain model to the UI seems great at first thought, and yes, maybe 80% of the UI model is similar to the domain model. But it’s that other 20% that can end up corrupting the domain model. Separation of concerns, loose coupling, these are ideas that are at least (if not more) important than DRY.
But on the other hand, at least for smaller projects, the productivity gains of skipping DTO can be compelling.
-
@marko While I mostly agree with you, I think you’re missing the fact that you can modify the DTO classes after you have generated them. The initial generation allows you to get off the ground quickly, but after that you can fine-tune the DTOs and exclude fields and relations that shouldn’t be visible to the clients. At that stage, you need to take advantage of Dozer’s mapping files.
One day I hope to provide an easier mapping mechanism than the XML files, but they work for now.
-
Sorry Peter, my comment was not a criticism of DTO’s/Dozer. On the contrary, i have a strong philosophical pull towards decoupling the UI and domain model. The only way to do this is through some form of DTO (my favored interpretation is REST documents). Of course the uncomfortable baggage that comes with a clean separation of models is some amount of repetition.
My comments were more directed towards the perception that using the domain model as-is from a disconnected context (like a fat UI), is not only a preferable architecture to DTO’s, but is goal that tools should strive to enable.
Personally i have been questioning myself for years, wondering what the right answer is to DTO vs direct domain model? My pure/simple side says “always REST” (or DTO), but my pragmatic/productivity-craving side is open to finding some mechanism to “transparently” operate on remote managed domain model objects. It’s always nice to get something for nothing, but at what cost does the immediate gratification come with?
-
No worries. I pretty much agree with you on using a server-side domain model from a client. I prefer the decoupling enabled by DTOs and XML/JSON.
-
I am using the DTO plugin together with GWT plugin. When running in the hoted mode the GWT compiler complains that it can’t find grails.plugins.dto.DTO interface to compile the generated DTO classes. Is there a setting that I am missing? Are the plugin classes exposed to GWT?
Thanks for your work.
-
You need to include the DTO module:
<inherits name="grails.plugins.Dto"/>You’ll need the latest snapshot of the GWT plugin (that I’ve just released) for this to work.
-
Hi Peter,
Thanks for the plugin.
I like toString() methods on the DTO’s. So I’ve added
// toString()
writer.write “\n\t@Override”
writer.write “\n\tpublic String toString() {”
writer.write “\n\t\tStringBuilder sb = new StringBuilder();”
writer.write “\n\t\tsb.append(\”${dc.shortName}DTO[\");"
fields.each { field ->
writer.write """\n\t\tsb.append("\\n\\t${field.name}: " +
this.${field.name});"""
}
writer.write "\n\t\tsb.append(\"]\”);”
writer.write “\n\t\treturn sb.toString();”
writer.write “\n\t}\n”just above
// Class terminator.
writer.write “}${eol}”in my local ~/.grails/1.2-M3/projects/mbservice/plugins/dto-0.2/src/groovy/org/codehaus/groovy/grails/plugins/dto/DefaultGrailsDtoGenerator.groovy
Maybe you could add it to the official plugin?
Best
Anders -
Hi Anders,
Could you raise a JIRA issue and either attach a patch or fork the plugin’s GitHub repository and send a pull request?
http://jira.codehaus.org/browse/GRAILSPLUGINS/component/14200
Make sure you set the component to “Grails-DTO”.
Thanks,
Peter
-
Natraj November 12th, 2009 at 10:32
I’m running grails 1.1.1, and I just downloaded the dto plugin ( using the grails plugin command).
I’m still having the issue another user had when my domain class has a reference to an enum.
there are several more issues.. when I use the –all and –pkg arguments, it seems to create classes inside .true, and the classes just have a package declaration called ‘true’.Should I upgrade to a grails 1.2 M build?
thanks
Natraj -
Natraj November 12th, 2009 at 12:21
More on the enum problem:
Initially, my enum was under src/groovy. After having the “Cannot get property ‘clazz’ on null object” error, I tried putting it under
src/domain
That did a little better in terms of generating the class referring to the enum, but since it couldn’t generate the DTO corresponding to the enum, the code wouldn’t compile.
Next, I tried changing the enum to a Java enum, and putting that under src/java.
Again the “Cannot get property ‘clazz’ on null object” error.thanks,
Natraj -
@natraj The “true” issue is specific to Windows. We could really do with some committers who use that platform because we’re all Linux/Mac OS X. Unfortunately there’s no workaround at the moment.
As for enums, could you please raise a JIRA issue with a reproducible example? Thanks.
-
Natraj November 14th, 2009 at 10:52
One other question:
I pulled the DTO plugin using the grails command – and it shows that the plugin version is 0.2.2
With this, the GWT (1.7) seems to be having trouble with the declaration.When I try the ‘gwt-compile’ command, I see this error:
Compiling GWT modules …
Module: com.episoft.PatientInfoScreen …
Loading module ‘com.episoft.PatientInfoScreen’
Loading inherited module ‘grails.plugins.Dto’
[ERROR] Unable to find ‘grails/plugins/Dto.gwt.xml’ on your classpath; could be a typo, or maybe you f
orgot to include a classpath entry for source?
[ERROR] Line 2: Unexpected exception while processing element ‘inherits’
com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)
at com.google.gwt.dev.cfg.ModuleDefLoader.nestedLoad(ModuleDefLoader.java:225)
at com.google.gwt.dev.cfg.ModuleDefSchema$BodySchema.__inherits_begin(ModuleDefSchema.java:212)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) -
@natraj Your version of the GWT plugin may not be recent enough. I think the latest 0.5-SNAPSHOT should work for you.
-
i came across a problem mapping my domain class(es) to the dozer dtos: dozer or the dto plugin have no options to limit the “mapping depth”… it just initializes any hibernate proxy or collection it finds in the whole object graph that is to be mapped.
now i have got a db schema respectively domain class associations that result in the whole database being sqeezed out by dozer because it just “does not stop”.any common workaround here? a similar dozer feature request to make a “depth-limit” parameter available in dozer seems to be stuck since mid 2k8
zyro
-
Hi Peter,
I have also encountered the same error as Natraj and I installed the GWT plugin 0.5-SNAPSHOT thru the grails install-plugin command.
The Dto.gwt.xml file seems missing in the plugin source.
Lik
-
I’ve just installed the plugin into a fresh application and verified that the DTO module file is here:
~/.grails/1.2.0.BUILD-SNAPSHOT/projects/gwt-app/plugins/gwt-0.5-SNAPSHOT/src/gwt/grails/plugins/Dto.gwt.xml
Are you sure it’s not there? If it’s not, what platform are you running on? Maybe it’s something platform-specific.
-
Hi Peter,
I am using grails 1.1.2 on Mac OS X. I have verified that the Dto.gwt.xml is also in my plugin source folder. It seems that grails 1.1.2 could not find the gwt plugin source under the src/gwt folder.
The problem has been resolved after I upgraded to 1.2.0.RC2.
Many thanks for you help.
Lik
-
Hi Peter,
I’m using grails 1.2.0, dto plugin 0.2.2 and gwt plugin 0.4.1 on Mac OSX. When I run grails generate-dto I get a NullPointerException :
grails generate-dto M1_user
Welcome to Grails 1.2.0 – http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /Users/don/Desktop/grails-1.2.0
Base Directory: /Users/don/Desktop/grails-1.2.0/GwtTutorial
Resolving dependencies…
Dependencies resolved in 2043ms.
Running script /Users/don/.grails/1.2.0/projects/GwtTutorial/plugins/dto-0.2.2/scripts/GenerateDto.groovy
Environment set to development
Compiling GWT i18n properties files …
Module: org.grails.gwttutorial.Application …
No i18n Constants file found
No i18n Messages file found
Finished compiling the i18n properties files. …
Compiling GWT modules …
Finished compiling GWT modules …
Compiling GWT i18n properties files …
Module: org.grails.gwttutorial.Application …
No i18n Constants file found
No i18n Messages file found
Finished compiling the i18n properties files. …
Compiling GWT modules …
Finished compiling GWT modules …
Error executing script GenerateDto: java.lang.NullPointerException: Cannot invoke method replace() on null object
gant.TargetExecutionException: java.lang.NullPointerException: Cannot invoke method replace() on null object
at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:331)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy)
at gant.Gant.withBuildListeners(Gant.groovy:344)
at gant.Gant.this$2$withBuildListeners(Gant.groovy)
at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
at gant.Gant.dispatch(Gant.groovy:334)
at gant.Gant.this$2$dispatch(Gant.groovy)
at gant.Gant.invokeMethod(Gant.groovy)
at gant.Gant.processTargets(Gant.groovy:495)
at gant.Gant.processTargets(Gant.groovy:480)
Caused by: java.lang.NullPointerException: Cannot invoke method replace() on null object
at GenerateDto$_run_closure1_closure3.doCall(GenerateDto:95)
at GenerateDto$_run_closure1.doCall(GenerateDto:94)
at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)
… 10 more
Error executing script GenerateDto: java.lang.NullPointerException: Cannot invoke method replace() on null object
Application context shutting down…
Application context shutdown.Any suggestions?
Thanks,
Don -
Barton January 26th, 2010 at 10:27
Hi,
Just starting to learn Grails so maybe I’m missing something with how to run DTO.
From my root I entered:
grails generate-dto –non-recursive Actor
And got the following stack trace:
Error executing script GenerateDto: java.lang.NullPointerException: Cannot invok
e method replace() on null object
gant.TargetExecutionException: java.lang.NullPointerException: Cannot invoke met
hod replace() on null object
at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:331)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy)
at gant.Gant.withBuildListeners(Gant.groovy:344)
at gant.Gant.this$2$withBuildListeners(Gant.groovy)
at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
at gant.Gant.dispatch(Gant.groovy:334)
at gant.Gant.this$2$dispatch(Gant.groovy)
at gant.Gant.invokeMethod(Gant.groovy)
at gant.Gant.processTargets(Gant.groovy:495)
at gant.Gant.processTargets(Gant.groovy:480)
Caused by: java.lang.NullPointerException: Cannot invoke method replace() on nul
l object
at GenerateDto$_run_closure1_closure3.doCall(GenerateDto:95)
at GenerateDto$_run_closure1.doCall(GenerateDto:94)
at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)
… 10 more
Error executing script GenerateDto: java.lang.NullPointerException: Cannot invok
e method replace() on null objectThe Actor.groovy (no package) class is:
class Actor {
static belongsTo = Film
static hasMany = [films: Film]String firstName
String lastNamestatic constraints = {
firstName(nullable: false, blank: false, maxSize: 45)
lastName(nullable: false, blank: false, maxSize: 45)
}static mapping = {
id column: “actor_id”
films joinTable: “film_actor”
sort lastName: “asc”
version false
}String toString() { “${firstName} ${lastName}” }
void setFirstName(String firstName){
this.firstName = firstName?.toUpperCase()
}void setLastName(String lastName){
this.lastName = lastName?.toUpperCase()
}
} -
Despite having a plethora of tests, none of them actually tested domain classes with no package – doh! This has been fixed in version 0.2.3 of the plugin.
-
Hi, I’m writing a tutorial on GWT on Grails using the DTO plugin (previously I did one without using it), after executing “grails generate-dto” the generated DTO implements grails.plugins.dto.DTO, but that has not been imported or anything else in my project.
I found that it is a simple interface residing deep in ./.grails/1.1.2/, so the question is: do I have to copy paste this in my project the first time to have all working properly or am I doing something wrong and that’s why I do not see “by default” this interface?Thank you in advance and for the plugin
Ciao
-
@Alberto You have to inherit the DTO module:
<inherits name="grails.plugins.Dto"/>
I also have these set up as source paths:
<source path="client"/> <source path="shared"/>
-
Thanks for the quick reply.
Yes, I did the inherits part, yesterday I saw you said that to another user, but that did not solve my problem, which is: I do not have the DTO file in my project. You set those source paths, ok, but where did you put the class? I do not have a “shared” path, do I have to put DTO.java inside a folder of my choice and then link it with ? -
What version of the GWT plugin are you using? Do you have the DTO plugin installed (I assume yes based on the fact you found the DTO source file)? Are you running into problems when doing grails compile or grails compile-gwt-modules?
The GWT plugin (depending on the version) should check whether the DTO plugin is installed and if so, add its src/java directory to the GWT compiler classpath.
-
Sorry for the delay, I was at work and I don’t have my stuff there.
GWT plugin at version 0.4.1, yes I have installed the DTO plugin, which is at version 0.2.3.
No problems during compile in each of the two.It’s not doing that… what can I do to solve this? Copy paste the DTO interface into src/java?
-
You need version 0.5 of the GWT plugin. Alternatively, patch the scripts/_GwtInternal.groovy file to include:
// Must include src/java and src/gwt in classpath so that // the source files can be translated. if (new File("${basedir}/${gwtSrcPath}").exists()) { pathElement(location: "${basedir}/${gwtSrcPath}") } pathElement(location: "${basedir}/${grailsSrcPath}") pathElement(location: grailsSettings.classesDir.path) // Add the plugin's module paths. pathElement(location: "${gwtPluginDir}/${gwtSrcPath}") pathElement(location: "${gwtPluginDir}/${grailsSrcPath}") // Add the DTO source path if that plugin is installed in // the current project. if (getBinding().variables.containsKey("dtoPluginDir")) { pathElement(location: "${dtoPluginDir}/${grailsSrcPath}") } -
I had no luck upgrading in my previous project: I upgraded the gwt plugin to 0.5 and then run grails install-plugin dto. I still don’t have the DTO interface.
I created a new project and run:
grails install-plugin gwt
grails install-plugin dto
…and I still don’t have the DTO interface.I’ll try the patch way, but I’m confused, there must be something wrong I’m doing here…
-
What’s the error? Please show complete command output within a <pre> block.
-
I get the compile time error because in my project there is no interface DTO in the grails.plugins.dto package.
I pasted the installation output of the two plugins:
1) gwt plugin – http://pastebin.com/f3a73a35
2) dto plugin – http://pastebin.com/f6456880I also tried this procedure on my pc at work but with no success.
-
Sorry, I meant I need the command output with the compile error in it. I can’t reproduce the problem myself.
-
Ok, thanks to Peter that solved my problem, I was using Springsource Tool Suite, I just had to make a Grails Tools -> Refresh Dependencies.
I’ll write a tutorial on this with all the tips. Thanks again.Ciao
-
hi,
i have a grails web app and a grails plugin which houses all the domain classes and services that sit on top of these. I have changed the services to return DTOs using the plugin. However , i seem to have to install the dto on the client side (the web app) too, surely i should have to do this ?
Anyway I installed it on both sides, now I am getting a stackoverflow error when i try to do a tostring on my userDTO as it has roleDTos attached to it which in turn has the same userDto attached to itself – so it goes round and round and bombs out. Is there a solution to this without having to exclude some dtos ?
-
peter, i’m reasonably new to grails but have been working with GWT for a couple years. i’ve been using both your GWT and DTO plugins in getting going with grails, so first off, thanks for that.
probably because of my previous experience with GWT i’m used to a command pattern approach via GWT-RPC. been looking at your command pattern blog and now this one.
what i wanted to ask is, what’s your preferred architecture for GWT communication with the server? i found the comment in one of your responses above:
> No worries. I pretty much agree with you
> on using a server-side domain model from
> a client. I prefer the decoupling enabled
> by DTOs and XML/JSON.right now i’ve got it working by using the command pattern approach with action handlers, with the action and response command objects wrapping DTO classes. but i’m just wondering if that’s the best way to go long term, and if a cleaner approach would be to use RequestBuilder (which i don’t have experience with) to call REST apis and render the responses from grails as JSON. i don’t know if i’m that excited about getting into javascript overlay types and all that in GWT, but it may just be best to bite that bullet and do it.
so, just wondered if you could elaborate a bit on your comment about decoupling enabled by DTOs and XML/JSON and how you actually go about doing that.
thanks!
dave
-
@dave I would ask on the grails-gwt Google group/mailing list. One or two people are using RequestBuilder with JSON responses and they say that’s the best way to go. I don’t have any experience with it myself, but it’s a more natural fit on the server side for Grails. I’m sure you can rejig the command pattern to work with JSON responses.
Sorry, I haven’t done active GWT development for over half a year now and I wasn’t an aficionado in the first place
-
thanks peter. i found at least one discussion on the grails-gwt group on the topic and started to draft an email to see if i could get any more or new info out of anyone. (i’ve since gotten kind of distracted.)
i’m now leaning towards RequestBuilder and JSON just so there is a clearer separation between GWT on the client and grails on the server. using the gwt plugin, dto, and action handlers it seemed to be getting mixed together a bit too much.
whatever i end up doing i need to make sure that not only are the client and server loosely coupled, but also the code calling into that communication on both ends is also abstracted enough so if i decide to switch anything later it minimizes the risk.
regardless, fun stuff.
thanks again.
dave
-
Srinivas February 28th, 2011 at 17:29
Peter,
Two questions:
1. Once the DTOs are generated, if we remove few attributes (and getters/setters), and perform toDTO() at runtime, will it give Exception or only map the available fileds in DTO?
2. We are currently doing DTO -> Domain objects using domain class constructor which takes DTO as input, and use this.s1=dto.getS1() methods.. This is writing lot of code in the constructor. Any short-cut here?
Regards,
Srinivas. -
- To be honest, I don’t know. It depends on what Dozer does (the plugin uses the Dozer library to map the domain classes to DTOs). I think only properties that are common to the domain class and the DTO are copied across.
- I think you’re much better off using ‘new DomainClass(dto)’ or ‘bindData(new DomainClass(), dto)’.
Hope that helps,
Peter
-
Danil March 4th, 2011 at 17:48
Hi
I have a grails project, structured this way:
- “admin-domain-plugin” (plugin with only domains)
- “admin-app” which embedds “admin-domain-plugin”i’m writing a module “A” (with it’s own domains), and i want it to communicate by jms with “admin-app” via DTO objects without knowing about admin domains.
My first idea was to create “admin-dto-plugin”, include “admin-domain-plugin” in it, generate DTOs and than install “admin-dto-plugin” into module.
The problem is with enums : no DTO objects are generated for them so enums are left in “admin-domain-plugin” and grails is unable to resolve them in module “A”.Is there any way to force grails to distribute some of sub-plugin’s classes along with plugin (to inherit them)? I don’t want to install “admin-domain-plugin” into module “A”
Thanks in advance
-
Srinivas April 22nd, 2011 at 21:50
Peter,
Thank you very much for the response.
I am currently using a constructor in Domain Class that takes DTO as input and assigns data to its variables.
public def RewardAccount(RewardAccountDTO dto) {
this.accountId = dto.getAccountId();
this.cards = dto.getCards();
this.customer = dto.getCustomer();
this.nickName = dto.getNickName();
this.transactions = dto.getTransactions();
}Are you mentioning that the same can be achieved by writing:
bindData(new RewardAccount(), RewardAccountDTO)
If so, this can be done from services. right? And, where is the bindData() method available? Thanks for the info. -
This article has one example of adding bindData() to a service:
Unfortunately, the standard bindData() method is only available on controllers:
http://grails.org/doc/latest/ref/Controllers/bindData.html
That’s why you currently have to jump through a few hoops to use get bindData() in a service.
Hope that helps,
Peter
Leave a reply
-





Social Media