Is it possible, with Ada, to implement the following JSON containing a function declaration x: integer (float(x))?
Example_JSON = "Integer": lambda x: integer (float(x))}
If so, how?
I've tried to find a method in GNATCOLL.JSON without success.
It is impossible because a JSON value, according to RFC 8259 can only be one of the following:
null
true
false
object
array
number
string
You can put the function's source code into a string, and then parse that string at the receiving end, e.g. {"integer": "lambda x: integer(float(x))"}, but there's no direct way for a function to be a value in an object.
Related
exercise question screenshot
Not sure what's missing. The other discussion solutions seem too complicated compared to my homework question:
Q:
-The variable str_json has been assigned a string of a JSON object
-Call the parse method, pass it str_json and assign the return value to variable jsonobj
-Assign the property the_city to the variable v_the_city
-Assign the property stateval to the variable v_stateval
var str_json = {'v_the_city':'the_city','v_stateval':'stateval'};
var jsonobj = JSON.parse(str_json);
SyntaxError:
the JSON dataJSON.parse: unexpected character at line 1 column 2 of
SyntaxError: unexpected token: identifier
str_json should be a JSON string, not an object.
The JSON.parse() method parses a JSON string, constructing the JavaScript value or object described by the string. An optional reviver function can be provided to perform a transformation on the resulting object before it is returned. Read more here, link.
Syntax:
JSON.parse(text[, reviver])
Parameters:
text - The string to parse as JSON. See the JSON object for a description of JSON syntax.
reviver - [Optional] If a function, this prescribes how the value originally produced by parsing is transformed, before being returned.
During my fresh adventures with kotlin-react I hit a hard stop when trying to parse some data from my backend which contains enum values.
Spring-Boot sends the object in JSON form like this:
{
"id": 1,
"username": "Johnny",
"role": "CLIENT"
}
role in this case is the enum value and can have the two values CLIENT and LECTURER. If I were to parse this with a java library or let this be handled by Spring-Boot, role would be parsed to the corresponding enum value.
With kotlin-js' JSON.parse, that wouldn't work and I would have a simple string value in there.
After some testing, I came up with this snippet
val json = """{
"id": 1,
"username": "Johnny",
"role": "CLIENT",
}"""
val member: Member = JSON.parse(json) { key: String, value: Any? ->
if (key == "role") Member.Role.valueOf(value.toString())
else value
}
in which I manually have to define the conversion from the string value to the enum.
Is there something I am missing that would simplify this behaviour?
(I am not referring to using ids for the JSON and the looking those up, etc. I am curious about some method in Kotlin-JS)
I have the assumption there is not because the "original" JSON.parse in JS doesn't do this and Kotlin does not add any additional stuff in there but I still have hope!
As far as I know, no.
The problem
Kotlin.JS produces an incredibly weird type situation when deserializing using the embedded JSON class, which actually is a mirror for JavaScript's JSON class. While I haven't done much JavaScript, its type handling is near non-existent. Only manual throws can enforce it, so JSON.parse doesn't care if it returns a SomeCustomObject or a newly created object with the exact same fields.
As an example of that, if you have two different classes with the same field names (no inheritance), and have a function that accepts a variable, it doesn't care which of those (or a third for that matter) it receives as long as the variables it tries accessing on the class exists.
The type issues manifest themselves into Kotlin. Now wrapping it back to Kotlin, consider this code:
val json = """{
"x": 1, "y": "yes", "z": {
"x": 42, "y": 314159, "z": 444
}
}""".trimIndent()
data class SomeClass(val x: Int, val y: String, val z: Struct)
data class Struct(val x: Int, val y: Int, val z: Int)
fun main(args: Array<String>) {
val someInstance = JSON.parse<SomeClass>(json)
if(someInstance.z::class != Struct::class) {
println("Incompatible types: Required ${Struct::class}, found ${someInstance.z::class}");
}
}
What would you expect this to print? The natural would be to expect a Struct. The type is also explicitly declared
Unfortunately, that is not the case. Instead, it prints:
Incompatible types: Required class Struct, found class Any
The point
The embedded JSON de/serializer isn't good with types. You might be able to fix this by using a different serializing library, but I'll avoid turning this into a "use [this] library".
Essentially, JSON.parse fails to parse objects as expected. If you entirely remove the arguments and try a raw JSON.parse(json); on the JSON in your question, you'll get a role that is a String and not a Role, which you might expect. And with JSON.parse doing no type conversion what so ever, that means you have two options: using a library, or using your approach.
Your approach will unfortunately get complicated if you have nested objects, but with the types being changed, the only option you appear to have left is explicitly parsing the objects manually.
TL;DR: your approach is fine.
So my problem is presenting as a type-matching of sorts; I have code that queries a database, and returns an array of string type. When I attempt to validate against my JSON message returned from a web service, one of the values is a primitive integer (without the double-quotes), and the validation is failing, as it is stating: Expected: iterable containing {"1", "1", "1", "1", "1"}Actual: [1, 1, 1, 1, 1]I'm using the contains matcher to validate a ListArray of values against many returned by the query. My assumption is that the Actual is being evaluated as an integer, but the values to validate against (Expected) are String. I've been racking my brain attempting the HasToString or hasItem matchers but I think that would just parse toString if the target is a single value.I guess my ultimate question is, is there a way to force Hamcrest to evaluate the JSON data as a String, or implicitly/explicitly cast the Expected to the evaluated type?Thanks in advance.
So, I acutally think I figured this one out; what I ended up doing was performing a toString(). on the extracted ArrayList of objects, which gave me string values; code example below:
ArrayList<String> myObj = response.path(jsonField);
String[] myObjStr = new String[myObj.size()];
int x = 0;
for (Object obj : myObj){
myObjStr[x] = obj.toString();
x++;
}
From there, I was able to compare the resulting arrays; Now if only I could figure out how to get rid of pesky angle brackets for nested elements...
I'm trying to understand what is going on when I query data from a database and provide it to JSON and then push it to a GUI, in regards to what and when is converting to a string.
If I make a call to a database and provide this data as JSON to the front end, my JSON may look like
MyData{ [["Name": "Anna", "Age": 50],["Name": "Bob", "Age": 40 ]};
Visually it appears as if the value for Name is a string (as it's in quote marks) and the value for Age is an integer (as of no quote marks).
My 2 questions are
Is my understanding that the value for Name is a string and the value of Age is an integer or does JavaScript convert/cast behind the scenes?
How would I specify the type DateTime. According to The "right" JSON date format I actually just ensure the format is correct but ultimately it's a string.
Is my understanding that the value for Name is a string and the value of Age is an integer...?
Almost. It's a number, which may or may not be an integer. For instance, 10.5 is a number, but not an integer.
...or does JavaScript convert/cast behind the scenes?
JavaScript and JSON are different things. JSON defines that the number will be represented by a specific format of digits, . and possibly the e or E character. Whatever environment you're parsing the JSON in will map that number to an appropriate data type in its environment. In JavaScript's case, it's an IEEE-754 double-precision binary floating point number. So in that sense, JavaScript may cast/convert the number, if the JSON defines a number that can't be accurately represented in IEEE-754, such as 9007199254740999 (which becomes the number 9007199254741000 because IEEE-754 only has ~15 digits of decimal precision).
How would I specify the type DateTime. According to The "right" JSON date format I actually just ensure the format is correct but ultimately it's a string.
JSON has a fixed number of types: object, array, string, number, boolean, null. You can't add your own. So what you do is encode any type meta-data you want into either the key or value, or use an object with separate properties for type and value, and enforce that agreement at both ends.
An example of doing this is the common format for encoding date/time values: "/Date(1465198261547)/". As far as the JSON parser is concerned, that's just a string, but many projects use it as an indicator that it's actually a date, with the number in the parens being the number of milliseconds since The Epoch (Jan 1 1970 at midnight, GMT).
Two concepts related to this are a replacer and a reviver: When converting a native structure to JSON, the JSON serializer you're using may support a replacer which lets you replace a value during the serialization with another value. The JSON parser you're using may support a reviver that lets you handle the process in the other direction.
For example, if you were writing JavaScript code and wanted to preserve Dates across a JSON layer, you might do this when serializing to JSON:
var obj = {
foo: "bar",
answer: 42,
date: new Date()
};
var json = JSON.stringify(obj, function(key, value) {
var rawValue = this[key];
if (rawValue instanceof Date) {
// It's a date, convert it to our special format
return "/Date(" + rawValue.getTime() + ")/";
}
return value;
});
console.log(json);
That uses the "replacer" parameter of JSON.stringify to encode dates in the way I described earlier.
Then you might do this when parsing that JSON:
var json = '{"foo":"bar","answer":42,"date":"/Date(1465199095286)/"}';
var rexIsDate = /^\/Date\((-?\d+)\)\/$/;
var obj = JSON.parse(json, function(key, value) {
var match;
if (typeof value == "string" && (match = rexIsDate.exec(value)) != null) {
// It's a date, create a Date instance using the number
return new Date(+match[1]);
}
return value;
});
console.log(obj);
That uses a "reviver" to detect keys in the special format and convert them back into Date instances.
The specific format of a JSON string can be described by JSON Schema, as described here; in particular, date-time apparently is a type already defined in JSON Schema.
So you can replace a property with a number, string, array, or object in JSON.stringify, like so:
var myObj = {
'allstar': aFunction;
}
function myReplacer(key, value) {
if(key === 'allstar') {
return 'newFunction()';
}
}
JSON.stringify(myObj, myReplacer); //returns '{"allstar": "newFunction()"}'
But can you change it so that it instead returns '{"allstar": newFunction()}' (without the quotes around newFunction)?
I assume typeof aFunction == "function"? If so, even JSON.stringify(myObj) will not do what you want it to do, but return '{}' i.e. an object without properties, because functions are not supported in JSON.
Your desired result is not even valid JSON. newFunction() without quotes is not a supported value (string, number, array, object, boolean, null).
Edit: you could try to return newfunction.toString() in your replacer, which should deliver your function's source as string. When converting the JSON back, you then must eval() this string to get the actual function.
#derpirscher provided a very good answer that will probably get more upvotes than this one, but this is my preferred answer:
Based on derpirscher's answer I decided it would be easier to make my own version of JSON.stringify that allows you to replace properties with your own source code, and changed the name of the module so that there is no naming conflict with JSON.
It's on my github account:
https://github.com/johnlarson/xerxes