2013-09-01 4 views
5

나는 스칼라 케이스 클래스를 라운드 트립하기 위해 일부 작동 잭슨 스칼라 모듈 코드를 가지고있다. 잭슨은 플랫 케이스 클래스에서 훌륭하게 작동했지만 다른 케이스 클래스 목록이 포함 된 클래스를 만들었을 때 필요한 코드의 양이 많았습니다. 고려 : 시리얼 라이저와구조화 된 스칼라 케이스 클래스의 사용자 정의 json 직렬화

object ScrumGameMashaller { 

    val mapper = new ObjectMapper() 
    val module = new SimpleModule("CustomSerializer") 
    module.addSerializer(classOf[CardSet], new CardSetSerializer) 
    module.addDeserializer(classOf[CardSet], new CardSetDeserializer) 
    val scalaModule = DefaultScalaModule 
    mapper.registerModule(scalaModule) 
    mapper.registerModule(module) 

    def jsonFrom(value: Any): String = { 
    import java.io.StringWriter 
    val writer = new StringWriter() 
    mapper.writeValue(writer, value) 
    writer.toString 
    } 

    private[this] def objectFrom[T: Manifest](value: String): T = 
    mapper.readValue(value, typeReference[T]) 

    private[this] def typeReference[T: Manifest] = new TypeReference[T] { 
    override def getType = typeFromManifest(manifest[T]) 
    } 

    private[this] def typeFromManifest(m: Manifest[_]): Type = { 
    if (m.typeArguments.isEmpty) { m.runtimeClass } 
    else new ParameterizedType { 
     def getRawType = m.runtimeClass 
     def getActualTypeArguments = m.typeArguments.map(typeFromManifest).toArray 
     def getOwnerType = null 
    } 
    } 

:

public class CardSetSerializer extends JsonSerializer<CardSet> { 
@Override 
    public void serialize(CardSet cardSet, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { 
     jgen.writeStartObject(); 
     jgen.writeArrayFieldStart("cards"); 
     List<CardDrawn> cardsDrawn = cardSet.cards(); 
     scala.collection.Iterator<CardDrawn> iter = cardsDrawn.iterator(); 
     while(iter.hasNext()){ 
      CardDrawn cd = iter.next(); 
      cdSerialize(jgen,cd); 
     } 
     jgen.writeEndArray(); 
     jgen.writeStringField("mType", "CardSet"); 
     jgen.writeEndObject();  
    } 

    private void cdSerialize(JsonGenerator jgen, CardDrawn cd) throws IOException, JsonProcessingException { 
     jgen.writeStartObject(); 
     jgen.writeNumberField("player", cd.player()); 
     jgen.writeNumberField("card", cd.card()); 
     jgen.writeEndObject(); 
    } 
} 
잭슨 스칼라 모듈과 JSON에서 내가/자바로 작성 디시리얼라이저 사용자 지정 serializer를 사용에/

abstract class Message 
case class CardDrawn(player: Long, card: Int, mType: String = "CardDrawn") extends Message 
case class CardSet(cards: List[CardDrawn], mType: String = "CardSet") extends Message 

가 CardSet은 라운드 트립을 얻으려면

및 매칭 디시리얼라이저 :

public class CardSetDeserializer extends JsonDeserializer<CardSet> { 

    private static class CardDrawnTuple { 
     Long player; 
     Integer card; 
    } 

