2017-06-01 14 views
9

यह प्रश्न हाल ही में कुछ बार आया है, इसलिए मैं इसे यहां पूछताछ कर रहा हूं। मान लीजिए मैं इस तरह कुछ मामले वर्गों मिल गया है:मेरा कॉम्पॉडक्ट एन्कोडिंग संदिग्ध है

import io.circe._, io.circe.generic.semiauto._ 

object model { 
    case class A(a: String) 
    case class B(a: String, i: Int) 
    case class C(i: Int, b: Boolean) 

    implicit val encodeA: Encoder[A] = deriveEncoder 
    implicit val encodeB: Encoder[B] = deriveEncoder 
    implicit val encodeC: Encoder[C] = deriveEncoder 
    implicit val decodeA: Decoder[A] = deriveDecoder 
    implicit val decodeB: Decoder[B] = deriveDecoder 
    implicit val decodeC: Decoder[C] = deriveDecoder 
} 

और मैं एक मूल्य है कि JSON के रूप में इनमें से किसी भी एक circe और निराकार coproducts का उपयोग कर किया जा सकता है सांकेतिक शब्दों में बदलना चाहते हैं।

import io.circe.shapes._, io.circe.syntax._ 
import shapeless._ 

import model._ 

type ABC = A :+: B :+: C :+: CNil 

val c: ABC = Coproduct[ABC](C(123, false)) 

यह पहली बार में ठीक लग रहा है:

scala> c.asJson 
res0: io.circe.Json = 
{ 
    "i" : 123, 
    "b" : false 
} 

लेकिन समस्या यह है कि मैं एक coproduct एक B तत्व से युक्त डिकोड नहीं कर सकते हैं, के बाद से किसी भी मान्य JSON दस्तावेज है कि B के रूप में डीकोड किया जा सकता है भी किया जा सकता है A के रूप में डीकोड किया गया है, और कोरस-आकार द्वारा प्रदान किए गए उत्पादक डिकोडर्स तत्वों को क्रम में प्रकट करने के क्रम में तत्वों को आज़माते हैं।

scala> val b: ABC = Coproduct[ABC](B("xyz", 123)) 
b: ABC = Inr(Inl(B(xyz,123))) 

scala> val json = b.asJson 
json: io.circe.Json = 
{ 
    "a" : "xyz", 
    "i" : 123 
} 

scala> io.circe.jawn.decode[ABC](json.noSpaces) 
res1: Either[io.circe.Error,ABC] = Right(Inl(A(xyz))) 

मैं अपने एन्कोडिंग में अपने प्रोडक्ट के तत्वों को कैसे बांट सकता हूं?

उत्तर

9

सर्स-आकार मॉड्यूल सामान्य hlists को लेबल करता है और उपरोक्त वर्णित लेबल के बिना उत्पादित करता है: तत्व के नंगे JSON प्रतिनिधित्व के रूप में एक प्रोडक्ट, और एक सूची एक JSON सरणी के रूप में समाप्त होती है (डिफ़ॉल्ट ट्यूपल एन्कोडिंग के समान):

scala> ("xyz" :: List(1, 2, 3) :: false :: HNil).asJson.noSpaces 
res2: String = ["xyz",[1,2,3],false] 

hlists के मामले में वहाँ क्योंकि ओवरलैपिंग नामों की अस्पष्टता की कोई खतरा नहीं है, लेकिन coproducts के लिए नहीं है। दोनों मामलों में, हालांकि, आप शेपलेस के लेबलिंग तंत्र का उपयोग करके जेएसओएन प्रस्तुति में लेबल जोड़ सकते हैं, जो टाइप-स्तरीय प्रतीक वाले मानों को टैग करता है।

लेबल के साथ एक सूची को "रिकॉर्ड" कहा जाता है, और लेबल के साथ एक प्रोडक्ट "संघ" होता है। बेकार इन दोनों के लिए विशेष वाक्यविन्यास और संचालन प्रदान करता है, और परिसंचरण दोनों अलग-अलग hlists या coproducts से अलग व्यवहार करता है।

scala> import shapeless.union._, shapeless.syntax.singleton._ 
import shapeless.union._ 
import shapeless.syntax.singleton._ 

scala> type ABCL = Union.`'A -> A, 'B -> B, 'C -> C`.T 
defined type alias ABCL 

scala> val bL: ABCL = Coproduct[ABCL]('B ->> B("xyz", 123)) 
bL: ABCL = Inr(Inl(B(xyz,123))) 

scala> val jsonL = bL.asJson 
jsonL: io.circe.Json = 
{ 
    "B" : { 
    "a" : "xyz", 
    "i" : 123 
    } 
} 

scala> io.circe.jawn.decode[ABCL](jsonL.noSpaces) 
res3: Either[io.circe.Error,ABCL] = Right(Inr(Inl(B(xyz,123)))) 

रिकॉर्ड के लिए एन्कोडिंग इसी तरह सदस्य के नाम शामिल हैं: उदाहरण के लिए: (परिभाषाएँ और आयात से ऊपर मानते हुए)

scala> ('a ->> "xyz" :: 'b ->> List(1) :: 'c ->> false :: HNil).asJson.noSpaces 
res4: String = {"c":false,"b":[1],"a":"xyz"} 

सामान्य तौर पर अगर आप लेबल शामिल करने के लिए अपने hlist और coproduct एनकोडिंग चाहते हैं (और कक्षाओं और मुहरबंद विशेषता पदानुक्रमों के लिए जो आपको एन्कोडिंग से प्राप्त होता है, उसके समान दिखें), आप रिकॉर्ड्स-आकृतियों को कम से कम अतिरिक्त सिंटैक्टिक और रनटाइम ओवरहेड के साथ करने के लिए रिकॉर्ड या प्रोडक्ट्स का उपयोग कर सकते हैं।

संबंधित मुद्दे