In the following code i get the nullpointer exception only in some cases and the JSON is the same every time. How to resolve this
Error
errors.GrailsExceptionResolver - NullPointerException occurred when processing request: [POST] /school/sd/
Cannot set property 'school' on null object. Stacktrace follows:
Message: Cannot set property 'school' on null object
controller
def save() {
if (!requestIsJson()) {
respondNotAcceptable()
return
}
println request.GSON
def sInstance = new School(request.GSON)
println "got here"
if (sInstance.save(flush: true)) {
respondCreated sInstance
} else {
respondUnprocessableEntity sInstance
}
def resp = RestClientHelper.createExpGroup(sInstance)
}
In order to create Grails object from JSON it's easy to use special converter.
import grails.converters.JSON
.......
class Controller {
def doSomthing = {
def myDomain = new MyDomain(JSON.parse(params.myDomain))
//Save domain object
myDomain.save(flush:true)
}
}
Grails converter reference.
Related
After calling a MS Graph API using HttpBuilder which return user information, I would like to return the Id attribute of the Json response
The complete Json response is as below :
{
#odata.context=https://graph.microsoft.com/v1.0/$metadata#users,
value=[{
businessPhones=[],
displayName=Serge Cal GMAIL,
givenName=null,
jobTitle=null,
mail=user1.tom#gmail.com,
mobilePhone=null,
officeLocation=null,
preferredLanguage=null,
surname=null,
userPrincipalName=user1.tom_gmail.com#EXT##SCALDERARA.onmicrosoft.com,
id=253bca1d-6c03-441f-92e4-e206c7d180f7
}]
}
For doing so I have a groovy method define as below :
public String getUserIdByEmailQuery(String AuthToken,String userEmail){
String _userId
def http = new HTTPBuilder(graph_base_user_url +"?")
http.request(GET) {
requestContentType = ContentType.JSON
uri.query = [ $filter:"mail eq '$userEmail'".toString() ]
headers.'Authorization' = "Bearer " + AuthToken
response.success = { resp, json ->
**_userId=json["value"]["id"]**
}
// user ID not found : error 404
response.'404' = { resp ->
_userId = 'Not Found'
}
}
_userId
}
With this update the reponse value is [xxx-xxx-xxx-xxx-xxx-], which is correct excpet that it suround the value with []
Any idea ?
regards
The original problem was caused by the wrong expression to get the id and since you have got the id list [xxx-xxx-xxx-xxx, xxx-xxx-xxx-xxx, ...] by json["value"]["id"], so you just need to use json["value"]["id"][0] to get the first id of the list.
And this expression json["value"][0]["id"] might also work.
Update:
You can use groovy.json.JsonSlurper to help you parse the json and get the id value.
import groovy.json.JsonSlurper
JsonSlurper slurper = new JsonSlurper()
Map parsedJson = slurper.parseText(json)
String idValue = parsedJson.value[0].id
I am inserting a JSON value into a H2 database using GORM in the domain i have two column
String clobs
Date date
static mapping = {
datasource 'json'
clobs sqlType: 'clob'
}
static constraints = {
}
}
from the controller i call the service method
def createJson(){
log.debug("Inserting Values")
def builder = new JsonBuilder()
builder.message {
header {
from('mrhaki')
to 'Groovy Users', 'Java Users'
}
body "Check out Groovy's gr8 JSON support."
}
println "builder value before inserting is: "+ builder
def jsonExec = new JsonOrm(clobs: builder.toString(), date: new Date())
println "the builder value: "+ jsonExec.clobs
println "the date value: " + jsonExec.date
jsonExec.save()(failOnError:true)
println "values saved successfully in the table!!!!!"
}
while executing this is the error i am getting in the browser
URI
/SampleProject/jsonOrm/index
Class
groovy.lang.MissingMethodException
Message
No signature of method: com.ws.JsonOrm.call() is applicable for argument types: (java.util.LinkedHashMap) values: [[failOnError:true]] Possible solutions: wait(), last(), save(), any(), getAll(), wait(long)
To render a json string (from the CLOB), you can just parse string first and then render the json from it like this:
Map map = JSON.parse(jsonString)
render (map as JSON)
You're converting the entire CLOB object, you just want the 'contents', try:
stmt = row["JSON"]?.asciiStream.text
I am trying to build a REST service which accepts XML and convert it into JSON and call external Service which accepts JSON and put my JSON into it. I am able to put the json without pretty but I want to PUT the json in pretty format. Please suggest how to do, below is my code ...
package com.mypackge
import grails.converters.JSON
import grails.rest.RestfulController
import grails.plugins.rest.client.RestBuilder
class RestCustomerController extends RestfulController {
/*
static responseFormats = ['json', 'xml']
RestCustomerController() {
super(Customer)
}
*/
def index() {
convertXmlToJson()
}
def myJson = ''
def convertXmlToJson() {
def xml = ''' <Customer>
<customerid>9999999999999</customerid>
<ssn>8888</ssn>
<taxid>8888</taxid>
<address>
<addressline1>Yamber Ln</addressline1>
<addressline1>8664 SE</addressline1>
<city>CCCCC</city>
<state>CC</state>
<zipcode>97679</zipcode>
</address>
<firstname>Scott</firstname>
<middlename></middlename>
<lastname>David</lastname>
<account>
<accountno>576-294738943</accountno>
<accounttype>Lease</accounttype>
<accountsubtype></accountsubtype>
<accountstatus>complete</accountstatus>
<firstname>Scott</firstname>
<middlename></middlename>
<lastname>David</lastname>
<businessname></businessname>
<billingsystem>yoiuhn</billingsystem>
<brand></brand>
<plantype></plantype>
<billingaddress>
<addressline1>Yamber Ln</addressline1>
<addressline1>8664 SE </addressline1>
<city>CCCCC</city>
<state>CC</state>
<zipcode>97679</zipcode>
</billingaddress>
<job>
<jobid>8276437463728</jobid>
<jobstatus>SUCCESS</jobstatus>
</job>
</account>
</Customer>
'''.stripMargin()
// Parse it
def parsed = new XmlParser().parseText( xml )
def myId = parsed.customerid.text()
// Deal with each node:
def handle
handle = { node ->
if( node instanceof String ) {
node
}
else {
[ (node.name()): node.collect( handle ) ]
}
}
// Convert it to a Map containing a List of Maps
def jsonObject = [ (parsed.name()): parsed.collect { node ->
[ (node.name()): node.collect( handle ) ]
} ]
def json = new groovy.json.JsonBuilder(jsonObject) //.toPrettyString()
// Check it's what we expected
def mmyresp
try{
mmyresp = putRequest(myId,json)
}catch(Exception e) {
mmyresp = 'Please Validate JSON ....'
}
}
def putRequest(String id, JSON myJson) {
String url = "http://foo.com/customer/external/"+id
def rest = new RestBuilder()
def resp = rest.put(url){
contentType "application/json"
json{
myJson
}
}
return resp
}
}
The record is added in below format ...
{"Customer":[{"customerid":["9999999999999"]},{"ssn":["8888"]},
{"taxid":["8888"]},{"address":[{"addressline1":["Yamber Ln"]},
{"addressline1":["8664 SE"]},{"city":["CCCCC"]},{"state":["CC"]},{"zipcode":["97679"]}]},
{"firstname":["Scott"]},{"middlename":[]},{"lastname":["David"]},{"businessname":[]},
{"account":[{"accountno":["576-294738943"]},{"accounttype":["Lease"]},{"accountsubtype":[]},
{"accountstatus":["complete"]},{"firstname":["Scott"]},{"middlename":[]},{"lastname":["David"]},
{"businessname":[]},{"billingsystem":["yoiuhn"]},{"brand":[]},{"plantype":[]},
{"billingaddress":[{"addressline1":["Yamber Ln"]},{"addressline1":["8664 SE"]},
{"city":["CCCCC"]},{"state":["CC"]},{"zipcode":["97679"]}]},{"job":[{"jobid":["8276437463728"]},
,{"jobstatus":["SUCCESS"]}]}]}]}
But I want this to be inserted in pretty format. I tried .toPrettyString() but got casting exception when try to put as json. I am trying the REST services for the first time, not sure where I am doing wrong. Please suggest me on this.
You should set following field in you Config.groovy.
grails.converters.default.pretty.print = true
This will pretty print for both the xml and json.
you could optionally set it up for xml or json only like below:
For json:
grails.converters.json.pretty.print = true
For xml
grails.converters.xml.pretty.print = true
A sample of Config.groovy entry is:
environments {
development {
grails.converters.json.pretty.print = true
}
}
Hope it helps!!!
For Grails 4, try this:
def json = x as JSON
json.prettyPrint = true;
log.info(json.toString())
I am trying to move some code from a grails service file into src/groovy for better reuse.
import grails.converters.JSON
import org.codehaus.groovy.grails.web.json.JSONObject
class JsonUtils {
// seems like a clunky way to accomplish converting a domainObject
// to its json api like object, but couldn't find anything better.
def jsonify(obj, ArrayList removeableKeys = []) {
def theJson = obj as JSON
def reParsedJson = JSON.parse(theJson.toString())
removeableKeys.each { reParsedJson.remove(it) }
return reParsedJson
}
// essentially just turns nested JSONObject.Null things into java null things
// which don't get choked on down the road so much.
def cleanJson(json) {
if (json instanceof List) {
json = json.collect(cleanJsonList)
} else if (json instanceof Map) {
json = json.collectEntries(cleanJsonMap)
}
return json
}
private def cleanJsonList = {
if (it instanceof List) {
it.collect(cleanJsonList)
} else if (it instanceof Map) {
it.collectEntries(cleanJsonMap)
} else {
(it.class == JSONObject.Null) ? null : it
}
}
private def cleanJsonMap = { key, value ->
if (value instanceof List) {
[key, value.collect(cleanJsonList)]
} else if (value instanceof Map) {
[key, value.collectEntries(cleanJsonMap)]
} else {
[key, (value.class == JSONObject.Null) ? null : value]
}
}
}
but when I try to call jsonify or cleanJson from services I get MissingMethodExceptions
example call from grails service file:
def animal = Animal.read(params.animal_id)
if (animal) json.animal = JsonUtils.jsonify(animal, ['tests','vaccinations','label'])
error:
No signature of method: static org.JsonUtils.jsonify() is applicable for argument types: (org.Animal, java.util.ArrayList) values: [ ...]]\ Possible solutions: jsonify(java.lang.Object, java.util.ArrayList), jsonify(java.lang.Object), notify()
Also tried making the jsonify take an animal jsonify(Animal obj, ...) then it just said Possible solutions: jsonify(org.Animal, ...
The cleanJson method was meant to deal with JSONObject.Null things which have caused problems for us before.
example call:
def safeJson = JsonUtils.cleanJson(json) // json is request.JSON from the controller
error:
groovy.lang.MissingMethodException: No signature of method: static org.JsonUtils.cleanJson() is applicable for argument types: (org.codehaus.groovy.grails.web.json.JSONObject) values: [[...]]
Possible solutions: cleanJson(org.codehaus.groovy.grails.web.json.JSONObject)
All this code worked as it is when it was in service file. I am running grails 2.3.11 BTW
You've declared jsonify() and cleanJson() as instance methods and try to use them as static. Declare them as static and it should work:
class JsonUtils {
def static jsonify(obj, ArrayList removeableKeys = []) {
(...)
}
def static cleanJson(json) {
(...)
}
}
You need to define jsonify() and cleanJson() as static in order to call them statically.
Hi I have a grails restful code. I do perfect a Json get and delete request.
My problem is:
I want to do a Put or post request with json but if I use a program to do that It has an error and I cant do it!
Here my code:
One class:
package catalogo.json
class Catalogo {
String nombre
String descripcion
String url
Set <Parametros>parametros =[]
static hasMany = [parametros:Parametros]
int numeroParametros = parametros.size()
}
And other class:
package catalogo.json
class Parametros {
String tipoParametro
String json
static constraints = {
tipoParametro(nullable:true)
json(nullable:true)
}
}
I don't know how to put my json in the request. Heres the error when I put it.
EXAMPLE:
I PUT POST request.
body application/json (or text/json is the same error) Charset-utf-8
{"descripcion": "bla", "nombre" : "lalala", "numeroParametros":3, "parametros":[{
"tipoParametro":"string", "json":"bla"}],"url":"http://www.google.com"}
And here the error:
Could not create new Catalogo due to errors:
grails.validation.ValidationErrors: 3 errors
Field error in object 'catalogo.json.Catalogo' on field 'descripcion': rejected value [null]; codes [catalogo.json.Catalogo.descripcion.nullable.error.catalogo.json.Catalogo.descripcion,catalogo.json.Catalogo.descripcion.nullable.error.descripcion,catalogo.json.Catalogo.descripcion.nullable.error.java.lang.String,catalogo.json.Catalogo.descripcion.nullable.error,catalogo.descripcion.nullable.error.catalogo.json.Catalogo.descripcion,catalogo.descripcion.nullable.error.descripcion,catalogo.descripcion.nullable.error.java.lang.String,catalogo.descripcion.nullable.error,catalogo.json.Catalogo.descripcion.nullable.catalogo.json.Catalogo.descripcion,catalogo.json.Catalogo.descripcion.nullable.descripcion,catalogo.json.Catalogo.descripcion.nullable.java.lang.String,catalogo.json.Catalogo.descripcion.nullable,catalogo.descripcion.nullable.catalogo.json.Catalogo.descripcion,catalogo.descripcion.nullable.descripcion,catalogo.descripcion.nullable.java.lang.String,catalogo.descripcion.nullable,nullable.catalogo.json.Catalogo.descripcion,nullable.descripcion,nullable.java.lang.String,nullable]; arguments [descripcion,class catalogo.json.Catalogo]; default message [La propiedad [{0}] de la clase [{1}] no puede ser nulo]
Field error in object 'catalogo.json.Catalogo' on field 'nombre': rejected value [null]; codes [catalogo.json.Catalogo.nombre.nullable.error.catalogo.json.Catalogo.nombre,catalogo.json.Catalogo.nombre.nullable.error.nombre,catalogo.json.Catalogo.nombre.nullable.error.java.lang.String,catalogo.json.Catalogo.nombre.nullable.error,catalogo.nombre.nullable.error.catalogo.json.Catalogo.nombre,catalogo.nombre.nullable.error.nombre,catalogo.nombre.nullable.error.java.lang.String,catalogo.nombre.nullable.error,catalogo.json.Catalogo.nombre.nullable.catalogo.json.Catalogo.nombre,catalogo.json.Catalogo.nombre.nullable.nombre,catalogo.json.Catalogo.nombre.nullable.java.lang.String,catalogo.json.Catalogo.nombre.nullable,catalogo.nombre.nullable.catalogo.json.Catalogo.nombre,catalogo.nombre.nullable.nombre,catalogo.nombre.nullable.java.lang.String,catalogo.nombre.nullable,nullable.catalogo.json.Catalogo.nombre,nullable.nombre,nullable.java.lang.String,nullable]; arguments [nombre,class catalogo.json.Catalogo]; default message [La propiedad [{0}] de la clase [{1}] no puede ser nulo]
Field error in object 'catalogo.json.Catalogo' on field 'url': rejected value [null]; codes [catalogo.json.Catalogo.url.nullable.error.catalogo.json.Catalogo.url,catalogo.json.Catalogo.url.nullable.error.url,catalogo.json.Catalogo.url.nullable.error.java.lang.String,catalogo.json.Catalogo.url.nullable.error,catalogo.url.nullable.error.catalogo.json.Catalogo.url,catalogo.url.nullable.error.url,catalogo.url.nullable.error.java.lang.String,catalogo.url.nullable.error,catalogo.json.Catalogo.url.nullable.catalogo.json.Catalogo.url,catalogo.json.Catalogo.url.nullable.url,catalogo.json.Catalogo.url.nullable.java.lang.String,catalogo.json.Catalogo.url.nullable,catalogo.url.nullable.catalogo.json.Catalogo.url,catalogo.url.nullable.url,catalogo.url.nullable.java.lang.String,catalogo.url.nullable,nullable.catalogo.json.Catalogo.url,nullable.url,nullable.java.lang.String,nullable]; arguments [url,class catalogo.json.Catalogo]; default message [La propiedad [{0}] de la clase [{1}] no puede ser nulo]
EDIT HERE MY CONTROLLER:
package catalogo.json
import grails.converters.JSON
class CatalogoController {
def index = {
switch(request.method){
case "POST":
def catalogo = new Catalogo(params.catalogo)
if(catalogo.save()){
response.status = 201 // Created
render catalogo as JSON
}
else{
response.status = 500 //Internal Server Error
render "Could not create new Airport due to errors:\n
${catalogo.errors}"
}
break
case "GET":
if(params.id){render Catalogo.findById(params.id) as JSON}
else{render Catalogo.list() as JSON}
break
case "PUT":
def catalogo = Catalogo.findById(params.catalogo.id)
catalogo.properties = params.catalogo
if(catalogo.save()){
response.status = 200 // OK
render catalogo as JSON
}
else{
response.status = 500 //Internal Server Error
render "Could not create new Catalogo due to errors:\n ${catalogo.errors}"
}
break
case "DELETE":
if(params.id){
def catalogo = Catalogo.findById(params.id)
if(catalogo){
catalogo.delete()
render "Successfully Deleted."
}
else{
response.status = 404 //Not Found
render "${params.id} not found."
}
}
else{
response.status = 400 //Bad Request
render """DELETE request must include the ID code
Example: /rest/catalogo/id
"""
}
break
}
}
def list = {
if(!params.max) params.max = 10
def list = Catalogo.list(params)
withFormat{
html{
return [catalogoList:list]
}
json{
render list as JSON
}
}
}
}
Thanks
Here is how it should be done in controllers:-
def index() {
//JSON Object is not bound to params it is bound to request in POST/PUT
def jsonObj = request.JSON
//You can also use JSON.parse() to get a JSON object if the request payload has JSON as string
//def jsonObj = JSON.parse(request)
//You will not be able to save the inner JSONArrays if you
// directly bind the jsonObj to the domain. in order to save
//convert them to the proper domain objects otherwise you would get validation errors for parametros
def catalogParams = [] as Set
jsonObj.parametros.each{
catalogParams << new CatalogParams(it)
}
//Set the domain back to the jsonObj
jsonObj.parametros = catalogParams
//Bind to catalog
def catalog = new Catalog(jsonObj)
//Synonymous to new Catalog(params) but here you cannot use params.
//Save
if (!catalog.save(flush: true)){
catalog.errors.each {
println it
}
}
render catalog
}
//Domain Classes:-
class CatalogParams {
String tipoParametro
String json
static constraints = {
tipoParametro(nullable:true)
json(nullable:true)
}
}
class Catalog {
String nombre
String descripcion
String url
Set<CatalogParams> parametros = []
static hasMany = [parametros: CatalogParams]
int numeroParametros = parametros.size()
}
REST Client:
How are you testing the REST WS? You should have a REST client to test the service? Or you can use REST console extension in Chrome to test your service. You can also use a grails plugin rest-client-builder to test your service. In basic terms, if you do not want any client implementation then atleast a script to test your service. HttpBuilder will be useful in this case:. Something like this is required to test your service
import groovyx.net.http.HTTPBuilder
def http = new HTTPBuilder('http://yourdomain.com/catalog/')
http.request(POST, JSON) {
requestContentType = ContentType.APPLICATION_JSON // coreesponding to application/json
body = ["descripcion": "bla", "nombre" : "lalala", "numeroParametros":3, "parametros":[{ "tipoParametro":"string", "json":"bla"}],"url":"google.com"]
response.success = { resp ->
assert resp.statusLine.statusCode == 200
}
}