How to use wslite.rest.RestClient to get simple boolean value - json

I have a problem when using wslite.rest.RestClient in groovy, when I want to get response from endpoint that returns simple boolean "false".
def client = new wslite.rest.RESTClient("url:port")
def booleanResponse = client.get(path: "/path")
I get this error:
wslite.rest.RESTContentParseException: A JSONObject text must begin with '{' at 1 [character 2 line 1]
Endpoint that is returning boolean (in spring-boot) looks like this:
#GetMapping(path = "/path", produces = HAL_JSON_VALUE)
public boolean endpointName(#PathVariable("param") String param) {
return false;
}
Is there any posibility to get this value without editing endpoint? I want to use RestClient in tests only.
I tried adding some extra properties like
accept: ContentType.TEXT
but it of course doesn't work (it returns 406 Not acceptable response).

Related

How to split the data of NodeObject in Apache Flink

I'm using Flink to process the data coming from some data source (such as Kafka, Pravega etc).
In my case, the data source is Pravega, which provided me a flink connector.
My data source is sending me some JSON data as below:
{"key": "value"}
{"key": "value2"}
{"key": "value3"}
...
...
Here is my piece of code:
PravegaDeserializationSchema<ObjectNode> adapter = new PravegaDeserializationSchema<>(ObjectNode.class, new JavaSerializer<>());
FlinkPravegaReader<ObjectNode> source = FlinkPravegaReader.<ObjectNode>builder()
.withPravegaConfig(pravegaConfig)
.forStream(stream)
.withDeserializationSchema(adapter)
.build();
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<ObjectNode> dataStream = env.addSource(source).name("Pravega Stream");
dataStream.map(new MapFunction<ObjectNode, String>() {
#Override
public String map(ObjectNode node) throws Exception {
return node.toString();
}
})
.keyBy("word") // ERROR
.timeWindow(Time.seconds(10))
.sum("count");
As you see, I used the FlinkPravegaReader and a proper deserializer to get the JSON stream coming from Pravega.
Then I try to transform the JSON data into a String, KeyBy them and count them.
However, I get an error:
The program finished with the following exception:
Field expression must be equal to '*' or '_' for non-composite types.
org.apache.flink.api.common.operators.Keys$ExpressionKeys.<init>(Keys.java:342)
org.apache.flink.streaming.api.datastream.DataStream.keyBy(DataStream.java:340)
myflink.StreamingJob.main(StreamingJob.java:114)
It seems that KeyBy threw this exception.
Well, I'm not a Flink expert so I don't know why. I've read the source code of the official example WordCount. In that example, there is a custtom splitter, which is used to split the String data into words.
So I'm thinking if I need to use some kind of splitter in this case too? If so, what kind of splitter should I use? Can you show me an example? If not, why did I get such an error and how to solve it?
I guess you have read the document about how to specify keys
Specify keys
The example codes use keyby("word") because word is a field of POJO type WC.
// some ordinary POJO (Plain old Java Object)
public class WC {
public String word;
public int count;
}
DataStream<WC> words = // [...]
DataStream<WC> wordCounts = words.keyBy("word").window(/*window specification*/);
In your case, you put a map operator before keyBy, and the output of this map operator is a string. So there is obviously no word field in your case. If you actually want to group this string stream, you need to write it like this .keyBy(String::toString)
Or you can even implement a customized keySelector to generate your own key.
Customized Key Selector

Groovy/Grails - Json web service, map received with extra properties

I'm busy working on a function that sends a map (and other irrelevant values) through a json web service but the problem is that on the receiving side it sees it as JSONObject (using the getClass() method) and coz of this it adds extra properties to the object thus causing the service to return an error. So on the sending side the map println's like this:
[21:{adultValue=1, kidValue=0}, 11:{adultValue=0, kidValue=4}]
But on the receiving side it println's like this:
[11:[metaPropertyValues:[[name:adultValue, modifiers:1, type:java.lang.Object], [name:kidValue, modifiers:1, type:java.lang.Object]], properties:[kidValue:4, adultValue:0]], 21:[metaPropertyValues:[[name:adultValue, modifiers:1, type:java.lang.Object], [name:kidValue, modifiers:1, type:java.lang.Object]], properties:[kidValue:0, adultValue:1]]]
So on the receiving side there is code that does the following (simplified for this question):
map.each { key, value ->
def adultValue = value.adultValue.toInteger()
}
But it obviously throws a NullPointer exception coz according to the receiving side there's no map.adultValue, there's only a map.properties.adultValue
So my question is, what can I do on the sending side so that the receiving side receives it the same way that it was sent? I'm not allowed to change the receiving side's code but I can look at the output.
For extra clarification, here's the code I use on the sending side to make the web service call:
def addAddons(map, anotherVar1, anotherVar2) {
println(map) // outputs the map as shown above
try {
def result
def http = new HTTPBuilder("the real url, not shown here")
http.request(Method.POST, groovyx.net.http.ContentType.JSON) { req ->
body = [anotherVar1: anotherVar1, anotherVar2: anotherVar2, map: map]
response.success = { resp, json ->
result = json
}
}
println("result: ${result}")
return result
} catch (all) {
all.printStackTrace()
return null
}
}
Please let me know if there's anything else I need to add
You may also consider to use a JSON converter, so you still can create a Map and create the string out of the map.
import groovy.json.JsonOutput
def json = JsonOutput.toJson(map)
Turns out I was looking at it all wrong. I didn't realise but I was supposed to send a Json object instead of anything else which is why a map didn't work, and neither would an Arraylist (I tried that too, not shown in my question). So I tried to convert it to json using groovy.json.JsonBuilder but I couldn't figure that out so I ended up manually converting my map to json with the following code:
def json = '{'
def counter = 0
map.each { key, value ->
if(counter == map.size()-1) {
json += "\"$key\":{\"adultValue\":${value.adultValue},\"kidValue\":${value.kidValue}}"
} else {
json += "\"$key\":{\"adultValue\":${value.adultValue},\"kidValue\":${value.kidValue}},"
}
counter++
}
json += '}'
And that solved my problem

