|
1 | | -## This project is looking for maintainers. Please refer to the [announcement](https://github.com/OpenAPITools/jackson-databind-nullable/issues/71) for more information. |
2 | | - |
3 | | -# jackson-databind-nullable |
4 | | - |
5 | | -[](https://app.travis-ci.com/github/OpenAPITools/jackson-databind-nullable) |
6 | | - |
7 | | -This module provides a `JsonNullable` wrapper class and a Jackson module to serialize/deserialize it. |
8 | | -The `JsonNullable` wrapper shall be used to wrap Java bean fields for which it is important to distinguish between an explicit `"null"` and the field not being present. |
9 | | -A typical usage is when implementing [Json Merge Patch](https://tools.ietf.org/html/rfc7386) where an explicit `"null"` has the meaning "set this field to null / remove this field" whereas a non-present field has the meaning "don't change the value of this field". |
10 | | - |
11 | | -The module comes with an integrated `ValueExtractor` that automatically unwraps the contained value of the `JsonNullable` if used together with javax.validation Bean validation (JSR 380). |
12 | | - |
13 | | -Note: a lot of people use `Optional` to bring this behavior. |
14 | | -Although it kinda works, it's not a good idea because: |
15 | | -* Beans shouldn't have `Optional` fields. |
16 | | - `Optional` was designed to be used only as method return value. |
17 | | -* `Optional` should never be null. |
18 | | - The goal of `Optional` is to wrap the `null` and prevent NPE so the code should be designed to never assign `null` to an `Optional`. |
19 | | - A code invoking a method returning an Optional should be confident that this Optional is not null. |
20 | | - |
21 | | -## Installation |
22 | | - |
23 | | -The module is compatible with JDK8+ |
24 | | -``` |
25 | | -./mvnw clean install |
26 | | -``` |
27 | | - |
28 | | -## Usage |
29 | | - |
30 | | -`JsonNullable` shall primarily be used in bean fields. |
31 | | - |
32 | | -If we have the following class |
33 | | -```java |
34 | | -public static class Pet { |
35 | | - |
36 | | - @Size(max = 10) |
37 | | - public JsonNullable<String> name = JsonNullable.undefined(); |
38 | | - |
39 | | - public Pet name(JsonNullable<String> name) { |
40 | | - this.name = name; |
41 | | - return this; |
42 | | - } |
43 | | -} |
44 | | - |
45 | | -``` |
46 | | -And we instantiate the mapper either for JSON |
47 | | -```java |
48 | | -import com.fasterxml.jackson.databind.ObjectMapper; |
49 | | - |
50 | | -// ... |
51 | | - |
52 | | -ObjectMapper mapper = new ObjectMapper(); |
53 | | -mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
54 | | -mapper.registerModule(new JsonNullableModule()); |
55 | | -``` |
56 | | -or for XML |
57 | | -```java |
58 | | -import com.fasterxml.jackson.dataformat.xml.XmlMapper; |
59 | | - |
60 | | -// ... |
61 | | - |
62 | | -XmlMapper xmlMapper = new XmlMapper(); |
63 | | -xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
64 | | -xmlMapper.registerModule(new JsonNullableModule()); |
65 | | -``` |
66 | | -Then we can serialize |
67 | | -```java |
68 | | -assertEquals("{}", mapper.writeValueAsString(new Pet().name(JsonNullable.<String>undefined()))); |
69 | | -assertEquals("{\"name\":null}", mapper.writeValueAsString(new Pet().name(JsonNullable.<String>of(null)))); |
70 | | -assertEquals("{\"name\":\"Rex\"}", mapper.writeValueAsString(new Pet().name(JsonNullable.of("Rex")))); |
71 | | - |
72 | | -``` |
73 | | -and deserialize |
74 | | -```java |
75 | | -assertEquals(JsonNullable.of("Rex"), mapper.readValue("{\"name\":\"Rex\"}", Pet.class).name); |
76 | | -assertEquals(JsonNullable.<String>of(null), mapper.readValue("{\"name\":null}", Pet.class).name); |
77 | | -assertEquals(JsonNullable.<String>undefined(), mapper.readValue("{}", Pet.class).name); |
78 | | - |
79 | | -``` |
80 | | - |
81 | | -The `ValueExtractor` is registered automatically via Java Service loader mechanism. The example class above will validate as follows |
82 | | -```java |
83 | | -// instantiate javax.validation.Validator |
84 | | -Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); |
85 | | -Pet myPet = new Pet().name(JsonNullable.of("My Pet's really long name")); |
86 | | -Set<ConstraintViolation<Pet>> validationResult = validator.validate(myPet); |
87 | | -assertEquals(1, validationResult.size()); |
88 | | -``` |
89 | | - |
90 | | -## Limitations |
91 | | - |
92 | | -* Doesn't work when passed as a parameter to a `@JsonCreator` constructor (non present field gets deserialized as null instead of undefined). |
93 | | - But as JsonNullable is here to represent "optional" values, there shouldn't be a need to put it in a constructor. |
94 | | -* Doesn't work with `@JsonUnwrapped`. |
| 1 | +## This project is looking for maintainers. Please refer to the [announcement](https://github.com/OpenAPITools/jackson-databind-nullable/issues/71) for more information. |
| 2 | + |
| 3 | +# jackson-databind-nullable |
| 4 | + |
| 5 | +[](https://app.travis-ci.com/github/OpenAPITools/jackson-databind-nullable) |
| 6 | + |
| 7 | +This module provides a `JsonNullable` wrapper class and a Jackson module to serialize/deserialize it. |
| 8 | +The `JsonNullable` wrapper shall be used to wrap Java bean fields for which it is important to distinguish between an explicit `"null"` and the field not being present. |
| 9 | +A typical usage is when implementing [Json Merge Patch](https://tools.ietf.org/html/rfc7386) where an explicit `"null"` has the meaning "set this field to null / remove this field" whereas a non-present field has the meaning "don't change the value of this field". |
| 10 | + |
| 11 | +The module comes with an integrated `ValueExtractor` that automatically unwraps the contained value of the `JsonNullable` if used together with javax.validation Bean validation (JSR 380). |
| 12 | + |
| 13 | +Note: a lot of people use `Optional` to bring this behavior. |
| 14 | +Although it kinda works, it's not a good idea because: |
| 15 | +* Beans shouldn't have `Optional` fields. |
| 16 | + `Optional` was designed to be used only as method return value. |
| 17 | +* `Optional` should never be null. |
| 18 | + The goal of `Optional` is to wrap the `null` and prevent NPE so the code should be designed to never assign `null` to an `Optional`. |
| 19 | + A code invoking a method returning an Optional should be confident that this Optional is not null. |
| 20 | + |
| 21 | +## Installation |
| 22 | + |
| 23 | +The module is compatible with JDK8+ |
| 24 | +``` |
| 25 | +./mvnw clean install |
| 26 | +``` |
| 27 | + |
| 28 | +## Usage |
| 29 | + |
| 30 | +`JsonNullable` shall primarily be used in bean fields. |
| 31 | + |
| 32 | +If we have the following class |
| 33 | +```java |
| 34 | +public static class Pet { |
| 35 | + |
| 36 | + @Size(max = 10) |
| 37 | + public JsonNullable<String> name = JsonNullable.undefined(); |
| 38 | + |
| 39 | + public Pet name(JsonNullable<String> name) { |
| 40 | + this.name = name; |
| 41 | + return this; |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +``` |
| 46 | +And we instantiate the mapper either for JSON |
| 47 | +```java |
| 48 | +import com.fasterxml.jackson.databind.ObjectMapper; |
| 49 | + |
| 50 | +// ... |
| 51 | + |
| 52 | +ObjectMapper mapper = new ObjectMapper(); |
| 53 | +mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
| 54 | +mapper.registerModule(new JsonNullableModule()); |
| 55 | +``` |
| 56 | +or for XML |
| 57 | +```java |
| 58 | +import com.fasterxml.jackson.dataformat.xml.XmlMapper; |
| 59 | + |
| 60 | +// ... |
| 61 | + |
| 62 | +XmlMapper xmlMapper = new XmlMapper(); |
| 63 | +xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
| 64 | +xmlMapper.registerModule(new JsonNullableModule()); |
| 65 | +``` |
| 66 | +Then we can serialize |
| 67 | +```java |
| 68 | +assertEquals("{}", mapper.writeValueAsString(new Pet().name(JsonNullable.<String>undefined()))); |
| 69 | +assertEquals("{\"name\":null}", mapper.writeValueAsString(new Pet().name(JsonNullable.<String>of(null)))); |
| 70 | +assertEquals("{\"name\":\"Rex\"}", mapper.writeValueAsString(new Pet().name(JsonNullable.of("Rex")))); |
| 71 | + |
| 72 | +``` |
| 73 | +and deserialize |
| 74 | +```java |
| 75 | +assertEquals(JsonNullable.of("Rex"), mapper.readValue("{\"name\":\"Rex\"}", Pet.class).name); |
| 76 | +assertEquals(JsonNullable.<String>of(null), mapper.readValue("{\"name\":null}", Pet.class).name); |
| 77 | +assertEquals(JsonNullable.<String>undefined(), mapper.readValue("{}", Pet.class).name); |
| 78 | + |
| 79 | +``` |
| 80 | + |
| 81 | +The `ValueExtractor` is registered automatically via Java Service loader mechanism. The example class above will validate as follows |
| 82 | +```java |
| 83 | +// instantiate javax.validation.Validator |
| 84 | +Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); |
| 85 | +Pet myPet = new Pet().name(JsonNullable.of("My Pet's really long name")); |
| 86 | +Set<ConstraintViolation<Pet>> validationResult = validator.validate(myPet); |
| 87 | +assertEquals(1, validationResult.size()); |
| 88 | +``` |
| 89 | + |
| 90 | +## Limitations |
| 91 | + |
| 92 | +* Doesn't work when passed as a parameter to a `@JsonCreator` constructor (non present field gets deserialized as null instead of undefined). |
| 93 | + But as JsonNullable is here to represent "optional" values, there shouldn't be a need to put it in a constructor. |
| 94 | +* Doesn't work with `@JsonUnwrapped`. |
0 commit comments