[Jackson] json 変換時に isXXX プロパティを無視したい
Java オブジェクトで、フィールド名が isXXX
かつ ゲッター名が isXXX
となっているフィールドを、シリアライズ対象から外す方法。lombok の @Accessors(fluent = true)
と @JsonIgnore
の組み合わせだとうまくいかなかった。
やりたいこと
Student オブジェクトを 下記の形で json 変換させること。
json
{"id":999,"grade":3,"className":"もも","name":"Jackson"}
Student オブジェクト
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private int grade;
@Column(nullable = false)
private String className;
@Column(nullable = false)
private String name;
// シリアライズ対象外
@Column(nullable = false)
@Accessors(fluent = true)
private Boolean isActive;
@JsonIgnore
@Column(nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private ZonedDateTime created;
@JsonIgnore
@Column(nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
private ZonedDateTime updated;
}
isActive
は、 lombok の @Accessors(fluent = true)
を使って isGetter
と isSetter
を自動生成している。
ダメな例
シリアライズ対象外のフィールドに @JsonIgnore
をつける。
Student オブジェクト
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private int grade;
@Column(nullable = false)
private String className;
@Column(nullable = false)
private String name;
@Column(nullable = false)
@Accessors(fluent = true)
@JsonIgnore // ← ここに付与した
private Boolean isActive;
@JsonIgnore
@Column(nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private ZonedDateTime created;
@JsonIgnore
@Column(nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
private ZonedDateTime updated;
}
結果
json 変換して出力してみる。
void convertObjectToJson() throws JsonProcessingException {
Student object = new Student();
object.setId(999L);
object.setGrade(3);
object.setClassName("もも");
object.setName("Jackson");
object.isActive(true);
object.setCreated(ZonedDateTime.now());
object.setUpdated(ZonedDateTime.now());
String jsonStr = objectMapper.writeValueAsString(object);
System.out.println("JSON : " + jsonStr);
}
ΣΣ(゚д゚lll) エッ?
active
というプロパティが含まれる。
JSON : {"id":999,"grade":3,"className":"もも","name":"Jackson","active":true}
うまくいく例
@JsonIgnore
ではなく
@JsonAutoDetect
を使う。
isGetterVisibility
オプションがあるので、Visibility.NONE
に指定する。
これを付与することで、Jackson は isGetter
を検出しなくなる。
注意
@JsonAutoDetect
はクラスに付与するものなので、全ての isGetter
を検出しなくなる。
Student オブジェクト
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
// ↓これを付与した
@JsonAutoDetect(isGetterVisibility = JsonAutoDetect.Visibility.NONE)
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private int grade;
@Column(nullable = false)
private String className;
@Column(nullable = false)
private String name;
@Column(nullable = false)
@Accessors(fluent = true)
private Boolean isActive;
@JsonIgnore
@Column(nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private ZonedDateTime created;
@JsonIgnore
@Column(nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
private ZonedDateTime updated;
}
結果
変換された json を出力。
JSON : {"id":999,"grade":3,"className":"もも","name":"Jackson"}
なぜ?
明確な原因は分からなかったが、おそらく以下ではないかと思った。
ゲッター名が is
から始まると、 is
を取り除いた部分をプロパティ名として返すようだ。
https://github.com/FasterXML/jackson-module-kotlin/issues/80
おそらくこれが原因で active
が json に含まれた。 @JsonIgnore
は isActive
に付いているため、 active
はシリアライズの除外対象に含まれないのではないかと考える。
is から始まらないゲッターの場合
では、 canXXX
など、isGetter ではないゲッターだとどう動くのか試してみた。
Student オブジェクトに @JsonAutoDetect
なしで、↓を追加した。
@Accessors(fluent = true)
private Boolean canActive;
出力された json
JSON : {"id":999,"grade":3,"className":"もも","name":"Jackson","active":true}
ゲッター名の始まりが get
でも is
でもない場合、Jackson はプロパティを検出しないようだ。
次に @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
を付与して、フィールドを検出可能にしてみた。
出力された json
JSON : {"id":999,"grade":3,"className":"もも","name":"Jackson","isActive":true,"canActive":true,"active":true}
canActive
は検出された。
isActive
と active
は両方 json 出力されているので、ゲッター名が is
から始まる場合には、フィールド名とゲッター名が別物として検出しているようだ。