JSON undefined value type - json

I came across this JSON code. I noticed that it makes use of undefined value. Where can I find more information about this value type?
tracks:[
( {
codec:"h264",
language:undefined,
id:1,
bitrate:785236,
content:"video"
} ),
( {
codec:"aac",
language:undefined,
id:2,
bitrate:75969,
content:"audio"
} )
],

undefined is not a valid JSON value, even though it is valid in javascript.
From the official JSON standard
(ECMA-404, Section 5):
A JSON value can be an object, array, number, string, true, false, or null.
For JSON, use null instead of undefined: { "something": null }

undefined is a special type where it simply indicates that the variable language is not initialized or may be it's not yet defined.
null in javascript simply indicates absence of a value, and it can also be used to indicate “no value” for numbers and strings as well as objects.The undefined value also represents absence of value, it is the value of the variables that have not been initialized and the value when you get from object property or array element that doesn’t exist
undefined is a predefined global variable that is initialized to undefined value.
null and undefined doesn’t have any properties or methods.In fact, using . or [] to access property or method of these values causes a TypeError.

Related

Is there a way to avoid returning `any` within a JSON.parse reviver?

I have a project using TypeScript and ESLint. I need to deserialize a JSON string, and want to take advantage of the optional reviver parameter. A reviver function basically lets you conditionally transform values as part of the JSON deserialization.
The signature of the reviver function is defined as part of the JSON.parse specification, which is:
JSON.parse(text: string, reviver?: ((this: any, key: string, value: any) => any) | undefined): any
In particular: it takes in a value of type any and returns a value of type any.
const deserializedValue: unknown = JSON.parse(serializedValue, (key, value) => {
if (value === 'foo') {
return 'bar
}
return value
}
I'm scolded by ESLint because when I write return value I am returning something of any type:
5:4 error Unsafe return of an `any` typed value #typescript-eslint/no-unsafe-return
Is there a way for me to programmatically avoid the linting complaint about any types within the constraints of the unknown nature of deserialization, or do I have to disable the linting rule for that line?
eslint is a bit overzealous here. Or at least that rule doesn't apply well to this case.
Parsing JSON is an inherently type unsafe process. In this case the any is just passed through from the argument type, and the function is typed in a place you can't control to return any.
So I'd probably just cast it to unknown like:
return value as unknown
Which sort of makes it clear that "I don't know or care what this is". And the return type does matter because anything matches any and the return type is used in the return type of JSON.parse().
This seems to work.
But that's probably not that much better than disabling the rule for that line either. Which is right is more a matter of opinion.
But still, I'd go with the as unknown cast.

Pass list of integers as parameters to Ember transitionTo()?

I'm trying to pass a list of integers (of the form [1,5]) as params in transitionTo in Ember 3.14. I've verified that the list can be read within this function:
afterModel() {
this.transitionTo('newRoute', this.modelFor('lastLevel').list);
},
But I always get this error:
Cannot read property '0' of undefined TypeError: Cannot read property '0' of undefined
How should I transform the list so it will pass into transitionTo()?
I found the pretty simple solution. I had to join the list into a string:
this.transitionTo('newRoute', this.modelFor('lastLevel').list.join(',');

Replacing data fields with code in JSON.stringify?

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

Getting a single value from a JSON object using JSONPath

I have the following JSON and I need to get the plain name value using JSONPath:
{
"single" : {
"id" : 1,
"name" : "Item name"
}
}
Expression that I used is $.single.name but I always get an array:
[ "Item name" ]
instead of a string value ("Item name").
but I always get an array:
That is meant to happen. As you can read in this documentation, under 'Result' (almost at the bottom):
Please note, that the return value of jsonPath is an array, which is
also a valid JSON structure. So you might want to apply jsonPath to
the resulting structure again or use one of your favorite array
methods as sort with it.
So basically it will always return an array. If you need the data as an other type, e.g. a String in this case, you will have to do the conversion yourself I'm afraid.
I was using the Java implementation of JSONPath and got to the very same issue. What worked for me was to add '[0]' to the json path string. So in your case:
$.single.name[0]
I think, it depends of language implementation.
For example in nodejs there is a npm module : https://www.npmjs.com/package/jsonpath
Which have a method called value, which does exactly what we need
jp.value(obj, pathExpression[, newValue])
Returns the value of the first element matching pathExpression. If newValue is provided, sets the value of the first matching element and returns the new value.
I tried it and worked!
In case you got this error
"Unable to get a scalar value for expression $.yourfield"
You have just to configure the EvaluateJsonPath processor by changing the return type property value to 'json' instead of 'auto-detect'

Representing null in JSON

What is the preferred method for returning null values in JSON? Is there a different preference for primitives?
For example, if my object on the server has an Integer called "myCount" with no value, the most correct JSON for that value would be:
{}
or
{
"myCount": null
}
or
{
"myCount": 0
}
Same question for Strings - if I have a null string "myString" on the server, is the best JSON:
{}
or
{
"myString": null
}
or
{
"myString": ""
}
or (lord help me)
{
"myString": "null"
}
I like the convention for collections to be represented in the JSON as an empty collection http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html
An empty Array would be represented:
{
"myArray": []
}
EDIT Summary
The 'personal preference' argument seems realistic, but short sighted in that, as a community we will be consuming an ever greater number of disparate services/sources. Conventions for JSON structure would help normalize consumption and reuse of said services. As far as establishing a standard, I would suggest adopting most of the Jackson conventions with a few exceptions:
Objects are preferred over primitives.
Empty collections are preferred over null.
Objects with no value are represented as null.
Primitives return their value.
If you are returning a JSON object with mostly null values, you may have a candidate for refactoring into multiple services.
{
"value1": null,
"value2": null,
"text1": null,
"text2": "hello",
"intValue": 0, //use primitive only if you are absolutely sure the answer is 0
"myList": [],
"myEmptyList": null, //NOT BEST PRACTICE - return [] instead
"boolean1": null, //use primitive only if you are absolutely sure the answer is true/false
"littleboolean": false
}
The above JSON was generated from the following Java class.
package jackson;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonApp {
public static class Data {
public Integer value1;
public Integer value2;
public String text1;
public String text2 = "hello";
public int intValue;
public List<Object> myList = new ArrayList<Object>();
public List<Object> myEmptyList;
public Boolean boolean1;
public boolean littleboolean;
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new Data()));
}
}
Maven dependency:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.3.0</version>
</dependency>
Let's evaluate the parsing of each:
http://jsfiddle.net/brandonscript/Y2dGv/
var json1 = '{}';
var json2 = '{"myCount": null}';
var json3 = '{"myCount": 0}';
var json4 = '{"myString": ""}';
var json5 = '{"myString": "null"}';
var json6 = '{"myArray": []}';
console.log(JSON.parse(json1)); // {}
console.log(JSON.parse(json2)); // {myCount: null}
console.log(JSON.parse(json3)); // {myCount: 0}
console.log(JSON.parse(json4)); // {myString: ""}
console.log(JSON.parse(json5)); // {myString: "null"}
console.log(JSON.parse(json6)); // {myArray: []}
The tl;dr here:
The fragment in the json2 variable is the way the JSON spec indicates null should be represented. But as always, it depends on what you're doing -- sometimes the "right" way to do it doesn't always work for your situation. Use your judgement and make an informed decision.
JSON1 {}
This returns an empty object. There is no data there, and it's only going to tell you that whatever key you're looking for (be it myCount or something else) is of type undefined.
JSON2 {"myCount": null}
In this case, myCount is actually defined, albeit its value is null. This is not the same as both "not undefined and not null", and if you were testing for one condition or the other, this might succeed whereas JSON1 would fail.
This is the definitive way to represent null per the JSON spec.
JSON3 {"myCount": 0}
In this case, myCount is 0. That's not the same as null, and it's not the same as false. If your conditional statement evaluates myCount > 0, then this might be worthwhile to have. Moreover, if you're running calculations based on the value here, 0 could be useful. If you're trying to test for null however, this is actually not going to work at all.
JSON4 {"myString": ""}
In this case, you're getting an empty string. Again, as with JSON2, it's defined, but it's empty. You could test for if (obj.myString == "") but you could not test for null or undefined.
JSON5 {"myString": "null"}
This is probably going to get you in trouble, because you're setting the string value to null; in this case, obj.myString == "null" however it is not == null.
JSON6 {"myArray": []}
This will tell you that your array myArray exists, but it's empty. This is useful if you're trying to perform a count or evaluation on myArray. For instance, say you wanted to evaluate the number of photos a user posted - you could do myArray.length and it would return 0: defined, but no photos posted.
null is not zero. It is not a value, per se: it is a value outside the domain of the variable indicating missing or unknown data.
There is only one way to represent null in JSON. Per the specs (RFC 4627 and json.org):
2.1. Values
A JSON value MUST be an object, array, number, or string, or one of
the following three literal names:
false null true
There is only one way to represent null; that is with null.
console.log(null === null); // true
console.log(null === true); // false
console.log(null === false); // false
console.log(null === 'null'); // false
console.log(null === "null"); // false
console.log(null === ""); // false
console.log(null === []); // false
console.log(null === 0); // false
That is to say; if any of the clients that consume your JSON representation use the === operator; it could be a problem for them.
no value
If you want to convey that you have an object whose attribute myCount has no value:
{ "myCount": null }
no attribute / missing attribute
What if you to convey that you have an object with no attributes:
{}
Client code will try to access myCount and get undefined; it's not there.
empty collection
What if you to convey that you have an object with an attribute myCount that is an empty list:
{ "myCount": [] }
I would use null to show that there is no value for that particular key. For example, use null to represent that "number of devices in your household connects to internet" is unknown.
On the other hand, use {} if that particular key is not applicable. For example, you should not show a count, even if null, to the question "number of cars that has active internet connection" is asked to someone who does not own any cars.
I would avoid defaulting any value unless that default makes sense. While you may decide to use null to represent no value, certainly never use "null" to do so.
I would pick "default" for data type of variable (null for strings/objects, 0 for numbers), but indeed check what code that will consume the object expects. Don't forget there there is sometimes distinction between null/default vs. "not present".
Check out null object pattern - sometimes it is better to pass some special object instead of null (i.e. [] array instead of null for arrays or "" for strings).
According to the JSON spec, the outermost container does not have to be a dictionary (or 'object') as implied in most of the comments above. It can also be a list or a bare value (i.e. string, number, boolean or null). If you want to represent a null value in JSON, the entire JSON string (excluding the quotes containing the JSON string) is simply null. No braces, no brackets, no quotes. You could specify a dictionary containing a key with a null value ({"key1":null}), or a list with a null value ([null]), but these are not null values themselves - they are proper dictionaries and lists. Similarly, an empty dictionary ({}) or an empty list ([]) are perfectly fine, but aren't null either.
In Python:
>>> print json.loads('{"key1":null}')
{u'key1': None}
>>> print json.loads('[null]')
[None]
>>> print json.loads('[]')
[]
>>> print json.loads('{}')
{}
>>> print json.loads('null')
None
This is a personal and situational choice. The important thing to remember is that the empty string and the number zero are conceptually distinct from null.
In the case of a count you probably always want some valid number (unless the count is unknown or undefined), but in the case of strings, who knows? The empty string could mean something in your application. Or maybe it doesn't. That's up to you to decide.
'null' is best for practical use
FWIW, using PHP as an example, PHP interprets empty sets as entries made by PHP...
// This loop will iterate one item with the value 'the car'
$empty_json = '["the car"]';
$some_json_array = json_decode($empty_json);
foreach ($some_json_array as $i) {
echo "PHP sees one item";
}
output: PHP sees the car
// This loop will iterate one item, but with no values
$empty_json = '[""]';
$some_json_array = json_decode($empty_json);
foreach ($some_json_array as $i) {
echo "PHP sees: $i";
}
output: PHP sees
// This loop will iterate nothing because PHP's `json_decode()` function knew it was `null`
$empty_json = 'null';
$some_json_array = json_decode($empty_json);
foreach ($some_json_array as $i) {
echo "PHP sees one item";
}
output: (nothing, foreach will not loop)