재생 2 JSON 형식에서 누락된 속성에 대한 기본값
플레이 스칼라에는 다음 모델과 동등한 모델이 있습니다.
case class Foo(id:Int,value:String)
object Foo{
import play.api.libs.json.Json
implicit val fooFormats = Json.format[Foo]
}
다음 Foo 인스턴스의 경우
Foo(1, "foo")
다음 JSON 문서를 받을 수 있습니다.
{"id":1, "value": "foo"}
이 JSON은 유지되고 데이터스토어에서 읽힙니다.이제 요구 사항이 변경되어 Foo에 속성을 추가해야 합니다.속성 기본값은 다음과 같습니다.
case class Foo(id:String,value:String, status:String="pending")
JSON에 쓰는 것은 문제가 되지 않습니다.
{"id":1, "value": "foo", "status":"pending"}
그러나 여기서 읽으면 "/status" 경로가 누락되어 JsError가 발생합니다.
노이즈가 최소인 디폴트를 설정하려면 어떻게 해야 합니까?
(ps: 아래에 올릴 답변이 있습니다만, 그다지 만족하지 않고, 보다 나은 선택지를 상향 투표해 받아들이겠습니다.
2.6 이상 재생
@CanardMousant의 답변에 따르면 Play 2.6부터 Play-json 매크로가 개선되었으며, 역직렬화 시 디폴트 값을 플레이스 홀더로 사용하는 것을 포함한 여러 새로운 기능을 제안합니다.
implicit def jsonFormat = Json.using[Json.WithDefaultValues].format[Foo]
2.6 미만의 재생에서는 다음 옵션 중 하나를 사용하는 것이 좋습니다.
play-json-disply의
질문의 내용을 포함하여 플레이제이슨의 대부분의 단점에 대해 훨씬 더 나은 해결책을 찾았습니다.
이 질문의 특정 문제를 해결하기 위해 내부적으로 [play-json-extensions]를 사용합니다.
여기에는 시리얼라이저/디시리얼라이저에 누락된 기본값이 자동으로 포함되어 리팩터에 오류가 발생하기 쉬운 매크로가 포함되어 있습니다.
import play.json.extra.Jsonx
implicit def jsonFormat = Jsonx.formatCaseClass[Foo]
라이브러리에는 더 많은 정보가 있습니다: play-json-filename
Json 변압기
현재 솔루션은 JSON Transformer를 생성하여 매크로에서 생성된 Reads와 결합하는 것입니다.트랜스폼은 다음 방법으로 생성됩니다.
object JsonExtensions{
def withDefault[A](key:String, default:A)(implicit writes:Writes[A]) = __.json.update((__ \ key).json.copyFrom((__ \ key).json.pick orElse Reads.pure(Json.toJson(default))))
}
포맷 정의는 다음과 같습니다.
implicit val fooformats: Format[Foo] = new Format[Foo]{
import JsonExtensions._
val base = Json.format[Foo]
def reads(json: JsValue): JsResult[Foo] = base.compose(withDefault("status","bidon")).reads(json)
def writes(o: Foo): JsValue = base.writes(o)
}
그리고.
Json.parse("""{"id":"1", "value":"foo"}""").validate[Foo]
는 기본값을 적용한 Foo 인스턴스를 생성합니다.
제 의견에는 크게 두 가지 결함이 있습니다.
- 채무 불이행자 키 이름이 문자열에 있으므로 리팩터링에 의해 선택되지 않습니다.
- 기본값은 중복되며 한 위치에서 변경할 경우 다른 위치에서 수동으로 변경해야 합니다.
제가 찾은 가장 깨끗한 접근법은 "또는 순수"를 사용하는 것입니다.
...
((JsPath \ "notes").read[String] or Reads.pure("")) and
((JsPath \ "title").read[String] or Reads.pure("")) and
...
이는 기본값이 상수일 때 일반적인 암묵적인 방법으로 사용할 수 있습니다.다이내믹한 경우에는 Reads를 작성하는 메서드를 작성하여 범위 내에서 도입해야 합니다.
implicit val packageReader = makeJsonReads(jobId, url)
An alternative solution is to use 대체 해결책은 다음과 같습니다.formatNullable[T]
combined with 와 조합하여inmap
부에서InvariantFunctor
....
import play.api.libs.functional.syntax._
import play.api.libs.json._
implicit val fooFormats =
((__ \ "id").format[Int] ~
(__ \ "value").format[String] ~
(__ \ "status").formatNullable[String].inmap[String](_.getOrElse("pending"), Some(_))
)(Foo.apply, unlift(Foo.unapply))
이제 Play Json 2.6과 함께 제공되는 With Default Values를 사용하는 것이 공식 답변은 다음과 같습니다.
implicit def jsonFormat = Json.using[Json.WithDefaultValues].format[Foo]
편집:
동작은 play-json-extra 라이브러리와 다르다는 점에 주의해 주십시오.예를 들어, DateTime의 기본값을 가진 DateTime 매개 변수가 있는 경우.이제 프로세스의 시작 시간을 얻을 수 있습니다(아마 원하는 것은 아닐 것입니다). 반면 play-json-extra에서는 JSON에서 생성 시간을 얻을 수 있습니다.
모든 JSON 필드를 옵션(사용자 측에서는 옵션)으로 하고 싶지만, 내부적으로는 사용자가 특정 필드를 지정하지 않을 경우에 대비하여 모든 필드를 옵션 이외의 값으로 정확하게 정의해야 합니다.이것은 사용 사례와 비슷해야 합니다.
는 나 재 현 축 순 무 는 법 려 다있고 i consid'ruction고 wraps of방하짓 which마을단 the건 currently리m을히 const simplyeringFoo
선택적 주장으로:완전 옵션 인수:
case class Foo(id: Int, value: String, status: String)
object FooBuilder {
def apply(id: Option[Int], value: Option[String], status: Option[String]) = Foo(
id getOrElse 0,
value getOrElse "nothing",
status getOrElse "pending"
)
val fooReader: Reads[Foo] = (
(__ \ "id").readNullable[Int] and
(__ \ "value").readNullable[String] and
(__ \ "status").readNullable[String]
)(FooBuilder.apply _)
}
implicit val fooReader = FooBuilder.fooReader
val foo = Json.parse("""{"id": 1, "value": "foo"}""")
.validate[Foo]
.get // returns Foo(1, "foo", "pending")
Unfortunately, it requires writing explicit 불행히도, 그것은 명시적인 쓰기를 필요로 한다.Reads[Foo]
★★★★★★★★★★★★★★★★★」Writes[Foo]
마마피 하었 ?었? 었??? ???은 키가 이 "Default"인 입니다.null
이 포함되어 " ", " "가 반환됩니다.ValidationError
이러한 옵션의 JSON 구조를 네스트 하는 것은 문제가 되지 않습니다.예를 들어 다음과 같습니다.
case class Bar(id1: Int, id2: Int)
object BarBuilder {
def apply(id1: Option[Int], id2: Option[Int]) = Bar(
id1 getOrElse 0,
id2 getOrElse 0
)
val reader: Reads[Bar] = (
(__ \ "id1").readNullable[Int] and
(__ \ "id2").readNullable[Int]
)(BarBuilder.apply _)
val writer: Writes[Bar] = (
(__ \ "id1").write[Int] and
(__ \ "id2").write[Int]
)(unlift(Bar.unapply))
}
case class Foo(id: Int, value: String, status: String, bar: Bar)
object FooBuilder {
implicit val barReader = BarBuilder.reader
implicit val barWriter = BarBuilder.writer
def apply(id: Option[Int], value: Option[String], status: Option[String], bar: Option[Bar]) = Foo(
id getOrElse 0,
value getOrElse "nothing",
status getOrElse "pending",
bar getOrElse BarBuilder.apply(None, None)
)
val reader: Reads[Foo] = (
(__ \ "id").readNullable[Int] and
(__ \ "value").readNullable[String] and
(__ \ "status").readNullable[String] and
(__ \ "bar").readNullable[Bar]
)(FooBuilder.apply _)
val writer: Writes[Foo] = (
(__ \ "id").write[Int] and
(__ \ "value").write[String] and
(__ \ "status").write[String] and
(__ \ "bar").write[Bar]
)(unlift(Foo.unapply))
}
" 요건을 만, 를 "최소한의 노이즈"로 하는 것은 요?Option[String]
case class Foo(id:String,value:String, status:Option[String] = Some("pending"))
를 때Foo
오래된 고객으로부터는None
에 제가 ) getOrElse
를 참조해 주세요.
마음에 안 들면 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아BackwardsCompatibleFoo
:
case class BackwardsCompatibleFoo(id:String,value:String, status:Option[String] = "pending")
case class Foo(id:String,value:String, status: String = "pending")
그리고 나서 저걸 다른 걸로 바꿔서Foo
코드에서 이런 종류의 데이터 체조를 다루지 않아도 되기 때문에 더 많은 작업을 할 수 있습니다.
상태를 옵션으로 정의할 수 있습니다.
case class Foo(id:String, value:String, status: Option[String])
다음과 같이 JsPath를 사용합니다.
(JsPath \ "gender").readNullable[String]
언급URL : https://stackoverflow.com/questions/20616677/defaults-for-missing-properties-in-play-2-json-formats
'programing' 카테고리의 다른 글
다른 TypeScript 파일을 Import하려면 어떻게 해야 하나요? (0) | 2023.02.25 |
---|---|
angularjs multi-step/wizard 폼을 한 페이지/url로 하는 방법 (0) | 2023.02.25 |
JUnit의 @TestMethodOrder 주석이 작동하지 않습니다. (0) | 2023.02.25 |
Wordpress 테마 업그레이드가 부모 테마 기능을 변경하지 않도록 하려면 어떻게 해야 합니까?php (0) | 2023.02.25 |
Oracle에서 임시 테이블스페이스를 축소하는 방법 (0) | 2023.02.25 |