Grails: Defining a JSON custom marshaller as static method in domain - json

I'm using Grails 2.4.2. As can be seen here:
https://grails.org/Converters+Reference
You can create a static method in your domain with your custom marshaller to render the JSON in the controller. Like that:
Domain:
// a class to output in JSON
package com.sample
class User {
String login
String passwd
// JSON definition of the User object
static {
grails.converters.JSON.registerObjectMarshaller(User) {
return [
login: it.login
]
}
}
Then in your controller:
def user = new User(login:'bob', passwd:'1234')
render user as JSON
This is not working for me in my project. I render it and outputs as the default rendering (with class:"com.sample.User"...). But if I change something in the domain and the environment "reloads" it (recompiling), then the render is OK.
Of course, I want the custom marshaller code to be in the domain, and if it's possible with no more other code outside (BootStrap.groovy, resources.groovy...) etc, I know how to do custom marshaller the other way (like here: http://compiledammit.com/2012/08/16/custom-json-marshalling-in-grails-done-right/)
So... what i missed? Is it possible?

Related

How do I render plain object as JSON, XML in Grails?

I have a controller (RestfulController) code similar to the following:
def doSomethingAwesome() {
Domain domainObject = prepareDomainObject()
//do something on the domain object
Model model = new Model(name: domainObject.name, description: domainObject.description)
respond model
}
As can be seen, I'm trying to respond with data wrapped inside a Model object. However, Model class is not a domain class; it's just a plain Groovy class. When I try to test this code in isolation, I get it to pass, but when I test it with all the other tests, I get GroovyCastException saying the object cannot be cast to JSON.
Some of the articles that came up of my searches suggest I put the model object inside a map then have that map get rendered. Something like:
render ['model': model] as JSON
However, this isn't how I'd like the response message to be. In addition, the XML message would look very different.
The Grails 2.4.3 demo project at https://github.com/jeffbrown/pogorespond demonstrates passing a POGO (not a domain class) to the respond method. https://github.com/jeffbrown/pogorespond/blob/1646c64fe2b37856fc87b64ae1cf5a6c4fd44cb1/grails-app/controllers/demo/DemoController.groovy contains the following:
package demo
class DemoController {
static responseFormats = ['json']
def index() {
def m = new Model(name: 'Some Name', description: 'Some Description')
respond m
}
}
class Model {
String name
String description
}

Grails - rendering UUID to JSON

I'm using UUID as generator for my domain classes. When I render domain objects as JSON, the id looks like the following:
"id":{"class":"java.util.UUID","leastSignificantBits":-7570618374586820490,"mostSignificantBits":126481566314875615}
Instead, I want it to look as simple as,
"id":"01c15a50-7ed5-4adf-96ef-c2b2fcb51876"
which is how it looks like when I render the domain objects to XML. How do I make it work this way?
It may help if you post your domain class, but my assumption is it's something like the following:
class MyDomain {
UUID id = UUID.randomUUID()
}
Unless you explicitly need to keep it as a UUID, I imagine this will render the JSON as you're expecting:
class MyDomain {
String id = UUID.randomUUID().toString()
}
Because I required the UUID class so that ORM would work between Grails and Oracle, I couldn't just make the id field a String.
So instead, I used a very basic JsonRenderer to override the default (troublsome) JSON rendering of a UUID object.
#CompileStatic
class UuidJsonRenderer extends DefaultJsonRenderer<java.util.UUID> {
UuidJsonRenderer() {
super(java.util.UUID)
}
void renderJson(java.util.UUID object, RenderContext context) {
super.renderJson(object.toString(), context)
}
}
And plugged it in as a bean the following in resources.groovy:
beans = {
// Custom Renderers
uuidJsonRenderer(UuidJsonRenderer)
}
(I think you could probably annotate the renderer and have an annotation processor do this part automatically, if that's your pleasure.)

Reflectively save domain class instances in Grails

The problem is as follows: I want to handle a POST request with JSON body. The body consists of an array of JSON Objects, without further nesting, i.e. simple HashMaps. All of these objects represent JSON-serialized domain classes from an Android Application, which will have their counterpart in my Grails app. I am thinking of parsing the JSON body, iterating through every element and saving each node as its corresponding domain class instance.
a) How should I save the instance? I am quite new to Grails/Groovy so please excuse any huge mistakes. Code so far is
public static Object JSONArray2Instances(String json, Class type) {
def slurper = new JsonSlurper()
def result = slurper.parseText(json)
//we only want to parse JSON Arrays
if (!(result instanceof JSONArray))
return null
result.each {
def instance = it.asType(type)
// now I need to save to domain class!
}
}
b) where do I place the corresponding code? Currently it is in /grails-app/src/groovy. Where do the tests go? (Since it is not a 'real' Grails component)
c) Is an intermediate command object more appropriate?
Your code should go in to the controller which is handling the request. Please take a look at
gson-grails plugin which has examples of how to serialize and deserialze objects and map them to domain objects. Please take a look at the grails basics where they talk about the conventions used in the grails application and the layout. There are good examples at grails site. Hope this helps
I solved my problem as follows, based on help provided by the comment from allthenutsandbolts. : (Grails-Gson plugin was not needed)
Let N2696AdminAction be the name of a Domain Class
in my controller:
class N2696AdminActionController extends RestfulController{
static responseFormats = ['json', 'xml']
def JSONHandlerService
N2696AdminActionController() {
super(N2696AdminAction)
}
#Override
#Transactional
def save(){
if (request!=null)
JSONHandlerService.instancesfromJSON(request.JSON)
}
}
then I delegate persisting to my service as follows
class JSONHandlerService {
def instancesfromJSON(Object request){
//we only want to parse JSON Arrays
if (!(request instanceof JSONArray))
return null
request.each {
def domainClass = Class.forName("${it.type}",
true, Thread.currentThread().getContextClassLoader())
def newDomainObject = domainClass.newInstance(it)
newDomainObject.save(failOnError:true, flush:true, insert: true)
}
}
}
type is a Json attribute which holds the full (package inclusive) name for my class. This way, I can save to multiple Domain Classes with the same POST request.

