>

제 질문은 조금 까다 롭습니다. 다음과 같은 사례 클래스가 있습니다.

case class Foo(
    id: String,
    name: String,
    field1: Boolean,
    field2: Boolean,
    field3: Boolean,
    field4: Boolean
)

그러나 두 가지 유형의 입력이 있는데, 하나는 케이스 클래스 Foo 에 완벽하게 적합합니다. . 다른 하나는 field3 에 대한 값이 누락되었습니다.  그리고 field4 처럼 보이는 {id: "Test", name: "Test", field1: true, field2: true} , Decoder[Foo] 를 만들고 싶습니다  입력에 field3 가 누락 된 경우 두 경우 모두 작동합니다.  그리고 field4 기본값 false 를 설정하십시오. . 가능합니까?

예 :

입력 {id: "Test", name: "Test", field1: true, field2: true} 에 대한

(1) ,로 해독하고 싶습니다

Foo("Test, "Test", true, true, false, flase)

입력 {id: "Test", name: "Test", field1: true, field2: true, field3: true, field4: false} 에 대한

(2) ,로 해독하고 싶습니다

Foo("Test, "Test", true, true, true, flase)

가장 좋은 해결책은 field3 를 설정하는 것입니다.  그리고 field4   Option[Boolean] 로 그러나 원래 디자인에 따라 수많은 코드가 구현되었으며 데이터 모델을 변경하면 많은 코드 변경이 발생합니다. 따라서 make shift 솔루션이 있는지 확인하고 싶습니다.

정말 감사합니다!


  • 답변 # 1

    여러 가지 방법이 있습니다. 난 당신이 처음부터 코덱을 구축하지 않을 것이라고 가정하고 이미 주위에있는 것에서 얻을 수있는 것을 사용합니다.

    기본 매개 변수 + 일반 확장 프로그램

    와이즈 비즈가있다  패키지-자동 파생 코덱에 대한 일부 사용자 정의를 허용합니다. 특히 기본 매개 변수를 대체 값으로 사용할 수 있습니다.

    단점은 컴파일 속도가 느리고 암시 적 circe-generic-extras 가 필요하다는 것입니다  범위 내에서.

    <시간>

    먼저 암시 적 구성이 필요합니다 :

    io.circe.generic.extras.Configuration
    
    

    이것은 일반적으로 프로젝트의 일부 일반적인 util 패키지에 들어가므로 이러한 구성을 쉽게 재사용 할 수 있습니다.

    그런 다음 object Configs { implicit val useDefaultValues = Configuration.default.withDefaults } 를 사용합니다.  수업에서 매크로 주석을 사용하거나 @ConfiguredJsonCodec 를 사용하십시오.  동반자 :

    extras.semiauto.deriveConfiguredCodec
    
    

    구성 가져 오기를 잊지 않고 동시에 여러 구성을 가져 오지 않는 것이 중요합니다. 그렇지 않으면

    와 같은 도움이되지 않는 오류가 발생합니다
    import Configs.useDefaultValues
    @ConfiguredJsonCodec
    case class Foo(
        id: String,
        name: String,
        field1: Boolean,
        field2: Boolean,
        field3: Boolean = false,
        field4: Boolean = false
    )
    
    

    could not find Lazy implicit value of type io.circe.generic.extras.codec.ConfiguredAsObjectCodec[Foo] 를 해독하기에 충분합니다  이제 기본값이있는 필드가없는 경우 :

    Foo
    
    

    여기서 독립형 스 캐티

    폴백 디코더

    아이디어는 다음과 같습니다 : 구식 데이터 형식을 설명하는 별도의 케이스 클래스를 갖고, 구식 데이터와 새 형식 모두로 데이터 구문 분석을 시도하는 디코더를 빌드하십시오. Circe 디코더에는 println { io.circe.parser.decode[Foo](""" { "id": "someid", "name": "Gordon Freeman", "field1": false, "field2": true } """) } 가 있습니다  그런 종류의 시도를위한 조합기입니다.

    <시간>

    이제 먼저 "오래된"데이터 형식과이를 새로운 형식으로 업그레이드하는 방법에 대해 설명합니다.

    or
    
    

    새로운 형식에서는 코덱을 수동으로 연결해야하므로 매크로 주석을 사용할 수 없습니다. 그래도 @JsonCodec(decodeOnly = true) case class LegacyFoo( id: String, name: String, field1: Boolean, field2: Boolean, ) { def upgrade: Foo = Foo(id, name, field1, field2, false, false) } 를 사용할 수 있습니다  모든 필드를 직접 나열하지 않아도되는 방법 :

    generic.semiauto.deriveXXX
    
    

    이것은 또한 동일한 페이로드에 대해 "작동합니다":

    case class Foo(
        id: String,
        name: String,
        field1: Boolean,
        field2: Boolean,
        field3: Boolean,
        field4: Boolean
    )
    object Foo {
      implicit val encoder: Encoder[Foo] = semiauto.deriveEncoder[Foo]
      implicit val decoder: Decoder[Foo] =
        semiauto.deriveDecoder[Foo] or Decoder[LegacyFoo].map(_.upgrade)
    }
    
    

    여기 스 캐티.

    <시간> 첫 번째 방법은 추가 라이브러리가 필요하지만 상용구가 적습니다. 또한 발신자가 공급할 수도 있습니다 (예 : 와이즈 비즈  그러나 println { io.circe.parser.decode[Foo](""" { "id": "someid", "name": "Gordon Freeman", "field1": false, "field2": true } """) } 는  -두 번째 접근법에서 field4 의 가치  해당 시나리오에서는 완전히 삭제됩니다.

    두 번째는 "기타 값으로 추가 된 필드"보다 더 복잡한 변경을 처리 할 수 ​​있습니다. 예를 들어 여러 다른 값을 계산하거나 컬렉션 내부의 구조를 변경하거나 나중에 필요할 경우 더 많은 버전을 가질 수 있습니다.

    아, 당신은 또한 field3 를 넣을 수 있습니다   field4 로 추가 공개 데이터 유형을 노출하지 않으려면 비공개로 설정하십시오.

  • 답변 # 2

    이에 대해 매개 변수 기본값이 작동하지 않습니까?

    LegacyFoo
    
    
    object Foo

  • 이전 python - 다음 열에서 팬더 값을 선택하는 방법
  • 다음 google apps script - 파일 다운로드 URL을 얻는 방법