2013-06-16 10 views
6

Suche nach einem guten Beispiel für polymorphe Serialisierung Deserialisierung Jacksonfür ein gutes Beispiel für polymorphe Serialisierung Deserialisierung der Suche unter Verwendung von Jackson mit scala

mit scala Verwendung bekam eine Ausnahme:

Exception in thread „main“ Blockquote org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unerkannte Feld "Tiere" (Klasse Zoo), nicht als ignorable markiert

nach dem folgenden Code versuchen:

import org.codehaus.jackson.annotate.{ JsonTypeInfo, JsonSubTypes } 
    import org.codehaus.jackson.annotate.JsonSubTypes.Type 

    @JsonTypeInfo(
     use = JsonTypeInfo.Id.NAME, 
     include= JsonTypeInfo.As.PROPERTY, 
     property = "type" 
    ) 
    @JsonSubTypes(Array(
     new Type(value= classOf[Cat] , name = "cat"), 
     new Type(value= classOf[Dog] , name = "dog") 
    ) 
    ) 
    abstract class Animal { 
     val name:String = "NoName" 

    } 
class Cat extends Animal{ 
    val favoriteToy = "edi" 
} 
class Dog extends Animal{ 
    val breed = "German Shepherd" 
    val color = "brown" 
} 
class Zoo { 
    val animals = new scala.collection.mutable.ListBuffer[Animal] 
} 
import org.codehaus.jackson.map.ObjectMapper 

object Foo { 
    def main (args:Array[String]) { 
    val mapper = new ObjectMapper() 
    mapper.setPropertyNamingStrategy(CamelCaseNamingStrategy) 
    val source = scala.io.Source.fromFile("input.json") 
    val input = source.mkString 
    source.close 
    val zoo = mapper.readValue(input,classOf[Zoo]) 
    println(mapper.writeValueAsString(zoo)) 
    } 
import org.codehaus.jackson.map.introspect.{AnnotatedField, AnnotatedMethod} 
import org.codehaus.jackson.map.{MapperConfig, PropertyNamingStrategy} 

object CamelCaseNamingStrategy extends PropertyNamingStrategy{ 
override def nameForGetterMethod (config: MapperConfig[_], method: AnnotatedMethod, defaultName: String) = 
{ 
    translate(defaultName) 
} 

override def nameForSetterMethod (config: MapperConfig[_], method: AnnotatedMethod, defaultName: String) = { 
    translate(defaultName) 
} 

    override def nameForField (config: MapperConfig[_], field: AnnotatedField, defaultName: String) = { 
    translate(defaultName) 
    } 

    def translate(defaultName:String) = { 
    val nameChars = defaultName.toCharArray 
    val nameTranslated = new StringBuilder(nameChars.length*2) 
    for (c <- nameChars){ 
     if (Character.isUpperCase(c)){ 
     nameTranslated.append("_") 
     } 
     nameTranslated.append(Character.toLowerCase(c)) 
    } 
    nameTranslated.toString 
    } 

} 

Datei input.json

{ 
"animals": 
    [ 
    {"type":"dog","name":"Spike","breed":"mutt","color":"red"}, 
    {"type":"cat","name":"Fluffy","favoriteToy":"spider ring"} 
    ] 
} 

Antwort

4

Ok, Verstand hier ist ein funktionierendes Beispiel mit scala basierend auf Deserialize JSON with Jackson into Polymorphic by Programmer Bruce:

import org.codehaus.jackson.annotate.JsonSubTypes.Type 
import org.codehaus.jackson.annotate.{JsonSubTypes, JsonTypeInfo} 

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME, 
    include= JsonTypeInfo.As.PROPERTY, 
    property = "type" 
) 
@JsonSubTypes(Array(
    new Type(value= classOf[Cat] , name = "cat"), 
    new Type(value= classOf[Dog] , name = "dog") 
) 
) 
abstract class Animal { 
    var name:String ="" 

} 