error doing nested resource in grails

i am try to do nested resource call using angular and grails.
in my account domain i map domain this way:
example:
class Account {
static hasMany=[contacts:Contacts,users:User_BE];
}
and in contact domain
example:
class Contacts {
static belongsTo=[accounts:Account];
}
my json structure is like this:
{"accountType":"Single","traderwinkel":true,"lynxAgro":true,"contacts":[{"class":"com.crm.contacts","name":"abc"}]}
i am getting this error:
null id in com.crm.Contacts entry
and i am also try to send json without using array like this:
{"accountType":"Single","traderwinkel":true,"lynxAgro":true,"contacts":{"class":"com.crm.contacts","name":"abc"}}
but got same error like above.
and also i have used restfullcontroller:
class AccountController extends RestfulController {
static responseFormats = ['json', 'xml']
}
please suggest me how should i need to structure and send json data

Convert grails domain object to JSON and manipulate it

I have a grails object that I am converting using def json = object as JSON. After I have it converted I want to add one more property called pin to the JSON which looks like the following.
[location:[lat:23.03, lon:72.58]]
Only way to do this so far seems like following
Serialize the DomainClass to JSON using grails.converters.json
Convert the JSON to string
Create JSONBoject using the string from Step 2
Add the property
Convert it back to String
Any other way to do this using grails.converters.json? I have tried using Gson but I do not want to go that route because I am getting many Circular Reference Errors
Try this:
domainInstance.properties + [pin: pinInstance] as JSON
I recently needed to do a similar thing. Some caveats:
This is using Grails 2.4.5
I use MongoDB as a backend. As such, I created an object marshaller for MongoDB domain classes. It is printed below, and you can wrap a similar marshaller for your domain class(es):
Marshaller:
class MongodbObjectMarshaller implements ObjectMarshaller<JSON> {
#Override
boolean supports(Object o) { return o?.properties?.dbo }
#Override
void marshalObject(Object obj, JSON converter) throws
ConverterException {
Map propertiesToOutput = obj.properties.dbo
propertiesToOutput.remove("_id") //don't print org.bson.types.ObjectId
propertiesToOutput.remove("version") //don't print gorm verson column
converter.build {
_id obj.id.toString()
propertiesToOutput.each{ entry ->
"$entry.key" entry.value
}
}
}
}
What that marshaller does, it allow in JSON output any of the domain class's properties. obj.properties.dbo is special to MongoDB, but for a regular domain class, you can just grab the properties and exclude the ones you don't need.
Then in my controller, this works:
domainInstance.pin = [location:[lat:23.03, lon:72.58]]
def content = tacticalCard as JSON
because my marshaller now picks up the pin property and prints it.