    @Override 
    public CardSet deserialize(JsonParser jsonParser, DeserializationContext cxt) throws IOException, JsonProcessingException { 
     ObjectCodec oc = jsonParser.getCodec(); 
     JsonNode root = oc.readTree(jsonParser); 
     JsonNode cards = root.get("cards"); 
     Iterator<JsonNode> i = cards.elements(); 
     List<CardDrawn> cardObjects = new ArrayList<>(); 
     while(i.hasNext()){ 
      CardDrawnTuple t = new CardDrawnTuple(); 
      ObjectNode c = (ObjectNode) i.next(); 
      Iterator<Entry<String, JsonNode>> fields = c.fields(); 
      while(fields.hasNext()){ 
       Entry<String,JsonNode> f = fields.next(); 
       if(f.getKey().equals("player")) { 
        t.player = f.getValue().asLong(); 
       } else if(f.getKey().equals("card")){ 
        t.card = f.getValue().asInt(); 
       } else { 
        System.err.println(CardSetDeserializer.class.getCanonicalName()+ " : unknown field " + f.getKey()); 
       } 
      } 
      CardDrawn cd = new CardDrawn(t.player, t.card, "CardDrawn"); 
      cardObjects.add(cd); 
     } 

     return new CardSet(JavaConversions.asScalaBuffer(cardObjects).toList(), "CardSet"); 
    } 

} 

이것은 스칼라에서 상당히 바닐라적인 것을 다루는 많은 코드처럼 보입니다. 이 코드를 개선 할 수 있습니까? 그렇지 않으면 구조화 된 사례 클래스를 자동으로 수행 할 라이브러리가 있습니까? 저크슨 예제는 쉽게 보였지만 버려진 것 같습니다.

+0

내가 유망 보았다 잭을 시도했지만 내가 여기에보고 이러한 클래스에 문제가 있었다 https://github.com/ wg/jacks/issues/15 – simbo1905

+0

Argonaut는''암시적인 lazy val CodecCardSet로 작업을 수행합니다 : CodecJson [CardSet] = casecodec2 (CardSet.apply, CardSet.unapply) ("cards", "mType")'''and '''암묵적인 lazy val CodecCardDrawn : CodecJson [Card Drawn] = casecodec3 (CardDrawn.apply, CardDrawn.unapply) ("player", "card", "mType")'''예 : https://github.com/argonaut-io/argonaut/issues/64 – simbo1905

+0

스칼라 잭슨 모듈 사용을 고려해 보셨습니까? https://github.com/FasterXML/jackson-module-scala –

답변

0

Argonaut는 훌륭한 직업입니다. Mark Hibbard은 아래 예제를 작동시키는 것을 도와주었습니다. 필요한 것은 유형에 대한 코덱을 작성하는 것이며 암시 적으로 오브젝트에 asJson을 추가하여 오브젝트를 문자열로 변환합니다. 또한 객체를 추출하기 위해 문자열에 decodeOption[YourClass]을 추가합니다. 다음 :

package argonaut.example 

import argonaut._, Argonaut._ 

abstract class Message 
case class CardDrawn(player: Long, card: Int, mType: String = "CardDrawn") extends Message 
case class CardSet(cards: List[CardDrawn], mType: String = "CardSet") extends Message 

object CardSetExample { 

    implicit lazy val CodecCardSet: CodecJson[CardSet] = casecodec2(CardSet.apply, CardSet.unapply)("cards","mType") 
    implicit lazy val CodecCardDrawn: CodecJson[CardDrawn] = casecodec3(CardDrawn.apply, CardDrawn.unapply)("player", "card", "mType") 

    def main(args: Array[String]): Unit = { 
    val value = CardSet(List(CardDrawn(1L,2),CardDrawn(3L,4))) 
    println(s"Got some good json ${value.asJson}") 

    val jstring = 
     """{ 
     | "cards":[ 
     | {"player":"1","card":2,"mType":"CardDrawn"}, 
     | {"player":"3","card":4,"mType":"CardDrawn"} 
     | ], 
     | "mType":"CardSet" 
     | }""".stripMargin 

    val parsed: Option[CardSet] = 
     jstring.decodeOption[CardSet] 

    println(s"Got a good object ${parsed.get}") 
    } 
} 

출력 :

Got some good json {"cards":[{"player":"1","card":2,"mType":"CardDrawn"},{"player":"3","card":4,"mType":"CardDrawn"}],"mType":"CardSet"}

Got a good object CardSet(List(CardDrawn(1,2,CardDrawn), CardDrawn(3,4,CardDrawn)),CardSet)

관련 문제