Thanks in advance!
If it helps, this is my initial post.
As an input, I have this json:
{
"BidId": "ID1088622222",
"ItemNumber": "4.3.9",
"CodiceNegoziazione": "Doc104222222",
"CreationDate": "Wed, 15 Jun, 2022",
"ProjectId": "WS1042222222",
"ProjectOwner": "Silvia Gani",
"ProjectTitle": "gara import Europa Y2022-2023",
"CompanyCode": "A222 Olivetti",
"PurchasingOrganization": "",
"PurchasingGroup": "",
"PaymentTerms": "",
"Currency": "EUR",
"EventType": "RFP",
"EventOwner": "Silvia Gani",
"EventId": "Doc1042222222",
"EventTitle": "gara Import Europa Y2022-2023",
"SupplierOrgName": "ARCESE",
"SupplierOrgId": "buyersystemid:acm_2222",
"SectionLot": "GERMANIA (Emmer)",
"ItemName": "CAMION COMPLETO (EURO)",
"Type": "Line Item",
"SubmissionDate": "Mon, 4 Jul, 2022",
"Price": "1530",
"Quantity": "1",
"ExtendedPrice": "1530",
"MaterialGroup": "",
"RequestedDeliveryDate": "",
"BidCurrency": "EUR",
"BidExtendedPrice": "1530",
"BidSavings": "0",
"BidPrice": "1530",
"AwardAllocationPercentage": "100"
}
I would like to adjust this part of code:
class Version {
int major
Integer minor, patch
#Override String toString() {
return [major, minor, patch].findAll().join('.')
}
}
def parseVersion(String versionString) {
if (!versionString) return null
int[] tokens = versionString.split(/\./).collect { it as int }
return new Version(
major: tokens[0],
minor: tokens.length > 1 ? tokens[1] : null,
patch: tokens.length > 2 ? tokens[2] : null,
)
}
class Payload {
String ItemNumber
}
Payload payload = new Payload(ItemNumber: "2.4")
Version version = parseVersion(payload.ItemNumber?.trim())
printf("Major version : %d%n", version.major)
printf("Minor version : %s%n", version.minor ?: "<UNSET>")
printf("Patch version : %s%n", version.patch ?: "<UNSET>")
printf("Full version : %s%n", version)
In this groovy script:
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import groovy.json.*
def Message processData(Message message) {
//Body
def body = message.getBody(String.class);
def jsonSlurper = new JsonSlurper()
def list = jsonSlurper.parseText(body)
def ItemNumber = list.get("ItemNumber")
def Price = list.get("Price")
def Quantity = list.get("Quantity")
def ExtendedPrice = list.get("ExtendedPrice")
def BidExtendedPrice = list.get("BidExtendedPrice")
def BidTotalCost = list.get("BidTotalCost")
def BidSavings = list.get("BidSavings")
def BidPrice = list.get("BidPrice")
def RfqItemNumber = list.get("RfqItemNumber")
def AwardAllocationPercentage = list.get("AwardAllocationPercentage")
if (ItemNumber?.trim()){
list.ItemNumber = Double.parseDouble(ItemNumber.toString());
}
if (Price?.trim()){
list.Price = Double.parseDouble(Price.toString());
}
if (Quantity?.trim()){
list.Quantity= Double.parseDouble(Quantity.toString());
}
if (ExtendedPrice?.trim()){
list.ExtendedPrice= Double.parseDouble(ExtendedPrice.toString());
}
if (BidExtendedPrice?.trim()){
list.BidExtendedPrice= Double.parseDouble(BidExtendedPrice.toString());
}
if (BidTotalCost?.trim()){
list.BidTotalCost= Double.parseDouble(BidTotalCost.toString())
}
if (BidSavings?.trim()){
list.BidSavings= Double.parseDouble(BidSavings.toString());
}
if (BidPrice?.trim()){
list.BidPrice= Double.parseDouble(BidPrice.toString());
}
if (RfqItemNumber?.trim() && RfqItemNumber != 'null'){
list.RfqItemNumber= Integer.parseInt(RfqItemNumber.toString());
}else if (RfqItemNumber == 'null'){
list.RfqItemNumber = null
}
if (AwardAllocationPercentage?.trim()){
list.AwardAllocationPercentage= Double.parseDouble(AwardAllocationPercentage.toString());
}
def jsonOP = JsonOutput.toJson(list)
message.setBody(jsonOP)
return message;
}
The goal is to parse the field ItemNumber. (From "ItemNumber": "4.4.5" --> "ItemNumber": 4.4.5)
The desired result:
{"BidId":"ID1088625754","ItemNumber":4.4.5,"CodiceNegoziazione":"Doc1042163109","CreationDate":"Wed, 15 Jun, 2022","ProjectId":"WS1042082696","ProjectOwner":"Silvia Ganio Mego","ProjectTitle":"gara import Europa Y2022-2023","CompanyCode":"A200 Olivetti S.p.A.","PurchasingOrganization":"","PurchasingGroup":"","PaymentTerms":"","Currency":"EUR","EventType":"RFP","EventOwner":"Silvia Ganio Mego","EventId":"Doc1042163109","EventTitle":"gara Import Europa Y2022-2023","SupplierOrgName":"ARCESE TRASPORTI S.P.A.","SupplierOrgId":"buyersystemid:acm_36628101|sap:0000333441|networkid:an01009585103","SectionLot":"GERMANIA (Emmerich)","ItemName":"CAMION COMPLETO (EURO)","Type":"Line Item","SubmissionDate":"Mon, 4 Jul, 2022","Price":1530.0,"Quantity":1.0,"ExtendedPrice":1530.0,"MaterialGroup":"","RequestedDeliveryDate":"","BidCurrency":"EUR","BidExtendedPrice":1530.0,"BidSavings":0.0,"BidPrice":1530.0,"AwardAllocationPercentage":100.0}
I tried to adjust the above part of code in the groovy but I still get "ItemNumber": "4.4.5" .
If I try the code in a groovy ide it works fine though. I am not so familiar with all of this, not so long in this area.
Related
The server comes with json format:
{
"type": "string",
"object": {
"lead_id": int,
"form_name": "string",
"answers": [
{
"lead_id": int,
"key": "string",
}
...
]
},
"group_id": int,
"secret": "string"
}
How to use django REST framework to validate this json?
ru version
class AnswersSerializer(serializers.Serializer):
lead_id = serializers.IntegerField(required=True)
key = serializers.CharField(max_length=100)
class ObjectSerializer(serializers.Serializer):
lead_id = serializers.IntegerField(required=True)
form_name = serializers.CharField(max_length=100)
answers = serializers.ListField(child=AnswersSerializer())
class UpdateGroup(serializers.Serializer):
group_id = serializers.IntegerField(required=True)
type = serializers.CharField(max_length=100)
secret = serializers.CharField(max_length=100)
object = serializers.DictField(child=, default={})
Example:
# serializers.py
from rest_framework import serializers
class VkObjectSerializer(serializers.Serializer):
"""
is 'object'
"""
lead_id = serializers.IntegerField()
group_id = serializers.IntegerField()
user_id = serializers.IntegerField()
form_id = serializers.IntegerField()
class VkBaseSerializer(serializers.Serializer):
"""
Base serializer
"""
type = serializers.CharField(max_length=200)
object = VkObjectSerializer()
group_id = serializers.IntegerField()
secret = serializers.CharField(max_length=200)
# view.py
from rest_framework.generics import CreateAPIView
from rest_framework.response import Response
from .serializers import VkBaseSerializer
class VkCallbackView(CreateAPIView):
serializer_class = VkBaseSerializer
def create(self, request, *args, **kwargs):
"""
Method is validate json in view
"""
valid_ser = self.serializer_class(data=request.data)
if valid_ser.is_valid():
return Response('True')
return Response('False')
Valid data:
>>> valid_ser.data
{
"type": "str",
"object": {
"lead_id": 123,
"group_id": 12345,
"user_id": 12352,
"form_id": 1
},
"group_id": 5123,
"secret": "str"
}
The answers were very helpful:
Django Rest Framework ListField and DictField - how to set model json
How to validate a json object in django - validate data in view
You can use django rest framework to write you own validators like so,
class MultipleOf(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if value % self.base != 0:
message = 'This field must be a multiple of %d.' % self.base
raise serializers.ValidationError(message)
You can find more details here
Hope this helps!
I have text attribute in GenerateFlowfile processor like this:
[{
"status": {
"runStatus": "STOPPED"
},
"component": {
"state": "STOPPED",
"id": "ea5db028-015d-1000-5ad5-80fd006dda92"
},
"revision": {
"version": 46,
"clientId": "ef592126-015d-1000-bf4f-93c7cf7eedc0"
}
} ]
and related groovy script in my ExecuteScript processor :
import org.apache.commons.io.IOUtils
import java.nio.charset.*
def flowFile = session.get();
if (flowFile == null) {
return;
}
def slurper = new groovy.json.JsonSlurper()
def attrs = [:] as Map<String,String>
session.read(flowFile,
{ inputStream ->
def text = IOUtils.toString(inputStream, StandardCharsets.UTF_8)
text=flowFile.getAttribute('text')
def obj = slurper.parseText(text)
obj.each {k,v ->
attrs[k] = v.toString()
}
} as InputStreamCallback)
flowFile = session.putAllAttributes(flowFile, attrs)
session.transfer(flowFile, REL_SUCCESS)
but my processor still shows me exception like this, what should i change?
the problem that the root element of your json is an array
and you try to iterate it like map .each{k,v-> ... }
probably you want to take the first map to iterate it like in code below
def obj=[ [a:1] ]
//this line will throw exception:
//obj.each{k,v-> println "$k->$v" }
//but this one not
obj[0].each{k,v-> println "$k->$v" }
fyi: there is a EvaluateJsonPath processor that could extract attributes from json flowfile content and put result into attribute
I'm working on a Scala program that uses the Scala Pickling library to serialize and deserialize a Map object that contains a String and a Point2D.Double object from the java.awt.geom package.
Here's the relevant logic:
contents +=
new Button("Save Config") {
reactions += {
case ButtonClicked(_) => {
var m: Map[String, Point2D.Double] = Map()
nodeFields.foreach(x => {
m += (x._1 -> new Point2D.Double(x._2._1.text.toDouble, x._2._2.text.toDouble))
})
val pkl = m.pickle
fc.showSaveDialog(null)
val outputFile = fc.selectedFile
val writer = new PrintWriter(outputFile)
writer.write(pkl.value)
writer.close()
Dialog.showMessage(null, "Success!")
}
}
}
If you need to see more, here's the commit with the offending logic
As it stands, the JSON formatted string output from pkl.value is a working serialized Map[String, Point2D.Double], except that the values of Point2D.Double are dropped!
Here's a snippet of the output:
{
"$type": "scala.collection.mutable.Map[java.lang.String,java.awt.geom.Point2D.Double]",
"elems": [
{
"$type": "scala.Tuple2[java.lang.String,java.awt.geom.Point2D.Double]",
"_1": "BOTTOMLANE\r",
"_2": {
}
},
{
"$type": "scala.Tuple2[java.lang.String,java.awt.geom.Point2D.Double]",
"_1": "UPPERLANESECOND_0\r",
"_2": {
}
},
{
"$type": "scala.Tuple2[java.lang.String,java.awt.geom.Point2D.Double]",
"_1": "upperSecondTower_1",
"_2": {
}
},
...
]
}
What can I do to fix this?
scala-pickling can not directly pickle/unpickle Point2D.Double because it has no public fields (the x and y values are accessible through the getX and getY getters).
A possible Pickler / Unpickler for Point2D.Double would be :
object Point2DPickler {
import scala.pickling._
import scala.pickling.Defaults._
import java.awt.geom.Point2D
type DoublePoint = java.awt.geom.Point2D.Double
implicit object Point2DDoublePickle extends Pickler[DoublePoint] with Unpickler[DoublePoint] {
private val doubleUnpickler = implicitly[Unpickler[Double]]
override def tag = FastTypeTag[java.awt.geom.Point2D.Double]
override def pickle(point: DoublePoint, builder: PBuilder) = {
builder.beginEntry(point)
builder.putField("x",
b => b.hintTag(FastTypeTag.Double).beginEntry(point.getX).endEntry()
)
builder.putField("y",
b => b.hintTag(FastTypeTag.Double).beginEntry(point.getY).endEntry()
)
builder.endEntry()
}
override def unpickle(tag: String, reader: PReader): DoublePoint = {
val x = doubleUnpickler.unpickleEntry(reader.readField("x")).asInstanceOf[Double]
val y = doubleUnpickler.unpickleEntry(reader.readField("y")).asInstanceOf[Double]
new Point2D.Double(x, y)
}
}
}
Which could be used as :
import scala.pickling.Defaults._
import scala.pickling.json._
import java.awt.geom.Point2D
import Point2DPickler._
val dpoint = new Point2D.Double(1d, 2d)
scala> val json = dpoint.pickle
json: pickling.json.pickleFormat.PickleType =
JSONPickle({
"$type": "java.awt.geom.Point2D.Double",
"x": {
"$type": "scala.Double",
"value": 1.0
},
"y": {
"$type": "scala.Double",
"value": 2.0
}
})
scala> val dpoint2 = json.value.unpickle[java.awt.geom.Point2D.Double]
dpoint2: java.awt.geom.Point2D.Double = Point2D.Double[1.0, 2.0]
Is it possible to create JSON values in Groovy using the default JsonBuilder library to exclude all the null values of an object? Such as what Jackson does in Java by annotating classes to exclude null values.
An example would be:
{
"userId": "25",
"givenName": "John",
"familyName": null,
"created": 1360080426303
}
Which should be printed as:
{
"userId": "25",
"givenName": "John",
"created": 1360080426303
}
Not sure if it's OK for you as my method works on a Map with List properties:
def map = [a:"a",b:"b",c:null,d:["a1","b1","c1",null,[d1:"d1",d2:null]]]
def denull(obj) {
if(obj instanceof Map) {
obj.collectEntries {k, v ->
if(v) [(k): denull(v)] else [:]
}
} else if(obj instanceof List) {
obj.collect { denull(it) }.findAll { it != null }
} else {
obj
}
}
println map
println denull(map)
yields:
[a:a, b:b, c:null, d:[a1, b1, c1, null, [d1:d1, d2:null]]]
[a:a, b:b, d:[a1, b1, c1, [d1:d1]]]
After filter null values out, you then can render the Map as JSON.
I used the Groovy metaClass to workaround this issue, but am not sure it would work in all cases.
I created a Class to hold the required elements, but left out the optional elements that could possibly have a null (or empty) value.
private class User {
def id
def username
}
Then, I added the data to this class. My use case was fairly complex so this is a simplified version just to show an example of what I did:
User a = new User(id: 1, username: 'john')
User b = new User(id: 2, username: 'bob')
def usersList = [a,b]
usersList.each { u ->
if (u.id == 1)
u.metaClass.hobbies = ['fishing','skating']
}
def jsonBuilder = new JsonBuilder([users: usersList])
println jsonBuilder.toPrettyString()
Results:
{
"users": [
{
"id": 1,
"username": "john",
"hobbies": [
"fishing",
"skating"
]
},
{
"id": 2,
"username": "bob"
}
]
}
If you do not need use JSONBuilder you can use com.fasterxml.jackson:
Make object:
private static final ObjectMapper JSON_MAPPER = new ObjectMapper().with {
setSerializationInclusion(JsonInclude.Include.NON_NULL)
setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE)
}
and display your list of maps like that (maps can have any Object inside):
println(JSON_MAPPER.writeValueAsString(listOfMaps))
If you are using Groovy >2.5.0, you can use JsonGenerator. The example below is taken from Groovy's Documentation as of July 2018.
class Person {
String name
String title
int age
String password
Date dob
URL favoriteUrl
}
Person person = new Person(name: 'John', title: null, age: 21, password: 'secret',
dob: Date.parse('yyyy-MM-dd', '1984-12-15'),
favoriteUrl: new URL('http://groovy-lang.org/'))
def generator = new JsonGenerator.Options()
.excludeNulls()
.dateFormat('yyyy#MM')
.excludeFieldsByName('age', 'password')
.excludeFieldsByType(URL)
.build()
assert generator.toJson(person) == '{"dob":"1984#12","name":"John"}'
I am querying twitter api to get the tweets with a hashtag in grails 2.1.1.
My Controller is
import grails.converters.*
import org.codehaus.groovy.grails.web.json.*; // package containing JSONObject, JSONArray,...
import groovyx.net.http.*
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
class NepTweetController {
def index() {
//def restEndpointUrl = "http://search.twitter.com/search.json?q=%23nepal";
def restEndpointUrl = "http://search.twitter.com/search.json?q=%23nepal";
def http = new HTTPBuilder(restEndpointUrl);
// perform a GET request, expecting JSON response data
http.request( GET, JSON ) {
//uri.path = '/search.json'
//uri.query = [ q: '%23nepal' ]
response.success = { resp, json ->
// def tweetsResult = json.results;
// List parsedList = JSON.parse(json) as List;
// JSONObject tweetJson = JSON.parse(json);
//def tweetJson = JSON.parse(json);
def tweets = new JSON(json) as Map;
render(view: "index", model: [message: "Request sent" , tweets: tweets]);
}
}//end of request
}//end of method
}
I successfully get the json response as follows :
{
"completed_in": 0.017,
"max_id": 271907240007581696,
"max_id_str": "271907240007581696",
"next_page": "?page=2&max_id=271907240007581696&q=%23nepal%2F",
"page": 1,
"query": "%23nepal%2F",
"refresh_url": "?since_id=271907240007581696&q=%23nepal%2F",
"results": [
{
"created_at": "Fri, 23 Nov 2012 09:25:12 +0000",
"from_user": "iBshnu",
"from_user_id": 25051623,
"from_user_id_str": "25051623",
"from_user_name": "Bishnu Bhattarai",
"geo": null,
"id": 271907240007581696,
"id_str": "271907240007581696",
"iso_language_code": "ne",
"metadata": {
"result_type": "recent"
},
"profile_image_url": "http:\/\/a0.twimg.com\/profile_images\/2622309791\/42z33jnw1kak9ttyqkrf_normal.jpeg",
"profile_image_url_https": "https:\/\/si0.twimg.com\/profile_images\/2622309791\/42z33jnw1kak9ttyqkrf_normal.jpeg",
"source": "<a href="http:\/\/twitter.com\/">web<\/a>",
"text": "RT #dipakbhattarai: \u0930\u093e\u0937\u094d\u091f\u094d\u0930\u092a\u0924\u093f \u0921\u093e. \u0930\u093e\u092e\u092c\u0930\u0923 \u092f\u093e\u0926\u0935\u0926\u094d\u0935\u093e\u0930\u093e \u092e\u0919\u094d\u0938\u093f\u0930 \u0967\u096a \u092d\u093f\u0924\u094d\u0930 \u0926\u0932\u0939\u0930\u0941\u0932\u093e\u0908 \u0930\u093e\u0937\u094d\u091f\u094d\u0930\u093f\u092f \u0938\u0939\u092e\u0924\u093f\u0915\u094b \u0938\u0930\u0915\u093e\u0930 \u092c\u0928\u093e\u0909\u0928 \u0906\u0935\u094d\u0939\u093e\u0928\u0964 #Nepal",
"to_user": null,
"to_user_id": 0,
"to_user_id_str": "0",
"to_user_name": null
},
{
"created_at": "Fri, 23 Nov 2012 09:24:58 +0000",
"from_user": "Phanindra07",
"from_user_id": 63104333,
"from_user_id_str": "63104333",
"from_user_name": "Phanindra Dahal",
"geo": null,
"id": 271907179404095488,
"id_str": "271907179404095488",
"iso_language_code": "en",
"metadata": {
"result_type": "recent"
},
"profile_image_url": "http:\/\/a0.twimg.com\/profile_images\/2417859753\/febstuo4p4zltimnpky0_normal.jpeg",
"profile_image_url_https": "https:\/\/si0.twimg.com\/profile_images\/2417859753\/febstuo4p4zltimnpky0_normal.jpeg",
"source": "<a href="http:\/\/twitter.com\/">web<\/a>",
"text": "RT #DeepakAdk: Chef's assault on #Nepal #Maoist reflects grassroots anger, excellent piece by my #AFP colleague #FrankieTaggart http:\/\/t.co\/M47qJeoD",
"to_user": null,
"to_user_id": 0,
"to_user_id_str": "0",
"to_user_name": null
}
[....more....]
My /views/nepTweet/index.gsp is
<meta name='layout' content='main'/>
<b>${message}</b>
<p>Tweets</p>
<g:each in="${tweets}" var="tweet">
<p>${tweet.text}</p>
</g:each>
But, I get error parsing json to grails Map.
Error I get is :
Error 500: Internal Server Error
URI
/WhoTweetsNepal/nepTweet
Class
groovy.lang.MissingMethodException
Message
No signature of method: grails.converters.JSON.entrySet() is applicable for argument types: () values: [] Possible solutions: every()
I went through How do I access A JSON Object(String) from GSP page?, but couldn't get help.
Helpppp!!!
You definitely want
def tweetJson = JSON.parse(json);
(which will return a JSONObject, which is a Map) instead of
def tweetJson = new JSON(json) as Map;
but it looks like you have a bit of a name clash in your code - presumably the JSON in
http.request( GET, JSON )
is intended to be the HTTPBuilder content type rather than grails.converters.JSON. If you can clear up this name clash (i.e. remove the import static and say ContentType.JSON) then things may run more smoothly.
With to the point suggestions from Ian Roberts, I got the solution with my final Controller to be(realising there is no need to parse it) :
import grails.converters.*
import org.codehaus.groovy.grails.web.json.*; // package containing JSONObject, JSONArray,...
import groovyx.net.http.*
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
class NepTweetController {
def index() {
def restEndpointUrl = "http://search.twitter.com/search.json?q=%23nepal";
def http = new HTTPBuilder(restEndpointUrl);
// perform a GET request, expecting JSON response data
http.request( GET, ContentType.JSON ) {
//uri.path = '/search.json'
//uri.query = [ q: '%23nepal' ]
response.success = { resp, json ->
def tweetsResult = json.results;
render(view: "index", model: [message: "Request sent" , tweets: tweetsResult]);
}
}//end of request
}//end of method
}