我试图使用Jackson将类值写入JSON,其中包含Optional作为字段:
public class Test {
Optional<String> field = Optional.of("hello, world!");
public Optional<String> getField() {
return field;
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new Test()));
}
}
执行时,此类生成以下输出:
{"field":{"present":true}}
我理解当前/不存在的字段被包含在内并且可以在读取JSON数据时解决它,但是我无法解决可选的实际内容永远不会写入输出的事实。 :(
除了根本不使用ObjectMapper之外,这里有任何变通方法吗?
答案 0 :(得分:52)
您可以使用jackson-datatype-jdk8,其描述为:
支持新的JDK8特定类型,例如Optional
为了做到这一点:
com.fasterxml.jackson.datatype:jackson-datatype-jdk8
添加为依赖项objectMapper.registerModule(new Jdk8Module());
答案 1 :(得分:13)
Optional
类有一个value
字段,但没有标准的getter / setter。默认情况下,杰克逊寻找getter / setter来查找类属性。
您可以添加自定义Mixin以将字段标识为属性
final class OptionalMixin {
private Mixin(){}
@JsonProperty
private Object value;
}
并将其注册到您的ObjectMapper
。
ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(Optional.class, OptionalMixin.class);
您现在可以序列化您的对象。
System.out.println(mapper.writeValueAsString(new Test()));
将打印
{"field":{"value":"hello, world!","present":true}}
还要考虑jackson-datatype-guava
。对于Guava类型,杰克逊Module
实现了Optional
。它可能比我上面所示的更完整。
答案 2 :(得分:9)
与@ Manikandan的回答类似,但是将@JsonProperty
添加到私有字段而不是getter,这样您就不会在公共API上公开您的工作。
public class Test {
@JsonProperty("field")
private String field;
@JsonIgnore
public Optional<String> getField() {
return Optional.of(field); // or Optional.ofNullable(field);
}
}
答案 3 :(得分:5)
您只需注册模块Jdk8Module
即可。然后它会将Optional<T>
序列化为T
(如果存在)或null
。
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module());
让我们稍微修改一下Test
类,这样我们就可以测试Optional.empty()
值。这与序列化时的原始Test
类相似,因为对象映射器正在查找getter(因为该字段为private
)。但是,使用原始的Test
类也可以。
class Test {
private final String field;
public Test(String field) {
this.field = field;
}
public Optional<String> getField() {
return Optional.ofNullable(field);
}
}
然后在我们的主要课程中:
Test testFieldNull = new Test(null);
Test testFieldNotNull = new Test("foo");
// output: {"field":null}
System.out.println(objectMapper.writeValueAsString(testFieldNull));
// output: {"field":"foo"}
System.out.println(objectMapper.writeValueAsString(testFieldNotNull));
答案 4 :(得分:3)
定义新的getter,它将返回String而不是Optional。
public class Test {
Optional<String> field = Optional.of("hello, world!");
@JsonIgnore
public Optional<String> getField() {
return field;
}
@JsonProperty("field")
public String getFieldName() {
return field.orElse(null);
}
}
答案 5 :(得分:3)
尝试将选项传入@JsonInclude
注释
例如,如果您不希望在值为field
时显示null
。 您可能需要使用Jackson-Modules&gt; 2.8.5 。
import com.fasterxml.jackson.annotation.JsonInclude;
public class Test {
@JsonInclude(JsonInclude.Include.NON_NULL)
Optional<String> field;
}
答案 6 :(得分:1)
如果您使用的是最新版本的Spring-boot,那么您可以通过在pom文件中添加以下依赖项来实现此目的
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
自动连接JacksonObjectMapper。
@Autowired
private ObjectMapper jacksonObjectMapper;
然后使用上面的Spring容器的映射器实例将Object转换为String
jacksonObjectMapper.writeValueAsString(user);
如果在类路径中检测到一些众所周知的Jackson模块,则会自动注册:
- jackson-datatype-jdk7:Java 7类型,如java.nio.file.Path(自4.2.1版本起)
- jackson-datatype-joda:Joda-Time types
- jackson-datatype-jsr310:Java 8 Date&amp;时间API数据类型
- jackson-datatype-jdk8:其他Java 8类型,如Optional(自4.2.0发布)