json-schema-org / vocab-idl

Help and clarify how JSON Schema can be interpreted from validation rules to data definition. This extends to how those data definitions can be represented in any programming language

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Define how to handle `null` type

jonaslagoni opened this issue · comments

We need to figure out how we want to handle the null type overall.

In JSON, null is a different concept than "not present" and the types we generate need to reflect that. In most languages, null or nil is synonymous with "not present". In those languages I would expect code gen to use a custom type that represents the JSON null value.

So, for null I am not quite sure what is best. If we look at the behavior JSON schema has on the JSON data.

JSON Schema:

{ "properties": { "test": { "type": "null" } } }

validates correctly against

{ "test": null }

and

{  }

In a sense, removing the property completely makes sense to some extend here, as there are no values you want to access is there?

However, with require, removing the property is not possible and it needs to be present:

{ "required": ["test"], "properties": { "test": { "type": "null" } } }

validates correctly against

{ "test": null }

but not

{  }

In a sense, we have the same scenario anyway, where you don't really have an incentive to access such as property in any use-case is there (besides when the class is serialized the property needs to be there)?

In TS we can do the following:

class testType {
  test: null
}

And for Java:

class testType {
  final Object test = null;
}

We could also let custom serializable functionality handle it, and not generate the property at all:

class testType {
  serialize(){
    return '{test: null}'
  }
}

I do however find that a bit weird 🤔 What are your thoughts?

You have to remember that JSON Schema describes JSON data and in JSON, null is a value. null is also a type, that contains one value: null. It's just like boolean which is a type that contains two values: true and false. This concept is not compatible with Java's null. In Java, null is not a type. Any type can be null because null means "there isn't anything here". It's equivalent to not defining a property in the instance.

So, in your example, the "test" property definitely needs to be generated because null doesn't mean "there isn't anything here", it means there's a thing here called null. So, in Java I would expect the following.

"test" is null and not required

class TestType {
  JsonNull test = JsonNull.getInstance();
}

"test" is null and required

class TestType {
  @NotNull
  JsonNull test = JsonNull.getInstance();
}

I'm assuming JsonNull is defined by the implementation to be a singleton class. Since there's no equivalent of JSON's null in Java, we have to create something to represent that concept. TypeScript, on the other hand does have the same concept of null as JSON because it's runtime is JavaScript. So, we don't need to create something to represent it.

"test" is null and not required

type TestType = {
  test?: null;
}

"test" is null and required

type TestType = {
  test: null;
}

Alright, that makes sense 👍 Thanks for clarifying 🙂

I realize this has been closed for a while, but I thought this was relevant.

null is also important in how many APIs handle 'PUT' and even PATCH requests. For these APIs, { "test": null } means "clear the test property, whereas { } means do nothing.

In some API frameworks (like what's offered out of the box by .Net), this is difficult to discern, though, because they treat null and "absent" as the same when deserializing JSON into models.