Archive

Author Archive

You don’t know what you don’t know

October 12th, 2010 No comments

Disclaimer: If you are reading this post, then you probably don’t need to.  It likely doesn’t contain anything that you don’t already know or practice.  But perhaps it will help you convince a co-worker who is still pounding away in the dark.

I used to believe that I didn’t need to keep up with technical RSS feeds or newsgroups. I learn things quickly and know how to use Google. Thus, if I ever wanted to find some tool to accomplish a certain task or if I hit a problem with a library I was using, I could quickly go out and find what I was looking for. Spending time reading the Hibernate user group and the JBoss user groups and the Spring user group and all the rest just took away time from designing and implementing the next feature on the schedule. Who could possibly remember all the other new product, library, and feature announcements unless you had a need for them right then?

I now know that this is an excellent way to regularly reinvent the wheel. Why? Because you don’t know what you don’t know. Sometimes it’s easy to guess when there are tools, libraries, or entire languages that can help you do your job. For example, we all know that there are many ORM, logging, and xml-parsing libraries.  There are many situations, however, where it is unlikely that you will realize you are facing a problem that someone else has already solved.

This happened to me last spring.  We were in crunch time trying to finish up a release and I had fallen behind on my feed/newsgroup reading.  I winced every time I opened up Google Reader and saw the unread count tick higher and higher.  As part of this release, I wrote a handy little utility routine that let me override a single method of a class by using groovy’s ExpandoMetaClass.  The nice thing about the routine was that it always discarded the modified MetaClass after the closure that was passed to it finished.  I could thus remove the many try…finally blocks that were piling up in my tests as a tried to make sure I didn’t corrupt a MetaClass from one test to another.

A couple of days later, I was able to whittle down the backlog in Google Reader.  That’s when I saw this entry from mrhaki: http://mrhaki.blogspot.com/2010/03/grails-goodness-using-metaclass-with.html.  Built into the GrailsUnitTestCase class was a method that did exactly what I wanted, plus a lot more – registerMetaClass.  Given, my utility routine can be used outside of a Grails’ unit test, so it’s not a complete waste.  But I could have saved myself a few hours of effort if I had been up to date on my reading.  Perhaps I could have spent those hours catching up on the rest of my “To Read” list…

Categories: pain, Testing Tags: ,

Using Hudson to run tests in parallel

October 11th, 2010 1 comment

We have been using Hudson to do CI on our grails application for a few months now. We use it to run unit, integration, jsunit, and functional (via selenium) tests, as well as code coverage metrics using Cobertura. Since this was the first project that we used Hudson for, the person who originally set it up just put all of these steps into a single job. It worked fairly well, but a single build was taking between 20-30 minutes, depending on how extensive the changes were. This can be a real pain, especially during very active development cycles when you most need rapid feedback. I decided to look into how I could run the tests in parallel, and hopefully get our build times to under 5 minutes. This is what I have come up with so far. It’s not perfect, but the tests do run more quickly (around 5 1/2 minutes total, primarily limited by the speed of the Selenium tests).

Primary Job – Poll and Build

The primary job is very simple. It polls Subversion and executes clean and test-compile targets. (We use maven with the grails-plugin to compile the app.) It normally only takes 30-40s to run. It doesn’t do a full package/install because that adds another minute to the build time.

Primary Build Steps

Build steps for the primary job

Using the Groovy Plugin

One shortcoming of not running the package step is that the job doesn’t generate a unique file that can be used for fingerprinting like a jar or a war. You need to turn on fingerprinting in order to aggregate test results.  (More on that subject, below.)

To resolve this, I used the Groovy plugin to execute a one-line script to generate a unique file for this purpose. I pass in the path and build information as script parameters rather than environment properties because the Groovy plugin doesn’t resolve Hudson environment variables when they are set in the Properties field. This seems like a big shortcoming, so perhaps I just misunderstand how to pass them correctly as properties.

A side-effect of using the Groovy command option rather than invoking an existing Groovy script is that you end up with a copy of the script in your workspace directory. In fact, you get a copy of it for each build. I am not certain why the plugin needs to generate the script file at all as opposed to just running it in memory. Hopefully, this will get corrected in a future release. For now, I may put the script in a regular file just so I don’t have to clear out all the temps.