class Dog extends Animal{ 
    var breed= "German Shepherd" 
    var color = "brown" 
} 

class Cat extends Animal{ 
    var favoriteToy:String = "nothing" 
} 


class Zoo { 
    var animals = new Array[Animal](5) 
} 


import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility 
import org.codehaus.jackson.annotate.JsonMethod 
import org.codehaus.jackson.map.{DeserializationConfig, ObjectMapper} 

object Foo { 
    def main (args:Array[String]) { 
    val mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD,Visibility.ANY) 
    mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,false) 
    val source = scala.io.Source.fromFile("/input.json") 
    val input = source.mkString 
    println("input " + input) 
    source.close 
    val zoo = mapper.readValue(input,classOf[Zoo]) 

    println(mapper.writeValueAsString(zoo)) 
    } 

} 

file: input.json {"Tiere": [ {"Typ": "Hund", "Name": "Spike", "Rasse": "Köter", "Farbe": "rot"}, { "type": "cat", "name": "Fluffy", "favoriteToy": "Spinne Ring"} ]}

5

Wenn Sie polymorphe Deserialisierung in Scala tun würde ich empfehlen, mit Fallklassen und Jacksons Scala-Modul.

object Test { 
    import com.fasterxml.jackson.annotation.JsonSubTypes.Type 
    import com.fasterxml.jackson.annotation.{JsonSubTypes, JsonTypeInfo} 
    import com.fasterxml.jackson.databind.ObjectMapper 
    import com.fasterxml.jackson.module.scala.DefaultScalaModule 
    import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper 

    @JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME, 
    include = JsonTypeInfo.As.PROPERTY, 
    property = "type" 
) 
    @JsonSubTypes(Array(
    new Type(value = classOf[Cat], name = "cat"), 
    new Type(value = classOf[Dog], name = "dog") 
)) 
    trait Animal 

    case class Dog(name: String, breed: String, leash_color: String) extends Animal 
    case class Cat(name: String, favorite_toy: String) extends Animal 
    case class Zoo(animals: Iterable[Animal]) 

    def main(args: Array[String]): Unit = { 
    val objectMapper = new ObjectMapper with ScalaObjectMapper 
    objectMapper.registerModule(DefaultScalaModule) 

    val dogStr = """{"type": "dog", "name": "Spike", "breed": "mutt", "leash_color": "red"}""" 
    val catStr = """{"type": "cat", "name": "Fluffy", "favorite_toy": "spider ring"}""" 
    val zooStr = s"""{"animals":[$dogStr, $catStr]}""" 

    val zoo = objectMapper.readValue[Zoo](zooStr) 

    println(zoo) 
    // Prints: Zoo(List(Dog(Spike,mutt,red), Cat(Fluffy,spider ring))) 
    } 
} 
+0

Nate, was Jackson-Version und welche Scala-Version haben Sie ausgeführt? Ich bekomme com.fasterxml.jackson.databind.JsonMappingException: Kann keine Instanz von TestJackson $ Animal, Problem erstellen: abstrakte Typen müssen entweder zu konkreten Typen gemappt werden, einen eigenen Deserializer haben oder mit zusätzlichen Typinformationen auf Scala 2.10 instanziiert werden .4 mit dem neuesten Jackson 2.4.3 –

+0

Ich habe meinen Beitrag aktualisiert, um die spezifischen Importe einzuschließen (dieser Fehler klingt wie ein falscher Import). Dies sollte bei allen Versionen von Scala 2.9+ und Jackson 2.2+ (wenn nicht früher) funktionieren. Ich benutzte speziell Scala 2.11.2 und Jackson 2.4.3. Solange ein Jackson-Modul-Scala-Glas für die Kombination gebaut ist, sollte es funktionieren. Sie können sie hier finden: http://search.maven.org/#search%7Cga%7C1%7Cjackson-module-scala – Nate

+0

Großartig, funktioniert jetzt. Vielen Dank! –

Verwandte Themen