Reputation: 12283
When marshalling to XML in Grails 2.3.5, I want null properties to be excluded from the XML.
Currently code like this
if ( myObj.someProp == null ) log.info("yeap, it's null")
render myObj as XML
will output "yeap, it's null" to the log and then render XML that looks like
<myObj>
<someProp />
</myObj>
but what I want is
<myObj>
</myObj>
Or simply (if no other properties are present)
<myObj />
Can Grails be configured to exclude null properties from marshalling?
Also, using
def xml = myObj as XML
if ( myObj.someProp == null ) {
xml.excludes = ["someProp"]
}
render xml
won't work in all cases because sometimes it's a list of results
where the items in the list may have null properties.
UPDATE
I tried @dmahapatro's suggestion by adding the following code to BootStrap.groovy
XML.registerObjectMarshaller(MyObj) {
it.properties.findAll { it.value != null }
}
with the appropriate import statements.
The results are XML that is incorrect:
<myObj>
<entry key="someProp">non-null value</entry>
</myObj>
Now the properties are no longer the names of tags. Instead, a generic "entry" tag is used, because Grails is seeing a Map instead of a domain object.
Upvotes: 1
Views: 1891
Reputation: 12283
It is not possible to exclude tags for null values from the output using the built-in converters and marshallers. Having read the Grails source code there are two relevant classes that control this behavior, neither of which is configurable to behave differently.
The first is the marshaller class DomainClassMarshaller
in grails-plugin-converters/src/main/groovy/org/codehaus/groovy/grails/web/converters/marshaller/xml/
and the relevant lines are
xml.startNode(propertyName);
if (!property.isAssociation()) {
// Write non-relation property
Object val = beanWrapper.getPropertyValue(propertyName);
xml.convertAnother(val);
}
This starts the node for the property (regardless of its value) then calls xml.convertAnother
on the value.
The second relevant line of code is the convertAnother
method in XML.java
of grails-plugin-converters/src/main/groovy/grails
if (o == null) {
// noop
}
Which does nothing if the value is null (leaving the tag empty) and references no configuration options to behave differently.
Therefore, the only way to get the desired behavior is to implement it from scratch and register the custom marshaller/converter as @dmahapatro suggested.
Since the OP asked how to do this with the Grails XML Marshaller, the correct answer is simply: it cannot be done.
Upvotes: 1
Reputation: 50245
You can use registerObjectMarshaller
to modify that behavior.
//Bootstrap.groovy
import grails.converters.XML
import my.package.MyObj
XML.registerObjectMarshaller(MyObj) {
it.properties.findAll { it.value != null }
}
UPDATE
In order to avoid the entry tags because of map representation of domain class, the object marshaller can be easily transformed to get expected result as below:
XML.registerObjectMarshaller(Author) {obj, xml ->
xml.attribute 'id', "$obj.id"
xml.build {
obj.properties.each {
if(it.value != null) {
"$it.key" it.value
}
}
}
}
Upvotes: 2