Downstream Jobs – Test, Test, Test

The tests are divided into 3 downstream jobs that are kicked off when the primary job has a successful build. The jobs run the unit and integration tests, the Selenium tests, and the JsUnit tests, respectively. I didn’t bother splitting out the unit and integration tests into separate jobs because they take less time combined than do the Selenium tests. I could easily split them out later.

Cloning the Workspace

In order to speed up the downstream jobs, I didn’t want to pull the code for each and recompile. Instead, I used the Clone Workspace SCM Plugin to make copies of the primary job’s workspace for each downstream job. This adds only a few seconds to the primary job in order to create the zip archive.

Cloning a workspace - upstream project view

Cloning a workspace - downstream project view

I had two small issues with the plugin:

  1. The zip command doesn’t include empty directories by default. This can be an issue if any of your tests in downstream jobs expect some directories to be there already.
  2. In the downstream job, the working directory is set to the workspace directory itself rather than the (sub-)directory pulled from Subversion as it is in the primary job. This makes sense since the Clone Workspace plugin does clone the entire workspace and not just what was pulled from the SCM system. It just threw off some of the tests that expected files at specific paths. (Yes, I know – the tests should be more flexible. It’s “on the list…”)

I need to do more research to see if I can use this approach when I spin up some slave machines. I will post when I tackle that issue.

Downstream Build Steps

The build steps for the downstream jobs look like this:

Unit and Integration Tests Job

Funtional Tests Job

JsUnit Tests Job

You can see that the two jobs which run the server-side test jobs execute a shell command rather than a regular maven target. This was because of the working directory issue I mentioned above. I use the shell to cd into the proper directory first, and then execute the tests. A little hackish, but it was a good experiment with using the Execute shell build step.

You can also see how many different ports are used by the tests – the JsUnit acceptor servlet, the Selenium server servlet, the app itself when launched for Selenium, etc. I use the Hudson Port Allocator Plug-in to keep tests from stomping on each other.

Aggregating Test Results and Fingerprinting

I turned on test aggregation in the primary job so I could get a single view of test results. In order for this to work, the primary job needs to know how to associate specific downstream builds with specific builds in it. This is done through the fingerprinting feature. None of the docs mention this connection. I didn’t figure it out until I did a build, clicked on the Aggregate Test Results link, and saw this error message:

Generating a unique-per-build file using the above Groovy script (discussed above) let me link the jobs together for aggregating.

NOTE: You do not select the “Publish JUnit test result report” option in the primary job as part of this feature. That option is only used in the jobs that actually run the tests. If you turn it on in the primary job, you will get an error during the build because there are no JUnit files for it to process.

The Aggregate Test Results feature is nice since it provides links through to the test results pages for the downstream builds and a simple table listing the fail/total counts from the downstream builds.

Aggregate results report for a good build

Unfortunately, there appears to be a bug in it where it will not report results for any downstream job that has failures. A failing downstream job is shown in the build details page for the primary job

Aggregate results summary with failing job

but you can see that the Aggregated Test Result link lists “no failures.” Clicking that link shows the summary table, but it is missing a line for the downstream job with failures:

Aggregate results, but failing job is missing

In addition to having this bug, the feature does not show the test result trend chart or the tests by packages in the primary build. This makes it of very limited usefulness.

Next Steps

I was able to accomplish my primary goal of cutting our CI build times, but not without losing some required output.  Most of the shortcomings for this approach are related to one core issue – Multiple jobs means multiple places to configure and view results. For example, I had to configure failure email notifications in all downstream jobs rather than just one. Also, there is no way to get an aggregated code coverage report that spans all the tests (unit, integration, and functional). I could live with not having a single view of all test failures since I can get that info from the downstream jobs, but not having accurate code coverage metrics is not an option. I have to figure out a way around that.

Since most of the problems with this configuration were related to aggregating the test results (both direct results and coverage stats), my next step will be to try a “diamond” build configuration using the Join Plugin. Hopefully, I can pull all of the test results, coberturra.ser, and other such files into the bottom of the diamond to get a single place to view the status of the build.

