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
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
}
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.)
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.
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
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.