2015-06-29 5 views
2

Я пытаюсь пройти JSON и извлекать информацию о типах объектов в полях:Странное поведение Scala в сопоставлении с образцом в случае JSON полей (рамки json4s)

import org.json4s._ 
import org.json4s.JsonAST.{JArray, JString, JObject, JInt, JBool, JDouble} 
import org.json4s.JsonDSL._ 
import org.json4s.native.JsonMethods._ 

def guessTypes(example: JValue): JObject = example match { 
case JObject(lst) => JObject(lst.map { 
    case (f, JObject(nested)) => JField(f, ("type" -> "object") ~ ("properties" -> guessTypes(nested))) 
    case (f, JString(s)) => JField(f, "type" -> "string") 
    case (f, JInt(num)) => JField(f, "type" -> "integer") 
    case (f, JDouble(double)) => JField(f, "type" -> "double") 
    case (f, JBool(b)) => JField(f, "type" -> "bool") 
    case (f, JArray(jarray: List[JInt])) => JField(f, ("type" -> "array") ~ ("items" -> "integer")) 
    case (f, JArray(jarray: List[JString])) => JField(f, ("type" -> "array") ~ ("items" -> "string")) 
    case (f, JArray(jarray: List[JObject])) => JField(f, ("type" -> "array") ~ ("items" -> "object")) ~ ("properties" -> jarray.map{ x => guessTypes(x)})) 
})} 

В случае:

def example = """ 
    |{ 
    | "partners_data": [ 
    | { 
    |  "info": { 
    |  "label": "partner45" 
    |  }, 
    |  "partner_id": "partner45", 
    |  "data": { 
    |  "field": 24 
    |  } 
    | } 
    | ], 
    | "name": "*****(", 
    | "location": [ 
    | 1, 
    | 2 
    | ], 
    | "is_mapped": false 
    |} 
    """.stripMargin 

результат получается:

{ "данные": { "Тип": "массив", "элементы": "объект"}, "название": { "Тип": "строка" }, "место": { "Тип": "ARRA у " "элементы": "объект"}, "is_mapped": { "типа": "BOOL"}}

Это не соответствующий результат, потому что для ключевых "пунктов" в "Location" значение" целое число " ожидается.

Похоже, Scala не может отличить ничего, кроме JValue в JArrays. будет получено

по последней строке, для ключевых "пунктов" в "месте" значение "объект": Если я заменяю

случая (Список [JINT]) е, JArray (jarray) , но для других полей значение будет неправильным.

Как я могу обойти эту особенность соответствия шаблону scala и рамки json4s?

+0

Какую версию Json4s вы используете? При использовании '" org.json4s "%%" json4s-native "%" 3.2.2 "' Я получаю правильные типы. – millhouse

+0

Я использую '" org.json4s "%%" json4s-native "%" 3.2.11 ". В нашем случае нет возможности использовать более раннюю версию json4s. – Gregg

ответ

1

Последние три шаблона по существу одинаковы из-за type erasure на JVM.

Поскольку массив JSON может содержать несколько типов (Scala/Java/...), трудно сопоставить тип элементов списка.

Вы можете проверить только первый элемент массива:

case (f, JArray(JString(_) :: tail)) => 
    JField(f, ("type" -> "array") ~ ("items" -> "string")) 
case (f, JArray(jarray @ JObject(_) :: tail)) => 
    JField(f, ("type" -> "array") ~ ("items" -> "object") ~ ("properties" -> jarray.map(guessTypes))) 

Или проверить каждый элемент в массиве:

case (f, JArray(list : List[JValue])) if list forall { case JInt(_) => true; case _ => false } => 
    JField(f, ("type" -> "array") ~ ("items" -> "integer"))