I also want to get CodeNarc output displaying for the job via the Violations plugin. I can generate the CodeNarc output, and the Violations tries to parse it, but it then crashes with an NPE. I need to narrow down what part of the file is causing the exception so I can report the issue.

Categories: Testing Tags: ,

Hudson + Windows + JsUnit = Boom

October 5th, 2010 No comments

Anyone thinking about upgrading Hudson on a Windows box might want to hold off for a bit if you have any Ant build steps. In Hudson v1.370, they introduced a change for parsing some Ant parameters (HUDSON-7108). However, this caused several other problems, including one that will bust any step you have that runs JsUnit tests (HUDSON-7657). I banged my head against this for a while before I realized that my configuration changes hadn’t caused the problem, so I thought I’d try to save others some pain.

Categories: Testing Tags: ,

Mr. Haki tears it up

June 15th, 2010 No comments

I always love the Groovy Goodness blog. So many gems in such a compact space. He just posted about a dozen tips in the past day alone, all on stuff that I could use in one project or another. The only thing I don’t like about it is it makes me want to go in and update all the places in my code where I could use the new calls right now. Major time suck… must resist… ohhhh… may just one little tweak…

Categories: Uncategorized Tags:

Validation differences between Grails 1.1 and 1.2

June 9th, 2010 No comments

…or My Penance For Ignoring Validation Errors…

We recently updated our app from Grails 1.1.1 to 1.2.2. (We wanted to move all the way to 1.3.1 but since we build with maven, we finally decided to wait until a new grails-maven plugin is released. See GRAILS-6327.) During the upgrade, we hit two particularly annoying issues related to persistence and setting up associations.

The first involved a belongsTo relation like this:

class AppUser {
    UserPrefs prefs = new UserPrefs()
}

class UserPrefs {
    static belongsTo = [user: AppUser]
}

This worked under Grails 1.1, but under Grails 1.2 the prefs object was not getting persisted when the user was saved. Other belongsTo relations, both one-to-many and one-to-one worked as expected. We finally discovered that using the short form of the relation notation did work:

static belongsTo = AppUser

This post provided a clue as to where the problem may be. The user property of the Prefs object is not automatically set because the relationship is one-to-one. (At least, it is not automatically set all the time. If we load an AppUser object with Hibernate, it appears that the user property is set in the UserPrefs object. Go figure.) Under Grails 1.1, having a null user was apparently fine. My guess (based on the second error we hit, below) is that any validation errors caused by the child object were not stopping the save of the parent object. Grails 1.2, on the other hand, does care about the child object validation, though I could never get it to report anything in the errors property of either the parent or child object.

In order to work around the issue, I loosened the constraints on UserPrefs a little:

class UserPrefs {
    static constraints = {
        user(nullable: true)
    }
    static belongsTo = [user: AppUser]
}

With this change, cascading persistence works. Given, it’s not an ideal solution, but it does let us have access to the user property if needed.

What made this extra confusing is that we have a similar relationship in another set of classes that worked without a problem. The only difference there is that the child class is not automatically created with a static initializer as is done in for the prefs property in AppUser. It is always explicitly set into the owning object. I’ve run out of time to pursue this one further, so I don’t have a final answer. Anyone else out there have more insight into this?

The second persistence issue related to this section of code in the update method of one of our controllers:

def update = {
    def hubMap = HubMap.get(params.id);
    hubMap.properties = params;
    if (hubMap.save()) {
        ...add success message to response...
    } else {
        ...add failure message to response...
    }
    ...
}

Again, the code worked fine under Grails 1.1.1, but the save call failed under 1.2.2. Unfortunately, there was a hole in both our unit and integration tests for this method, so we didn’t catch it until much later in the release cycle.

Was the JSON conversion in the controller’s get method that generated the original data for the browser different? Nope.
Had the behaviour of the properties meta-method changed? Nope.