Grails: Easy and efficient way to parse JSON from a Request

Please pardon me if this is a repeat question. I have been through some of the questions/answers with a similar requirement but somehow got a bit overwhelmed and confused at the same time. My requirement is:
I get a JSON string/object as a request parameter. ( eg: params.timesheetJSON )
I then have to parse/iterate through it.
Here is the JSON that my grails controller will be receiving:
{
"loginName":"user1",
"timesheetList":
[
{
"periodBegin":"2014/10/12",
"periodEnd":"2014/10/18",
"timesheetRows":[
{
"task":"Cleaning",
"description":"cleaning description",
"paycode":"payCode1"
},
{
"task":"painting",
"activityDescription":"painting description",
"paycode":"payCode2"
}
]
}
],
"overallStatus":"SUCCESS"
}
Questions:
How can I retrieve the whole JSON string from the request? Does request.JSON be fine here? If so, will request.JSON.timesheetJSON yield me the actual JSON that I want as a JSONObject?
What is the best way to parse through the JSON object that I got from the request? Is it grails.converters.JSON? Or is there any other easy way of parsing through? Like some API which will return the JSON as a collection of objects by automatically taking care of parsing. Or is programatically parsing through the JSON object the only way?
Like I said, please pardon me if the question is sounding vague. Any good references JSON parsing with grails might also be helpful here.
Edit: There's a change in the way I get the JSON string now. I get the JSON string as a request paramter.
String saveJSON // This holds the above JSON string.
def jsonObject = grails.converters.JSON.parse(saveJSON) // No problem here. Returns a JSONObject. I checked the class type.
def jsonArray = jsonArray.timesheetList // No problem here. Returns a JSONArray. I checked the class type.
println "*** Size of jsonArray1: " + jsonArray1.size() // Returns size 1. It seemed fine as the above JSON string had only one timesheet in timesheetList
def object1 = jsonArray[1] // This throws the JSONException, JSONArray[1] not found. I tried jsonArray.getJSONObject(1) and that throws the same exception.
Basically, I am looking to seamlessly iterate through the JSON string now.
I have wrote some code that explains how this can be done, that you can see below, but to be clear, first the answers to your questions:
Your JSON String as you wrote above will be the contents of your POST payload to the rest controller. Grails will use its data binding mechanism to bind the incomming data to a Command object that your should prepare. It has to have fields corresponding to the parameters in your JSON String (see below). After you bind your command object to your actual domain object, you can get all the data you want, by simply operating on fields and lists
The way to parse thru the JSON object is shown in my example below. The incomming request is esentially a nested map, with can be simply accessed with a dot
Now some code that illustrates how to do it.
In your controller create a method that accepts "YourCommand" object as input parameter:
def yourRestServiceMethod (YourCommand comm){
YourClass yourClass = new YourClass()
comm.bindTo(yourClass)
// do something with yourClass
// println yourClass.timeSheetList
}
The command looks like this:
class YourCommand {
String loginName
List<Map> timesheetList = []
String overallStatus
void bindTo(YourClass yourClass){
yourClass.loginName=loginName
yourClass.overallStatus=overallStatus
timesheetList.each { sheet ->
TimeSheet timeSheet = new TimeSheet()
timeSheet.periodBegin = sheet.periodBegin
timeSheet.periodEnd = sheet.periodEnd
sheet.timesheetRows.each { row ->
TimeSheetRow timeSheetRow = new TimeSheetRow()
timeSheetRow.task = row.task
timeSheetRow.description = row.description
timeSheetRow.paycode = row.paycode
timeSheet.timesheetRows.add(timeSheetRow)
}
yourClass.timeSheetList.add(timeSheet)
}
}
}
Its "bindTo" method is the key piece of logic that understands how to get parameters from the incomming request and map it to a regular object. That object is of type "YourClass" and it looks like this:
class YourClass {
String loginName
Collection<TimeSheet> timeSheetList = []
String overallStatus
}
all other classes that are part of that class:
class TimeSheet {
String periodBegin
String periodEnd
Collection<TimeSheetRow> timesheetRows = []
}
and the last one:
class TimeSheetRow {
String task
String description
String paycode
}
Hope this example is clear enough for you and answers your question
Edit: Extending the answer according to the new requirements
Looking at your new code, I see that you probably did some typos when writting that post
def jsonArray = jsonArray.timesheetList
should be:
def jsonArray = jsonObject.timesheetList
but you obviously have it properly in your code since otherwise it would not work, then the same with that line with "println":
jsonArray1.size()
shuold be:
jsonArray.size()
and the essential fix:
def object1 = jsonArray[1]
shuold be
def object1 = jsonArray[0]
your array is of size==1, the indexing starts with 0. // Can it be that easy? ;)
Then "object1" is again a JSONObject, so you can access the fields with a "." or as a map, for example like this:
object1.get('periodEnd')
I see your example contains errors, which lead you to implement more complex JSON parsing solutions.
I rewrite your sample to the working version. (At least now for Grails 3.x)
String saveJSON // This holds the above JSON string.
def jsonObject = grails.converters.JSON.parse(saveJSON)
println jsonObject.timesheetList // output timesheetList structure
println jsonObject.timesheetList[0].timesheetRows[1] // output second element of timesheetRows array: [paycode:payCode2, task:painting, activityDescription:painting description]

