Mam kilka działającego kodu modułu scala jackson dla klas klasycznych zajęć klasycznych. Jackson świetnie pasował do klas płaskich, ale kiedy zrobiłem taki, który zawiera listę innych klas przypadków, ilość kodu, którego potrzebowałem, była bardzo duża. Rozważmy:Niestandardowa serializacja json klas uporządkowanych klas scala
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
Aby uzyskać cardset aby obie strony do/z json z modułem scala jackson użyłem niestandardowe serializatora/Deserializator napisany w Javie:
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
}
}
z serializatora:
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();
}
}
i pasujący deserializator:
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");
}
}
To wydaje się dużo kodu, aby poradzić sobie z czymś dość wanilii w scala. Czy ten kod może być ulepszony (czego brakowało mi, żeby Jackson miał to ułatwić)? Czy istnieje biblioteka, która automatycznie tworzy uporządkowane klasy spraw? Przykłady jerksona wydawały się łatwe, ale wydaje się, że zostały porzucone.
Próbowałem gniazda, które wyglądały obiecująco, ale miał problem z tych klas, które zgłosiłem tutaj https://github.com/ wg/jacks/issues/15 – simbo1905
Argonaut wykonuje zadanie za pomocą '' 'implicit lazy val CodecCardSet: CodecJson [CardSet] = casecodec2 (CardSet.apply, CardSet.unapply) (" cards "," mType ")' '' i '' 'niejawny lazy val CodecCardDrawn: CodecJson [Card Drawn] = casecodec3 (CardDrawn.apply, CardDrawn.unapply) ("player", "card", "mType") '' 'zobacz przykład na https://github.com/argonaut-io/argonaut/issues/64 – simbo1905
czy rozważałeś użycie modułu Scala Jackson? https://github.com/FasterXML/jackson-module-scala –