2013-06-11 2 views
3

Я пытаюсь обернуть Argonaut (http://argonaut.io), чтобы сериализовать/десериализовать JSON в проекте Scala. Мы, где раньше пользовались Джерксоном, но, поскольку это было прекращено, мы ищем альтернативу.Как передать общие типы Argonaut

Это основной JSON обертка

import argonaut._, Argonaut._ 

object Json { 
    def Parse[T](input: String): T = { 
    input.decodeOption[T].get 
    } 
} 

Когда я пытаюсь скомпилировать это я получаю следующие ошибки.

could not find implicit value for evidence parameter of type argonaut.DecodeJson[T] 
    input.decodeOption[T] 
       ^
not enough arguments for method decodeOption: (implicit evidence$6: argonaut.DecodeJson[T]) Option[T]. 
Unspecified value parameter evidence$6. 
    input.decodeOption[T] 
       ^

Любые предложения относительно того, как исправить это или указатели на то, что я делаю неправильно, будут наиболее ценными.

Также приветствуются предложения по альтернативным системам JSON.

Я как бы новичок в Scala/Java и как работают дженерики, но я много лет писал .NET/C#.

+0

Я предполагаю, что decodeOption возвращает Option, но вы возвращаете метод T –

+0

спасибо lukas, забыли о добавлении .get в пример. –

ответ

7

Для того, чтобы сделать ваш код работать, вам нужно будет переопределить Json объект следующим образом:

object Json { 
    def Parse[T](input: String)(implicit decode:DecodeJson[T]): Option[T] = { 
    input.decodeOption[T] 
    } 
} 

Что вам не хватало был неявный DecodeJson экземпляр, что функция decodeOption необходимо для того, чтобы выяснить, как декодировать. Вам также необходимо определить тип возврата как Option[T], а не только T.Полный пример этого все работы будет выглядеть следующим образом:

import argonaut._, Argonaut._ 
case class User(id:Long, email:String, name:String) 

object Json { 
    def Parse[T](input: String)(implicit decode:DecodeJson[T]): Option[T] = { 
    input.decodeOption[T] 
    } 
} 

object JsonTest{ 
    implicit val userDecode = casecodec3(User.apply, User.unapply)("id", "email", "name") 

    def main(args: Array[String]) { 
    val json = """{ 
     "id": 1, 
     "email": "[email protected]", 
     "name": "foo bar" 
    }""" 

    val userOpt = Json.Parse[User](json) 
    println(userOpt) 
    } 
} 

Что касается других структур JSon, вы можете посмотреть в:

Play Json

json4s

spray-json

Jackson Scala Module

3

Кажется, что аргонавт, как и почти все библиотеки сериализации Scala, использует шаблон типа типа. Это звучит как причудливая вещь, но на самом деле это просто означает, что при сериализации/десериализации объекта типа T вам требуется неявно передать экземпляр другого объекта, к которому отложена часть или весь процесс. В частности, когда вы делаете decodeOption[T], вам необходимо иметь в виду экземпляр argonaut.DecodeJson[T] (который decodeOption будет использовать во время десериализации).

Что вы должны сделать, это просто требовать это неявное значение передается в Parse (она будет автоматически передаваться вместе с decodeOption:

def Parse[T](input: String)(implicit decoder: argonaut.DecodeJson[T]): Option[T] = { 
    input.decodeOption[T] 
} 

Scala даже предоставляет некоторые синтаксический сахар, чтобы сделать заявление короче (это называется «контекст связан»):

def Parse[T:argonaut.DecodeJson](input: String): Option[T] = { 
    input.decodeOption[T] 
} 

Теперь при вызове Parse, вы должны принести в сферу неявное значение из argonaut.DecodeJson, или его кал будет не в состоянии с ompile. По-видимому, объект Argonaut уже определяет декодеры для многих стандартных типов, поэтому для типов тиков вам нечего делать. Для других типов (например, ваших собственных пользовательских типов) вам придется определять декодеры и импортировать их неявно.

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