2013-06-16 1 views
6

Alla ricerca di un buon esempio di polimorfica serializzazione deserializzazione utilizzando Jackson con scalaAlla ricerca di un buon esempio di polimorfica serializzazione deserializzazione utilizzando Jackson con scala

trovato un'eccezione:

Exception in thread "main" blockquote org.codehaus.jackson.map.exc.UnrecognizedPropertyException: non riconosciuti campo "animali" (zoo di classe), non è contrassegnato come ignorabile

dopo aver provato il seguente codice:

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 
    } 

} 

file di input.json

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

risposta

4

OK, ricevuto qui è un esempio di lavoro con scala in base a 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 {"animals": [ {"type": "cane", "nome": "Spike", "razza": "mutt", "color": "red"}, { "type": "gatto", "name": "Fluffy", "favoriteToy": "l'anello del ragno"} ]}

5

Se stai facendo deserializzazione polimorfico a Scala mi piacerebbe consigliamo vivamente usando classi di casi e il modulo scala di Jackson.

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, quale versione di Jackson e quale versione di Scala hai eseguito su questo? Sto diventando com.fasterxml.jackson.databind.JsonMappingException: Impossibile costruire l'istanza di TestJackson $ Animale, problema: i tipi astratti devono essere mappati su tipi concreti, hanno deserializzatore personalizzato o essere istanziati con informazioni di tipo aggiuntive su Scala 2.10 .4 con l'ultimo Jackson 2.4.3 –

+0

Ho aggiornato il mio post per includere le importazioni specifiche (quell'errore sembra un'importazione errata). Questo dovrebbe funzionare su tutte le versioni di Scala 2.9+ e Jackson 2.2+ (se non prima). Stavo specificatamente utilizzando Scala 2.11.2 e Jackson 2.4.3. Finché c'è un vaso jackson-module-scala costruito per la combinazione, dovrebbe funzionare. Puoi trovarli qui: http://search.maven.org/#search%7Cga%7C1%7Cjackson-module-scala – Nate

+0

Grande, funziona ora. Grazie! –