The difference is in how Grails handles any existing validation errors on a domain object when you call save(). In our case, the JSON that was being sent to the controller (via a Prototype AJAX call) contained two properties that were references to other objects. The javascript object conversion in the browser was not setting these properties in a meaningful way for the AJAX call; they were both coming across with the string value [object Object]. Since these fields are never updated in this particular workflow, we had never checked what was happening to them. Grails obviously could not convert from the string values to the proper objects, it ignored the values and set two errors on the domain object to record them. However, we didn’t check for errors after the properties call. We went straight to the save call. Under Grails 1.1, deep within the saving sequence in a random class called AbstractDynamicPersistentMethod, you come across this bit of code:

doInvokeInternal(...) {
    ...
    Errors errors = new BeanPropertyBindingResult(target, target.getClass().getName());
    mc.setProperty(target, ERRORS_PROPERTY, errors);
    ...
}

Any existing errors are replaced with a fresh, clean BeanPropertyBindingResult object, wiping out the error information. We never spotted it because we never expected the properties with errors to change anyway. That hole has been closed in Grails 1.2:

doInvokeInternal(...) {
    ...
    Errors errors = setupErrorsProperty(target);
    ...
}

The new setupErrorsProperty call will copy out existing errors. We put in a few adjustments to not attempt to update those properties and all is well.

So there you have it. A couple of gotchas in the upgrade path for grails. Hope this saves some folks from banging their head against the wall.

Grails, Maven, packaging, and skipTests fun

April 22nd, 2010 No comments

The grails maven plugin honors the maven.test.skip option (which turns off compiling and executing tests), but not the skipTests option (which only turns off executing tests). This means that you cannot easily create a package with test classes in it without running all of the tests. I finally come up with a close work around:

mvn clean grails:exec install -Dcommand=test-app -Dargs="-unit DoesNotExist" -Dmaven.test.skip=true

By explicitly listing the test-app command but specifying a test that does not exist, I was able to get the unit tests to be compiled. Since I only needed some common testing files in my package, this works for me. If someone wanted to package both the unit and integration tests, I don’t think this would work. I filed a new issue in the Grails Jira to try to get a real resolution.

Grails+Maven+GeoTools+PdfBox = PITA

March 20th, 2010 No comments

Here’s a bit of maven-voodoo for you. If you have a Grails (1.1.1) app that is built with Maven (2.1) and you try to link in GeoTools (specifically the gt-xsd-core module) and you try to bring in PdfBox as well, you will get really fascinating class loading and linking problems revolving around various XML pieces. I finally found two different ways to get rid of the errors. For those who like to cut to the chase, I’ll list the solutions first and then explain a bit more what errors I was seeing.

Solution #1: Exclude, exclude, exclude

If you don’t need commons-jxpath, you can add these three exclusions to the gt-xsd-core dependency declaration.

    <dependency>
        <groupId>org.geotools.xsd</groupId>
        <artifactId>gt-xsd-core</artifactId>
        <version>${gt.version}</version>
        <exclusions>
            <exclusion>
                <groupId>commons-jxpath</groupId>
                <artifactId>commons-jxpath</artifactId>
            </exclusion>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis</artifactId>
            </exclusion>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis-xerces</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

This at least works for me given the subset of geotools functionality I am using (primarily encoding and parsing OGC Filter objects to and from XML so I can persist them with Hibernate). It is still pulling in xercesImpl and that appears to be enough, at least to get my unit and integration tests working.

Solution #2: Using Dependency Management

