Jacksonを使用して、フィールドとしてOptionalを持つJSONにクラス値を書き込もうとしていました。
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}}
Present/not presentフィールドが含まれていることを理解しており、JSONデータを読み取るときに回避できますが、オプションの実際のコンテンツが出力に書き込まれないという事実を回避することはできません。 :(
ObjectMapperをまったく使用しないことを除いて、ここで回避策はありますか?
jackson-datatype-jdk8 を使用できます。
オプションなど、新しいJDK8固有のタイプのサポート
これを行うためには:
com.fasterxml.jackson.datatype:jackson-datatype-jdk8
_を依存関係として追加しますobjectMapper.registerModule(new Jdk8Module());
Optional
クラスにはvalue
フィールドがありますが、標準のゲッター/セッターはありません。デフォルトでは、Jacksonはクラスプロパティを見つけるために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
。 Module
を含むGuava型のJackson Optional
実装があります。おそらく、上記で示したものよりも完全なものです。
@Manikandanの回答に似ていますが、@JsonProperty
ゲッターではなくプライベートフィールドに追加して、パブリックAPIでの作業を公開しないようにします。
public class Test {
@JsonProperty("field")
private String field;
@JsonIgnore
public Optional<String> getField() {
return Optional.of(field); // or Optional.ofNullable(field);
}
}
モジュール_Jdk8Module
_を登録するだけです。次に、_Optional<T>
_が存在する場合はT
として、そうでない場合はnull
としてシリアル化します。
_ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module());
_
Optional.empty()
値をテストできるように、Test
クラスを少し変更してみましょう。これは、オブジェクトマッパーがゲッターを探しているため(フィールドがTest
であるため)、シリアル化されたときの元の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));
_
OptionalではなくStringを返す新しいゲッターを定義します。
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);
}
}
オプションを@JsonInclude
アノテーションに渡してみてください。
たとえば、値がfield
のときにnull
を表示したくない場合。 2.8.5以上のJackson-Modulesを使用する必要がある場合があります。
import com.fasterxml.jackson.annotation.JsonInclude;
public class Test {
@JsonInclude(JsonInclude.Include.NON_NULL)
Optional<String> field;
}
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-datatype-jdk7:Java Java.nio.file.Pathのような7タイプ(4.2.1リリース時点)
- jackson-datatype-joda:Joda-Timeタイプ
- jackson-datatype-jsr310:Java 8 Date&Time APIデータ型
- jackson-datatype-jdk8:other Java Optionalなどの8つのタイプ(4.2.0リリース以降)