How to get Slurpable data from REST client in Groovy?

I have code that looks like this:
def client = new groovyx.net.http.RESTClient('myRestFulURL')
def json = client.get(contentType: JSON)
net.sf.json.JSON jsonData = json.data as net.sf.json.JSON
def slurper = new JsonSlurper().parseText(jsonData)
However, it doesn't work! :( The code above gives an error in parseText because the json elements are not quoted. The overriding issue is that the "data" is coming back as a Map, not as real Json. Not shown, but my first attempt, I just passed the parseText(json.data) which gives an error about not being able to parse a HashMap.
So my question is: how do I get JSON returned from the RESTClient to be parsed by JsonSlurper?
The RESTClient class automatically parses the content and it doesn't seem possible to keep it from doing so.
However, if you use HTTPBuilder you can overload the behavior. You want to get the information back as text, but if you only set the contentType as TEXT, it won't work, since the HTTPBuilder uses the contentType parameter of the HTTPBuilder.get() method to determine both the Accept HTTP Header to send, as well was the parsing to do on the object which is returned. In this case, you need application/json in the Accept header, but you want the parsing for TEXT (that is, no parsing).
The way you get around that is to set the Accept header on the HTTPBuilder object before calling get() on it. That overrides the header that would otherwise be set on it. The below code runs for me.
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.6')
import static groovyx.net.http.ContentType.TEXT
def client = new groovyx.net.http.HTTPBuilder('myRestFulURL')
client.setHeaders(Accept: 'application/json')
def json = client.get(contentType: TEXT)
def slurper = new groovy.json.JsonSlurper().parse(json)
The type of response from RESTClient will depend on the version of :
org.codehaus.groovy.modules.http-builder:http-builder
For example, with version 0.5.2, i was getting a net.sf.json.JSONObject back.
In version 0.7.1, it now returns a HashMap as per the question's observations.
When it's a map, you can simply access the JSON data using the normal map operations :
def jsonMap = restClientResponse.getData()
def user = jsonMap.get("user")
....
Solution posted by jesseplymale workes for me, too.
HttpBuilder has dependencies to some appache libs,
so to avoid to add this dependencies to your project,
you can take this solution without making use of HttpBuilder:
def jsonSlurperRequest(urlString) {
def url = new URL(urlString)
def connection = (HttpURLConnection)url.openConnection()
connection.setRequestMethod("GET")
connection.setRequestProperty("Accept", "application/json")
connection.setRequestProperty("User-Agent", "Mozilla/5.0")
new JsonSlurper().parse(connection.getInputStream())
}

ContentType application/json in ASP.NET WebAPI

I'm building my first WebAPI using ASP.NET MVC 4 WebAPI.
The requests must be sent using the application/json ContentType with utf-8 as the character set.
My POST method looks like this:
public HttpResponseMessage Post([FromBody]string value)
{
return new HttpResponseMessage(HttpStatusCode.OK);
}
Whenever I'm sending a POST request the parameter 'value' is null. The request body contains Json: { "name":"test" }.
What I prefer is to have the parameter of the Post method to be either a string containing the Json or be of type JObject (from the JSON.NET library). How do I accomplish this? And is this even possible?
The easiest way is to grab the raw string directly from Request.Content:
public async Task<HttpResponseMessage> Post()
{
string value = await Request.Content.ReadAsStringAsync();
return new HttpResponseMessage(HttpStatusCode.OK);
}
There is a way to make ASP.NET Web Api treat your request body as string content, but in order to do that the content must be in =value format, in your case something like this:
={ "name":"test" }
You can achieve something like this with following jQuery code (for example):
$.post('api/values', '=' + JSON.stringify({ name: 'test' }));
In that case you can use signature from your question.
In the end there is always an option of creating your own MediaTypeFormatter to replace the default JsonMediaTypeFormatter and make it always deserialize the content into JObject. You can read more about creating and registering MediaTypeFormatter here and here.