{"id":20751173,"url":"https://github.com/openapitools/jackson-databind-nullable","last_synced_at":"2026-02-05T09:08:33.074Z","repository":{"id":39787951,"uuid":"155292140","full_name":"OpenAPITools/jackson-databind-nullable","owner":"OpenAPITools","description":"JsonNullable wrapper class and Jackson module to support meaningful null values","archived":false,"fork":false,"pushed_at":"2023-09-28T16:57:48.000Z","size":113,"stargazers_count":110,"open_issues_count":14,"forks_count":33,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-02T06:21:29.414Z","etag":null,"topics":["jackson","jackson-databind","nullable","optional"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenAPITools.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-29T22:56:00.000Z","updated_at":"2025-03-18T14:20:50.000Z","dependencies_parsed_at":"2024-11-17T23:17:20.480Z","dependency_job_id":null,"html_url":"https://github.com/OpenAPITools/jackson-databind-nullable","commit_stats":{"total_commits":48,"total_committers":18,"mean_commits":"2.6666666666666665","dds":0.75,"last_synced_commit":"8861f83253b2373288772a55f8fb3938fa4824b9"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenAPITools%2Fjackson-databind-nullable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenAPITools%2Fjackson-databind-nullable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenAPITools%2Fjackson-databind-nullable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenAPITools%2Fjackson-databind-nullable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenAPITools","download_url":"https://codeload.github.com/OpenAPITools/jackson-databind-nullable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247999859,"owners_count":21031046,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jackson","jackson-databind","nullable","optional"],"created_at":"2024-11-17T08:31:30.074Z","updated_at":"2026-02-05T09:08:33.068Z","avatar_url":"https://github.com/OpenAPITools.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## This project is looking for maintainers. Please refer to the [announcement](https://github.com/OpenAPITools/jackson-databind-nullable/issues/71) for more information.\r\n\r\n# jackson-databind-nullable\r\n\r\n[![Build Status](https://api.travis-ci.com/OpenAPITools/jackson-databind-nullable.svg?branch=master\u0026status=passed)](https://app.travis-ci.com/github/OpenAPITools/jackson-databind-nullable)\r\n\r\nThis module provides a `JsonNullable` wrapper class and a Jackson module to serialize/deserialize it.\r\nThe `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.\r\nA 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\".\r\n\r\nThe 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). \r\n\r\nNote: a lot of people use `Optional` to bring this behavior.\r\nAlthough it kinda works, it's not a good idea because:\r\n* Beans shouldn't have `Optional` fields.\r\n  `Optional` was designed to be used only as method return value.\r\n* `Optional` should never be null.\r\n  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`.\r\n  A code invoking a method returning an Optional should be confident that this Optional is not null.\r\n  \r\n## Installation\r\n\r\nThe module is compatible with JDK8+\r\n```\r\n./mvnw clean install\r\n```\r\n\r\n## Usage\r\n\r\n`JsonNullable` shall primarily be used in bean fields.\r\n\r\nIf we have the following class\r\n```java\r\npublic static class Pet {\r\n    \r\n    @Size(max = 10)   \r\n    public JsonNullable\u003cString\u003e name = JsonNullable.undefined();\r\n    \r\n    public Pet name(JsonNullable\u003cString\u003e name) {\r\n        this.name = name;\r\n        return this;\r\n    }\r\n}\r\n\r\n```\r\nAnd we instantiate the mapper either for JSON\r\n```java\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\n\r\n// ...\r\n\r\nObjectMapper mapper = new ObjectMapper();\r\nmapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);\r\nmapper.registerModule(new JsonNullableModule());\r\n```\r\nor for XML\r\n```java\r\nimport com.fasterxml.jackson.dataformat.xml.XmlMapper;\r\n\r\n// ...\r\n\r\nXmlMapper xmlMapper = new XmlMapper();\r\nxmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);\r\nxmlMapper.registerModule(new JsonNullableModule());\r\n```\r\nThen we can serialize\r\n```java\r\nassertEquals(\"{}\", mapper.writeValueAsString(new Pet().name(JsonNullable.\u003cString\u003eundefined())));\r\nassertEquals(\"{\\\"name\\\":null}\", mapper.writeValueAsString(new Pet().name(JsonNullable.\u003cString\u003eof(null))));\r\nassertEquals(\"{\\\"name\\\":\\\"Rex\\\"}\", mapper.writeValueAsString(new Pet().name(JsonNullable.of(\"Rex\"))));\r\n\r\n```\r\nand deserialize\r\n```java\r\nassertEquals(JsonNullable.of(\"Rex\"), mapper.readValue(\"{\\\"name\\\":\\\"Rex\\\"}\", Pet.class).name);\r\nassertEquals(JsonNullable.\u003cString\u003eof(null), mapper.readValue(\"{\\\"name\\\":null}\", Pet.class).name);\r\nassertEquals(JsonNullable.\u003cString\u003eundefined(), mapper.readValue(\"{}\", Pet.class).name);\r\n\r\n```\r\n\r\nThe `ValueExtractor` is registered automatically via Java Service loader mechanism. The example class above will validate as follows\r\n```java\r\n// instantiate javax.validation.Validator\r\nValidator validator = Validation.buildDefaultValidatorFactory().getValidator();\r\nPet myPet = new Pet().name(JsonNullable.of(\"My Pet's really long name\"));\r\nSet\u003cConstraintViolation\u003cPet\u003e\u003e validationResult = validator.validate(myPet);\r\nassertEquals(1, validationResult.size());\r\n```\r\n\r\n## Limitations\r\n\r\n* Doesn't work when passed as a parameter to a `@JsonCreator` constructor (non present field gets deserialized as null instead of undefined).\r\n  But as JsonNullable is here to represent \"optional\" values, there shouldn't be a need to put it in a constructor.\r\n* Doesn't work with `@JsonUnwrapped`.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenapitools%2Fjackson-databind-nullable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenapitools%2Fjackson-databind-nullable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenapitools%2Fjackson-databind-nullable/lists"}