google / google/gson

Distinguish between optional field and field with null value

Open
#1,558 4 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Java
Stars
24.2k
Forks
4.5k
Avg merge
6d 4h
Merged PRs (30d)
12

Description

JSON allows us to express fields that shouldn't be there and fields that could have a null value. These are different things. In Java with cannot have missing fields, so we use `null` to represent both of these states. We're interoping with an external non-Java party that has a schema like this:
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"nullProp": { "type": [ "string", "null" ] },
"optionalProp": { "type": "string" }
},
"required": [ "nullProp" ]
}
```
because `optionalProp` is not listed, it can be omitted from the JSON, but if it exists, it must have a non-null value:
* valid: `{ "nullProp": null, "optionalProp": "my value" }`
* valid: `{ "nullProp": null }`
* valid: `{ "nullProp": "null value", "optionalProp": "my value" }`
* invalid: `{ "nullProp": null, "optionalProp": null }` // `optionalProp` cannot be null
* invalid: `{ }` // missing required `nullProp`

we need to send valid JSON that adheres to the schema (manual tests www.jsonschemavalidator.net)

In Java we represent this with:
```java
class Data {
@Nullable String nullProp;
@Nullable String optionalProp;
}
```
but the serialization behavior needs to be different for these two fields. We've looked at all the combinations of `serializeNulls` and `@JsonAdapter`, but couldn't figure out how to omit the optional field when its null, while keeping the null field there if it's null.

Here's a test we've been trying to pass with no luck:
```java
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
import com.google.gson.*;

class OptionalTest {

class Data {
// TODO @JsonAdapter(NullAdapter.class)?
String nullProp;
// TODO @JsonAdapter(OptionalAdapter.class)?
String optionalProp;
}

private Gson gson;

@BeforeEach void setUp() {
gson = new GsonBuilder()
// TODO .serializeNulls()?
// TODO .registerTypeAdapterFactory()?
.create();
}

@Test void bothNull() {
Data data = new Data();
data.nullProp = null;
data.optionalProp = null;

assertEquals("{\"nullProp\":null}", gson.toJson(data));
}

@Test void filledContents() {
Data data = new Data();
data.nullProp = "some";
data.optionalProp = "thing";

assertEquals("{\"nullProp\":\"some\",\"optionalProp\":\"thing\"}", gson.toJson(data));
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.