I think you should not use Optional for this scenario. As @dkatzel noted in his answer, this meant that it was used as an API return value more than as a field.
Despite this academic discussion, you can accomplish what you want by simply initializing the fields in the Data class with default values:
public class Data { private String field = DEFAULT_VALUE; }
And then let Jackson do the rest.
EDIT as per OP comment:
When your JSON is null for field , Jackson will set it to null , and that will be stored in the database.
If your JSON does not contain a field, DEFAULT_VALUE will be automatically loaded into your Data instance.
And when your JSON really contains a value for field , Jackson will set it, and that value will reach the database.
EDIT 2, given the OP requirement, to find out if a field populated, set to null or not in the input JSON after parsing the JSON input:
If, after parsing the input JSON, you need to know if the field filled, set to null or absent, then consider this example, which shows the approach that I will take:
public class Data { private String field1 = "hello"; private Integer field2 = 10; private Double field3 = 3.75; private static final Data DEFAULTS = new Data(); // defaults will be kept here public String getField1() { return this.field1; } public void setField1(String field1) { this.field1 = field1; } public Integer getField2() { return this.field2; } public void setField2(Integer field2) { this.field2 = field2; } public Double getField3() { return this.field3; } public void setField3(Double field3) { this.field3 = field3; } @Override public String toString() { return "Data [field1=" + this.field1 + ", field2=" + this.field2 + ", field3=" + this.field3 + "]"; } public boolean isDefault(Function<Data, Object> getter) { Object defaultProperty = getter.apply(DEFAULTS); Object actualProperty = getter.apply(this); return defaultProperty != null // needed to support fields with no default value && defaultProperty.equals(actualProperty); } public boolean isNull(Function<Data, Object> getter) { return getter.apply(this) == null; } public boolean isSet(Function<Data, Object> getter) { return !this.isNull(getter) && !this.isDefault(getter); } }
Here I used the private static attribute to store your default Data values ββand 3 methods to query any field state (default, null or set). To determine which field to request, these methods get Function<Data, Object> , which are assigned an instance of Data and returns an Object , which should be desired. (If you stop thinking about it, then getters can be thought of as functions that take an instance as input and return a specific instance field.)
So, when you need to know how a specific field arrived in your JSON input, just use these 3 request methods to find out:
ObjectMapper m = new ObjectMapper(); String json = "{\"field1\":null,\"field2\":20}"; Data data = m.readValue(json, Data.class); System.out.println(data); // Data [field1=null, field2=20, field3=3.75] System.out.println("field1 default ? " + data.isDefault(Data::getField1)); // false System.out.println("field1 null ? " + data.isNull(Data::getField1)); // true System.out.println("field1 set ? " + data.isSet(Data::getField1)); // false System.out.println("field2 default ? " + data.isDefault(Data::getField2)); // false System.out.println("field2 null ? " + data.isNull(Data::getField2)); // false System.out.println("field2 set ? " + data.isSet(Data::getField2)); // true System.out.println("field3 default ? " + data.isDefault(Data::getField3)); // true System.out.println("field3 null ? " + data.isNull(Data::getField3)); // false System.out.println("field3 set ? " + data.isSet(Data::getField3)); // false