다음 도메인 모델을 JsonReader
사용하여 사용자 지정을 작성하려고합니다 spray-json
.
sealed trait OrderType
object OrderType {
case object MARKET extends OrderType
case object LIMIT extends OrderType
case object STOP extends OrderType
case object MARKET_IF_TOUCHED extends OrderType
case object TAKE_PROFIT extends OrderType
case object STOP_LOSS extends OrderType
case object TRAILING_STOP_LOSS extends OrderType
}
JsonReader
이 목적을 위해 만든 사용자 지정은 다음과 같습니다 .
implicit object OrderTypeJsonReader extends JsonReader[OrderType] {
def read(value: JsValue): OrderType = value match {
case JsString("MARKET") => MARKET
case JsString("LIMIT") => LIMIT
case JsString("STOP") => STOP
case JsString("MARKET_IF_TOUCHED") => MARKET_IF_TOUCHED
case JsString("TAKE_PROFIT") => TAKE_PROFIT
case JsString("STOP_LOSS") => STOP_LOSS
case JsString("TRAILING_STOP_LOSS") => TRAILING_STOP_LOSS
case _ => deserializationError("OrderType expected")
}
}
json 문자열과 이름이 case object
동일 하다는 점을 감안할 때 여기에서 코드 중복을 피할 수있는 방법이 있습니까?
패턴 일치를 부분 함수 (또는 맵)로 바꾸려고 시도 할 수 있습니다.
val orderTypes = List(MARKET, LIMIT, STOP, MARKET_IF_TOUCHED, TAKE_PROFIT, STOP_LOSS, TRAILING_STOP_LOSS)
val string2orderType: Map[JsValue, OrderType] =
orderTypes.map(ot => (JsString(ot.toString), ot)).toMap
implicit object OrderTypeJsonReader extends JsonReader[OrderType] {
def read(value: JsValue): OrderType =
string2orderType.getOrElse(value, deserializationError("OrderType expected"))
}
단점은 모든 케이스 오브젝트의 목록을 수동으로 지정해야한다는 것입니다. 리플렉션을 사용하여 생성 할 수 있습니다. 아마도이 질문은 봉인 된 특성의 서브 클래스 얻기에 도움이 될 것입니다 . 그러면 다음을 가질 수 있습니다.
import scala.reflect.runtime.universe
private val tpe = universe.typeOf[OrderType]
private val clazz = tpe.typeSymbol.asClass
private def objectBy[T](name: String): T = Class.forName(OrderType.getClass.getName + name + "$").newInstance().asInstanceOf[T]
val string2orderType: Map[JsValue, OrderType] = clazz.knownDirectSubclasses.map { sc =>
val objectName = sc.toString.stripPrefix("object ")
(JsString(objectName), objectBy[OrderType](objectName))
}.toMap
implicit object OrderTypeJsonReader extends JsonReader[OrderType] {
def read(value: JsValue): OrderType = string2orderType.getOrElse(value, deserializationError("OrderType expected"))
}
스프레이에 기본 케이스 클래스 형식을 추가하는 방법에 대한이 토론도 참조하십시오 : https://github.com/spray/spray-json/issues/186
의견을 해결하기 위해 업데이트
모든 유형 T에 대해 '생성'할 수 있습니까? 봉인 된 트레이 트 / 케이스 객체 열거가 꽤 많고 보일러 플레이트를 최소로 유지하는 것을 선호합니다.
나는 이것을 생각 해냈다 :
import spray.json._
import Utils._
sealed trait OrderStatus
object OrderStatus {
case object Cancelled extends OrderStatus
case object Delivered extends OrderStatus
// More objects...
implicit object OrderStatusJsonReader extends ObjectJsonReader[OrderStatus]
}
sealed trait OrderType
object OrderType {
case object MARKET extends OrderType
case object LIMIT extends OrderType
// More objects...
implicit object OrderTypeJsonReader extends ObjectJsonReader[OrderType]
}
object Utils {
import scala.reflect.ClassTag
import scala.reflect.runtime.universe._
def objectBy[T: ClassTag](name: String): T = {
val c = implicitly[ClassTag[T]]
Class.forName(c + "$" + name + "$").newInstance().asInstanceOf[T]
}
def string2trait[T: TypeTag : ClassTag]: Map[JsValue, T] = {
val clazz = typeOf[T].typeSymbol.asClass
clazz.knownDirectSubclasses.map { sc =>
val objectName = sc.toString.stripPrefix("object ")
(JsString(objectName), objectBy[T](objectName))
}.toMap
}
class ObjectJsonReader[T: TypeTag : ClassTag] extends JsonReader[T] {
val string2T: Map[JsValue, T] = string2trait[T]
def defaultValue: T = deserializationError(s"${ implicitly[ClassTag[T]].runtimeClass.getCanonicalName } expected")
override def read(json: JsValue): T = string2T.getOrElse(json, defaultValue)
}
}
그런 다음 다음과 같이 사용할 수 있습니다.
import OrderType._
import OrderStatus._
JsString("MARKET").convertTo[OrderType]
JsString(OrderStatus.Cancelled.toString).convertTo[OrderStatus]
또한 spray-json github 문제의 코드를 시도했으며 다음과 같이 사용할 수 있습니다.
implicit val orderTypeJsonFormat: RootJsonFormat[OrderType] = caseObjectJsonFormat(MARKET, LIMIT, STOP, MARKET_IF_TOUCHED, TAKE_PROFIT, STOP_LOSS, TRAILING_STOP_LOSS)
안타깝게도 모든 객체를 명시 적으로 지정해야합니다. 당신이 그렇게하고 싶다면, 내 첫 번째 제안 (반성없이)이 더 낫다고 생각합니다. (반사가 없기 때문에 :-))
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다