2010-11-03 2 views
6

Я провел последний день, пытаясь найти ответы на этот вопрос, и я не нашел ничего, что помогает. Я даже не уверен, насколько это возможно. Моя проблема в том, что я пытаюсь разобрать и извлечь Json Response с помощью lift-json. Ответ состоит из 4 частей, где первые 3 части всегда одинаковы для каждого ответа на каждый тип запроса, который я делаю. Последняя часть изменяется в зависимости от типа запроса, но она всегда будет списком некоторого типа. Я надеялся, что сделать что-то вроде этого:Извлечение lift-json в класс класса с верхней границей

abstract class MyObjects 
case class Apple(id: Int, name: String, color: String) extends MyObjects 
case class Orange(id: Long, name: String, state: String) extends MyObjects 

abstract class MyResponse 
case class Fruits[T <: MyObjects](aisle: Int, bin: Int, hasWhat: Option[List[T]]) 

Где, если я хотел бы знать, что все яблоки, я хотел бы сделать запрос на это и получить обратно ответ со списком яблок. Когда я пытаюсь извлечь этот пример:

myJson.extract[Fruits[Apple]] 

Я получаю эту ошибку:

net.liftweb.json.MappingException: do not know how to get type parameter from T 
    at net.liftweb.json.Meta$.fail(Meta.scala:128) 
    at net.liftweb.json.Meta$Reflection$.term$1(Meta.scala:206) 
    at net.liftweb.json.Meta$Reflection$.typeParameters(Meta.scala:220) 
    at net.liftweb.json.Meta$.mkContainer$1(Meta.scala:91) 
    at net.liftweb.json.Meta$.fieldMapping$1(Meta.scala:101) 
    at net.liftweb.json.Meta$.mkContainer$1(Meta.scala:90) 
    at net.liftweb.json.Meta$.fieldMapping$1(Meta.scala:107) 
    at net.liftweb.json.Meta$.toArg$1(Meta.scala:117) 
    at net.liftweb.json.Meta$$anonfun$constructors$1$1$$anonfun$apply$1.apply(Meta.scala:83) 
    at net.liftweb.json.Meta$$anonfun$constructors$1$1$$anonfun$apply$1.apply(Meta.scala:82) 
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:... 

Я использую Lift-JSon 2.1 & 2.8 Scala. У меня есть способ обойти это, специально создав класс case для каждого типа ответа, но я подумал, что я пытаюсь сделать это чище. Просто хотелось узнать, возможно ли это a)? б) Если да, то что я делаю неправильно?

EDIT ... Пример приложения:

val apples = """{ "aisle" : 1, "bin" : 1, 
      "hasWhat" : [{ "id" : 4, "name" : "Granny", "color" : "green"}, 
         { "id" : 4, "name" : "Fuji", "color" : "red"}] }""" 

val oranges = """ { "aisle" : 3, "bin" : 2, 
      "hasWhat" : [{ "id" : 2, "name" : "Navel", "state" : "FL" }, 
         { "id" : 2, "name" : "Clementine", "state" : "Spain" }]}""" 

scala> val aJson = parse(apples) 
aJson: net.liftweb.json.JsonAST.JValue = JObject(List(JField(aisle,JInt(1)), JField(bin,JInt(1)), JField(hasWhat,JArray(List(JObject(List(JField(id,JInt(4)), JField(name,JString(Granny)), JField(color,JString(green)))), JObject(List(JField(id,JInt(4)), JField(name,JString(Fuji)), JField(color,JString(red))))))))) 

scala> val oJson = parse(oranges) 
oJson: net.liftweb.json.JsonAST.JValue = JObject(List(JField(aisle,JInt(3)), JField(bin,JInt(2)), JField(hasWhat,JArray(List(JObject(List(JField(id,JInt(2)), JField(name,JString(Navel)), JField(state,JString(FL))))))))) 

scala> val doesntWork = aJson.extract[Fruits] 
doesntWork: org.spin.node.gogrid.objects.Fruits = Fruits(1,1,None) 

scala> val works = aJson.extract[AFruit] 
works: org.spin.node.gogrid.objects.AFruit = AFruit(1,1,Some(List(Apple(4,Granny,green), Apple(4,Fuji,red)))) 

Я хочу doesntWork быть как работает, где:

case class AFruit(aisle: Int, bin: Int, hasWhat: Option[List[Apple]]) 

Спасибо! -newbie

ответ

8

Извлечение параметризованного класса case еще не поддерживается. Один обход (не уверен, что это работает для вашего случая) заключается в том, чтобы сделать Fruits конкретным типом и добавить информацию о типе в JSON.

import net.liftweb.json._ 
import net.liftweb.json.Extraction._ 
import net.liftweb.json.JsonAST._ 
import net.liftweb.json.Printer._ 

abstract class MyObjects 
case class Apple(id: Int, name: String, color: String) extends MyObjects 
case class Orange(id: Long, name: String, state: String) extends MyObjects 

case class Fruits(aisle: Int, bin: Int, hasWhat: Option[List[MyObjects]]) 

object Test extends Application { 
    // This configuration adds an extra field for MyObjects to JSON 
    // which tells the real type of a MyObject. 
    implicit val formats = Serialization.formats(FullTypeHints(List(classOf[MyObjects]))) 

    val fs = Fruits(0, 0, Some(List(
    Apple(1, "Granny Smith", "green"), 
    Apple(2, "Grenade", "red")))) 
    val json = decompose(fs) 
    println(pretty(render(json))) 

    assert (json.extract[Fruits] == fs) 
} 

Это печатает:

{ 
    "aisle":0, 
    "bin":0, 
    "hasWhat":[{ 
    "jsonClass":"Apple", 
    "id":1, 
    "name":"Granny Smith", 
    "color":"green" 
    },{ 
    "jsonClass":"Apple", 
    "id":2, 
    "name":"Grenade", 
    "color":"red" 
    }] 
} 
+0

Привет Joni, Спасибо за ваш вклад, там, где я могу прочитать о различных конфигурациях и то, как сериализации работает? Это не работает. Я редактировал свой пост и разъяснял пример. Я буду получать струны, подобные тем, которые используются для яблок и апельсинов, и мне нужно закончить что-то вроде работ. – CaffiendFrog

+0

Привет, лучшие ресурсы - это README https://github.com/lift/lift/tree/master/framework/lift-base/lift-json/ и примеры (* Example.scala) в https://github.com/lift/lift/tree/master/framework/lift-base/lift-json/src/test/scala/net/liftweb/json /. На данный момент невозможно сделать дело «doesntwork» в вашей работе. Может быть, мы можем улучшить код отражения в будущем. – Joni

+0

Привет, Joni, я определенно могу жить с тем, чтобы классы case, такие как AFruit, поддерживали то, что мне нужно было делать, хорошо знать, что случай «doesntwork» не поддерживается ... Теперь я могу продолжить работу с остальной частью моей задачи. :). Еще раз спасибо, и спасибо, особенно за такой быстрый ответ, очень оцененный. – CaffiendFrog

 Смежные вопросы

  • Нет связанных вопросов^_^