2015-08-11 3 views
3

у меня есть это:Получить конкретный тип корпуса класса

sealed trait Block 

sealed case class Header(param1: String, 
             param2: String, 
             ...) extends Block 

... 
(more sealed case classes that follows the same pattern) 

Позже я группируя эти блоки в послед, следующим образом:

val blocks: Seq[Block with Product with Serializable] = Seq(structure.header, structure.body, ...) 

И я хочу, чтобы сериализовать каждый блок как Json (с Play). Я делаю это следующим образом:

blocks.map{ 
     x => 
      serializeBlock(x) 
    } 

Определение «serializeBlock»:

def serializeBlock[A<:Block](block:A): String = { 
    block match { 
     case block: Header => Json.toJson(block).toString() 
     case block: Body => Json.toJson(block).toString() 
     ... n-times for every possible case class that mixes the block trait 
    } 
} 

У меня есть читатели и писатели для каждого конкретного блока (заголовок, тело ...), но, как вы видите , когда я смешиваю эти блоки в Seq Scala, рассматриваю его как блок типа Generic, по этой причине я выполняю сопоставление шаблонов со всеми возможными типами блоков (неявное литье?). Если я просто назову «Json.toJson» в Map Play, жалуется, что не нашел Reader/Writer для типа «block».

«Блок» - это фрагмент относительно большого JSON. Я получаю JSON, я разделив его в квалифицированных «блоков», а затем я хочу сохранить его в виде строки в базе данных:

«Big» JSON:

{ 
    "header" : { 
     "param1" : "", 
     ... 
    }, 
    "body" : { 
     "param1" : "", 
     ... 
    } 
    ... 
} 

Блоки

{ 
    "param1" : "", 
    ... 
} 

Мой вопрос: есть ли способ сделать сериализации, не повторяя п раз в "блок: Тип "узор? Я имею в виду: есть ли какой-либо способ получить конкретный тип этого блока (зная, что Seq набирается как суперкласс «блок», а не как «конкретный» тип этого блока)?

EDIT

У меня есть устройство чтения/записи для каждого блока следующим образом:

implicit val headerReader: Reads[Header] = (
    (JsPath \ "param1").read[String] and 
    (JsPath \ "param2").read[String] and 
    ... 
)(Header.apply _) 

implicit val headerWriter: Writes[Header] = (
    (JsPath \ "param1").write[String] and 
    (JsPath \ "param2").write[String] and 
    ... 
)(unlift(Header.unapply)) 

EDIT 2:

ли Shapeless образом решить эту проблему?

EDIT 3:

Как отметил Анджей Jozwik: "param1" и "param2" являются 'шаблонные' Титулы, которые я использовал, чтобы определить мой JSON структуры здесь. Каждый блок имеет разные параметры.

+0

Имеют ли в корпусных случаях какие-либо разные поведенческие требования? –

+0

@SergeyLagutin Нет, каждый класс case - это просто контейнер для преобразования входящего/исходящего JSON. –

+0

Я имею в виду случаи, когда совпадение шаблонов отличается друг от друга? Или они такие же, кроме типа? –

ответ

1

бесформенный «HList» кажется возможным решением для вас. Вот пример, который, кажется, довольно близко к тому, что вы хотите сделать:

import shapeless._ 

sealed trait Block 
case class Test1(a: String, b: String) extends Block 
object Test1 { 
    implicit val writes = (
    (JsPath \ "a").write[String] and 
    (JsPath \ "b").write[String] 
)(unlift(Test1.unapply)) 
} 

case class Test2(c: String, d: String) extends Block 
object Test2 { 
    implicit val writes =(
    (JsPath \ "c").write[String] and 
    (JsPath \ "d").write[String] 
)(unlift(Test2.unapply)) 
} 

object serializeBlock extends Poly1 { 
    implicit def default[T <: Block](implicit w: Writes[T]) = at[T] { x => 
    Json.toJson(x).toString 
    } 
} 

val blocks = Test1("hi", "hello") :: Test2("what", "why") :: HNil 

blocks.map(serializeBlock).toList // List[String]({"a": "hi", "b": "hello"}, {"c": "what", "d": "why"}) 

Обратите внимание, что каждый член HList должен иметь неявное Записывает доступные для этого типа.Если это не ошибка вы получаете не дико полезно:

val list = Test1("hi", "hello") :: Test2("a", "b") :: NoWrites("wrong") :: HNil 
list.map(serializeBlock) 

с ошибкой:

could not find implicit value for parameter mapper: shapeless.ops.hlist.Mapper[serializeBlock.type,shapeless.::[Test1,shapeless.::[Test2,shapeless.::[NoWrites,shapeless.HNil]]]] 

Это просто означает, что это не представляется возможным назвать serializeBlock для некоторого члена HList вы назовете карту.

В этом случае он не может вызвать serializeBlock для объекта NoWrites, потому что в текущей области не существует неявных Writes [NoWrites].

Вы получите аналогичную ошибку, если какой-либо объект в HList не будет расширять блок.

+1

Это сработало! :) - Хороший способ решить эту проблему. –

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