我正在解析输入JSON。对于一个领域,有三种可能性:
实现了不同的行为:对于JSON中缺少的值,将默认值插入到数据库中;对于JSON中的空值,将空值插入数据库。
我考虑过Optional
对此进行建模:
public class Data {
private Optional<String> field;
}
以下哪两项选项最有意义?
field
为空,则JSON中不存在该字段。如果field
是Optional.empty,则该字段在JSON中为null
。field
为空,则JSON中的字段为null
。如果field
是Optional.empty,则JSON中不存在该字段。FWIW,我使用Jackson和模块jackson-datatype-jdk8来解析输入JSON。
答案 0 :(得分:5)
我认为你不应该在这种情况下使用Optional
。正如@dkatzel在他的回答中提到的那样,它意味着比作为一个领域更多地被用作API返回值。
尽管有这样的学术讨论,但只需将Data
类中的字段初始化为默认值即可完成您想要的任务:
public class Data {
private String field = DEFAULT_VALUE;
}
然后让杰克逊做其余的事。
根据OP的评论编辑:
当您的JSON为null
提供field
值时,杰克逊会将其设置为null
,以及将存储在数据库中的内容。
当您的JSON不包含该字段时,DEFAULT_VALUE
将自动加载到您的Data
实例中。
当你的JSON确实包含field
的值时,杰克逊会设置它,并且该值将到达数据库。
编辑2,考虑到OP要求在解析JSON之后找出field
是否填写,设置为null
或输入JSON中是否缺席输入:强>
如果在解析输入JSON 之后,您需要知道field
是填写,设置为null
还是不存在,那么请考虑这个例子,这显示了我采取的方法:
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);
}
}
我已使用private static
属性来保存您的Data
默认值和3种方法来查询任何字段状态(默认值,null或设置)。为了确定要查询的字段,这些方法会收到Function<Data, Object>
,它们被赋予Data
个实例并返回应该是所需字段的Object
。 (如果您停下来思考它,可以将getter视为将实例作为输入并返回实例的特定字段的函数。)
所以稍后,当你需要知道某个字段如何到达你的JSON输入时,只需使用这3个查询方法就可以找到:
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
答案 1 :(得分:2)
我会说第一个选项具有最大的语义意义。它还可能允许更容易的计算。
如果java中的字段为null,则表示缺少与第一个选项匹配的值。
我建议您将这些字段存储在哈希映射中,其中键是JSON字段名称,值是JSON字段的值。我还建议你不要在这里使用一个可选项(因为它可以添加一个不必要的复杂层),而是在hashmap中使用null或非null对象。
HashMap<String, Value> jsonFields = new HashMap<String, Value>();
boolean hasField1 = false;
Value field1Value = null;
if(jsonFields.contains("field1"){ // It is present in the JSON file
field1Value = jsonFields.get("field1"); // "null" here would mean that the JSON field was set to "null"
hasField1 = true;
}
答案 2 :(得分:1)
第二种选择对我来说更有意义。 null
表示null
,空表示不存在。
但是,Optional
不应该真正用作字段。 It's supposed to be used as an API return value
您是否可以将数据存储在允许空值的Map
中?如果地图中没有关键字(您的字段),请返回Optional.empty
?
答案 3 :(得分:0)
既不?我会用@DefaultValue()注释我的POJO字段。然后,您的可能性是在JSON中指定的空值或非空值,或者如果从JSON中省略该字段,则为默认值。然后你就可以在没有任何特殊的每场分析的情况下坚持POJO。
答案 4 :(得分:0)
如果您正在处理Object
而不是String
,这是一个我觉得优雅的解决方案:
Optional.empty();
Optional.of(value)
Optional.of(specialValue)
其中specialValue
是一个静态单例,您可以轻松地进行测试,例如:ObjectUtils.NULL
(来自 commons.lang )。
然后您可以轻松测试您的选项:
if (optional.isPresent()) {
if (ObjectUtils.NULL.equals(optional.get())) {
// value is there and null
} else {
// value is there and not null
}
} else {
// value is not there
}