If you need the commons-jxpath functionality in gt-xsd-core, add this to your dependencyManagement section of your POM:

    <dependencyManagement>
        <dependencies>
            <!-- The gt-xsd-core tries to bring commons-jxpath 1.2 in.  That messes up the maven junitreport plugin for
            some reason (like links to a version of xalan or xml-apis or something.  The 1.3 version doesn't have that
            issue. -->
            <dependency>
                <groupId>commons-jxpath</groupId>
                <artifactId>commons-jxpath</artifactId>
                <version>1.3</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

and then keep the exclusions for the xml-api artifacts as above:

    <dependency>
        <groupId>org.geotools.xsd</groupId>
        <artifactId>gt-xsd-core</artifactId>
        <version>${gt.version}</version>
        <exclusions>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis</artifactId>
            </exclusion>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis-xerces</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

This is what I have setup in my POM right now because I think I might need jxpath soon. I also tried adding a node in dependency management to use the 1.3.03 version of xml-apis rather than 1.0b2 (which is what was pulled in by default), but that doesn’t appear to make any difference. I still had to have the 2 exclusions under gt-xsd-core for things to work.

So what was the problem?

Now, a little more about the problems I had. I had two types of errors:

Maven junitreport conflict – When I added the dependency for gt-xsd-core and then ran my unit tests using the maven grails plugin (mvn grails:exec -Dcommand=test-app -Dargs="-unit"), my tests would run fine (except for one which I’ll detail below), but then I would get this error when the junitreport plugin tried to run its XSL transform:

Embedded error: java.lang.reflect.InvocationTargetException
Provider org.apache.xalan.processor.TransformerFactoryImpl not found

Normally I would suspect that the geotools dependencies brought in some new version of the xalan library and it didn’t have an old class that the junitreport plugin required. To check this, I compared the output from both maven dependency:classpath and dependency:tree between my trunk branch and the branch where I had added the geotools dependencies. The comparision showed that only one one dependency had changed between the branches; a newer version of commons-pool was used. All other classpath mods were new libraries that were not previously included at all. In fact, xerces and xalan was not included by the trunk branch at all. I am sure that someone with more recent experiences with xml-apis, xerces, and xalan knows exactly what was happening. My guess is that by including the xml-apis-xerces dependency, some piece of the junitreport plugin thought that it could use xalan as opposed to some other XSL lib that it would use when xerces was not present. This is supported by the fact that if I added xalan as a dependency, the error went away. If I have time, I’ll look at the docs for junitreport one of these days and see if that sheds some light on the issue.

PDFImageWriter/NodeList conflict – One of the unit tests exercised our use of PDFBox. If I did not have the above exclusions and I include xalan, this error appeared during the PDFImageWriter constructor:

java.lang.LinkageError: loader constraint violation: loader (instance
of <bootloader>) previously initiated loading for a different type with
name "org/w3c/dom/NodeList"

I haven’t tracked down exactly why this linkage conflict occurred. The bizare thing is that I inserted some link-loading debugging that I used in the past to try to see where NodeList was coming from in both my trunk and geotools-enabled branches:

def clazz = org.w3c.dom.NodeList.class
def codeSource = clazz.getProtectionDomain().getCodeSource();
println ("Source Location: " + codeSource);

In trunk (i.e. no geotools and working fine), it came back as null; NodeList wasn’t loaded at all. In the geotools-enabled branch, it would load (from xerces, I think), but then had that conflict.

At this point, I have a solution (two, actually) and have spend pretty much a whole day researching various paths, so I need to wrap it up and move on. If anyone has a better solution or thoughts as to why exactly there were problems, feel free to comment.

One last note in case there is any confusion from me mentioning xalan so much – I did not end up adding a dependency for xalan to my POM. Just using the exclusion statements listed above solved the issue.

JSON conversion and request thread reuse

December 18th, 2009 No comments

Wrapping up (I hope) my experience with custom JSON conversions in Grails… The day before we were supposed to hit a major release milestone last week, I finally caught sight of a random bug that had been driving us nuts. For some AJAX requests, seemingly at random, the object that has the transient properties was not being rendered with them. Instead, it had only the regular, persistent properties and full representations of its associated objects rather than just the normal stubs of related objects with just the type and id. In other words, it was using deep JSON rendering, and this was overriding the custom JSON ObjectMarshaller that we had set for the class. But why was it doing it seemingly at random? This is where luck and experience combined to make the solution clear rather quickly and avoided some painful slogging through request handling on the server.

The luck part was that I remembered seeing a checkin from a teammate a couple of weeks ago where he got rid of direct use of a grails.converters.deep.JSON object (which is deprecated) and instead switched to a normal grails.converters.JSON object with a use('deep') statement:

def get = {
def o = OurClass.get(params.id);
JSON.use("deep")
render(contentType: "application/json", text: o as JSON)
}

This change was in a different controller for a different domain object though. Why was it affecting our other domain class? That’s where the experience part came in. A few years ago I had to track down why hibernate transactions would fail seemingly at random in another web app when running under JBoss. I could see why an initial transaction would fail (we’d get a timeout and not rollback properly), but there was no reason why later requests would cause failures. That’s when I discovered the downside of request thread pooling. Under most web contains, HTTP requests are handled by a pool of reusable threads. That means changes to thread local variables stick around between requests unless explicitly reset. In the case of the Hibernate bug, since the session was not getting closed properly, it wasn’t getting fully reset and cleared out, so subsequent requests that used that thread were getting the old session and failing because there was no way to get it back to a good state.

For the current JSON conversion bug, the JSON.use method was calling ConvertersConfigurationHolder.setTheadLocalConverterConfiguration(...), thus making the deep converter stick around for that thread. So when future requests came in to any controller on that thread, all JSON conversion calls were made with the deep configuration.

The solution is straightforward. Use the JSON.use(String, Closure) call instead when you want to make a deep call:

def get = {
def o = OurClass.get(params.id);
JSON.use("deep") {
render(contentType: "application/json", text: o as JSON)
}
}

This sets the configuration only for the closure, saving you from thread-based side effects later on.

Grails JSON converter and transient properties

November 23rd, 2009 2 comments

I figured out why my domain object was rendering as JSON differently in unit tests vs. when running the application and integration tests. Drum roll, please…No grailsApplication object is setup in unit tests.

I hear a great big, “Huh?”

First, a little background on converters. (You may want to get the Grails source code and have directories open to the org.codehaus.groovy.grails.web.converters and grails.converter packages before diving into this.) When a JSON converter is created, it obtains a ConverterConfiguration from the global ConvertersConfigurationHolder. ConverterConfiguration has several properties which influence the conversion process, but the most interesting for this discussion is its prioritized set of ObjectMarshallers. ObjectMarshallers are what do the actual work of turning an object into a JSON representation. Each ObjectMarshaller handles a certain set of classes, like arrays, maps, beans, grails domain objects, etc. When the JSON object is ready to convert a data object, it calls config.getMarshaller(data). The config iterates through its list of marshallers, calling marshaller.supports(data) on each. Since multiple marshallers may be able to handle a specific class (like GroovyBeanMarshaller and DomainClassMarshaller can both handle domain classes), whichever marshaller has highest priority (i.e. is called first) will be invoked.

When the standard ConverterConfiguration is initialized, the DomainClassMarshaller is given higher priority than the GroovyBeanMarshaller. Thus, it handles the conversion of domain objects during normal Grails application execution even though domain objects are also groovy beans. However, the DomainClassMarshaller.supports() method has a slight twist to it. It depends on there being a GrailsApplication object registered in the ConverterUtil class in order to tell it that a particular object is a domain object. Without the GrailsApplication object, ConverterUtil.isDomainClass() always returns false, causing DomainClassMarshaller.supports() to also return false. The ConverterConfiguration next checks the GroovyBeanMarshaller. Its supports() method returns true, so it handles the conversion in this case.

So why is this a big deal? For most domain object, it probably isn’t. Both marshallers render the primary properties of the domain object. However, the DomainClassMarshaller only renders properties return by domainClass.getPersistentProperties() while GroovyBeanMarshaller renders all properties, including transient ones. Because I needed some transient properties in the JSON representation, my unit tests worked great (since there is no grailsApplication setup, so the GroovyBeanMarshaller did the full rendering), but then my code failed when I ran the integration tests and the real app (since the DomainClassMarshaller handled the rendering).

How do you fix this? It’s pretty easy once you know where to look. First, I wanted to make my unit tests behave like the real app, so I had to get them to fail. Unfortunately, the conversion classes are written in java, not groovy, so you can’t just do a quick override of the ConverterUtil metaclass to get it to return what you want. You actually need to setup a GrailsApplication object. Rather than trying to create and initialize a whole one though, I determined that I could create a small stub class that overrode the two methods I needed:


import org.codehaus.groovy.grails.commons.*
class GrailsApplicationStub extends DefaultGrailsApplication {
def artefacts = [(DomainClassArtefactHandler.TYPE):[:]]

boolean isArtefactOfType(String artefactType, String className) {
return getArtefact(artefactType, className) != null
}

GrailsClass getArtefact(String artefactType, String name) {
def retVal = artefacts[artefactType] ? artefacts[artefactType][name] : null
return retVal
}
}

When initializing the unit test, I created the stub and set in the particular domain class that I wanted to be recognized. Then register the application stub with the ConverterUtil class:


def grailsApp = new GrailsApplicationStub();
grailsApp.artefacts[DomainClassArtefactHandler.TYPE][YourClass.name] = new DefaultGrailsDomainClass(YourClass);
ConverterUtil.setGrailsApplication(grailsApp);

Instances of YourClass will now be handled by the DomainClassMarshaller in the unit test. When the unit test checks for the existence of a transient property in a JSON representation, it should fail.

Next, I needed to change the marshaller prioritization so that the desired domain class was handled by a regular GroovyBeanMarshaller. Since I always wanted the GroovyBeanMarshaller to handle the class, I inserted this code into my unit test setup (and later into BootStrap so the behavior would apply to the full app):


JSON.registerObjectMarshaller(YourClass, {o, c ->
new GroovyBeanMarshaller().marshalObject(o, c)
})

This creates a ClosureObjectMarshaller that handles YourClass objects and gives the new marshaller the default priority of 1 (which puts it at the top of the priority list). When processing an object, this closure marshaller simply passes it through to a GroovyBeanMarshaller. Since the new marshaller only handles YourClass objects, the rendering behavior for all other domain objects is not affected.

This resolved my original issue. The JSON rendering of my object is now correct when I run my app. I did go down a side path while coming to this final solution. If you only want to override how a YourClass object is rendered some of the time, you could instead register a named configuration for it like this:


JSON.createNamedConfig("FullYourClassRender") {cfg ->
cfg.registerObjectMarshaller(new ClosureOjectMarshaller(YourClass, {o, c ->
new GroovyBeanMarshaller().marshalObject(o, c)
}))
}

Then when you want to use that particular configuration, you wrap the JSON object calls in a use statement:


JSON.use("FullYourClassRender") {
render(contentType: "application/json", text: myObject as JSON)
}

Other configuration options are also available. Take a look at the JSON class to see them.

I hope this helps document the conversion process a bit.

Categories: Uncategorized Tags: , ,

Fun with Grails JSON conversion

November 20th, 2009 No comments

I discovered a problem this afternoon with how one of the domain objects in my Grails app was being converted to JSON in its controller.  The conversion functioned as expected in a unit test, but failed in integration tests and when running the real app.  “Time to see how good the debugger in Intellij 9 is,” I say to myself.  So I dive into the grails.converters.JSON class to try to find where the difference comes from.  Unfortunately, every time I step into the render() method, the rendering quickly fails with this exception:

org.codehaus.groovy.grails.web.json.JSONException: “Misplaced object”

It turns out that the JSON converter has a writer property that is a JSONWriter object.  The act of showing the writer in the variables window of the Intellij debugger causes its toString() method to be called by the IDE (though any breakpoints set in the class do not get triggered by the call).  This, in turn, causes the writer to actually do the writing of the object which, when complete, changes the writer’s state property to DONE.  When the real code execution tries to process the data, the JSONWriter throws the exception because it thinks it has already finished rendering.

The trick to step through the JSON converter is to define a custom Type Renderer for the JSONWriter class that does not invoke the “toString” method.  A blog post on the Intellij site defines how to setup a Type Renderer for a class.  I set mine up so that the node renders simply as “JSONWriter” since I don’t need to see the details for it.  One caveat though – I found that the new Type Renderer didn’t affect entries already in my variables window until I right-clicked one and selected “View As -> JSONWriter”.  Then the view changed to use the new display settings.

Now back to debugging…maybe I’ll actually figure out the real problem sometime before the sun comes up.

Categories: Uncategorized Tags: , ,