要するにEntityを元にJsonSchemaを生成するConverterがあるってことですね。
普通にJsonSchemaを出力してみると
class Text {
@Column
var title: String = ""
@Column
var page: Int = 0
@Column
@Enumerated(EnumType.STRING)
var category: CategoryType = CategoryType.Memo
enum class CategoryType {
Memo,
Article,
Log,
Code
}
}
上のEntityがあったとして、
RequestHeader -> Accept: application/schema+json HttpRequest.GET -> /profile/texts
となげると
{
title: "Text",
type: "object",
properties: {
title: {
title: "Title",
type: "string"
},
page: {
title: "Page",
type: "integer"
},
category: {
title: "Category",
type: "string",
enum: [
"Memo",
"Article",
"Log",
"Code"
]
}
}
}
といったものが返ってきます。(一部不要な部分は削ってます)
このEntityの一部にJsonIgnoreを指定してみます
class Text {
@Column
var title: String = ""
@JsonIgnore
@Column
var page: Int = 0
@Column
@Enumerated(EnumType.STRING)
var category: CategoryType = CategoryType.Memo
enum class CategoryType {
Memo,
Article,
@JsonIgnore Log,
@JsonIgnore Code
}
}
同じリクエストをなげた場合、返ってくるのは、
{
title: "Text",
type: "object",
properties: {
title: {
title: "Title",
type: "string"
},
category: {
title: "Category",
type: "string",
enum: [
"Memo",
"Article",
"Log",
"Code"
]
}
}
}
となります。
pageプロパティは期待どおり出力されなくなりましたが、categoryプロパティのenum値は全て出力されてしまっています。
これをどうにかしたいのが、本題。
enum値のJsonSchemaはJsonSchema.EnumPropertyというクラスで実装されています。
標準のconverter相当の作り方をした場合
fun buildSchema(clazz: Class<Any>): JsonSchema.JsonSchemaProperty? {
return when {
clazz.isEnum -> buildEnumSchema(clazz)
else -> null
}
}
fun buildEnumSchema(clazz: Class<Any>): JsonSchema.JsonSchemaProperty {
return JsonSchema.EnumProperty("name", "title", clazz, "description", false)
}
少し雑ですが、要するに、Classを渡して生成しています。
Classを渡した場合のコンストラクタは、
* 全Enumメンバーを取得
* toStringしてList化
* 別のコンストラクタへ渡す
という処理になっているので、JsonIgnore分を削ったListを用意して、その「別のコンストラクタ」をダイレクトに呼んであげれば良さそうです。
JsonIgnoreなメンバを省いたEnumPropertyを作る場合
上の処理を書き換えます。
fun buildEnumSchema(clazz: Class<Any>): JsonSchema.JsonSchemaProperty {
clazz as Class<Enum<*>>
return JsonSchema.EnumProperty("name", "title",
clazz.enumConstants.filter {
clazz.fields[it.ordinal]
.getAnnotationsByType(JsonIgnore::class.java)
.isEmpty()
}.map { it.toString() }.toList(),
"description", false)
}
これをConverterに組み込んで、JsonSchema取得のリクエストをなげてみると、
{
title: "Text",
type: "object",
properties: {
title: {
title: "Title",
type: "string"
},
category: {
title: "Category",
type: "string",
enum: [
"Memo",
"Article"
]
}
}
}
categoryのenumの値もフィルタリングされました。
やっていることは単純で、enumメンバのうち、JsonIgnoreが貼られているものを除外してtoStringしたものを渡してEnumPropertyを作っているだけです。
ポイントは、ClassがEnumだと後続処理に教える為に未代入でキャストしているのと、enumConstantsを再度、自身のClassからFieldとして取得してAnnotationを見れるようにするところでしょうか。
最新のSDRならもしかしたら、わざわざやらなくてもいけるのかな?とか思いますが、まあ、メモ程度ってことで。
いじょ