在Sangria中编组嵌套的自定义对象

问题描述 投票:6回答:2

我有以下输入对象:

val BusinessInputType = InputObjectType[BusinessInput]("BusinessInput", List(
    InputField("userId", StringType),
    InputField("name", StringType),
    InputField("address", OptionInputType(StringType)),
    InputField("phonenumber", OptionInputType(StringType)),
    InputField("email", OptionInputType(StringType)),
    InputField("hours", ListInputType(BusinessHoursInputType))

  ))


 val BusinessHoursInputType = InputObjectType[BusinessHoursInput]("hours",  List(
    InputField("weekDay", IntType),
    InputField("startTime", StringType),
    InputField("endTime", StringType)
  ))

以下是定制编组定义的模型:

case class BusinessInput(userId: String, name: String, address: Option[String], phonenumber: Option[String], email: Option[String], hours: Seq[BusinessHoursInput])

object BusinessInput {

  implicit val manual = new FromInput[BusinessInput] {
    val marshaller = CoercedScalaResultMarshaller.default

    def fromResult(node: marshaller.Node) = {
      val ad = node.asInstanceOf[Map[String, Any]]

      System.out.println(ad)
      BusinessInput(
        userId = ad("userId").asInstanceOf[String],
        name = ad("name").asInstanceOf[String],
        address = ad.get("address").flatMap(_.asInstanceOf[Option[String]]),
        phonenumber = ad.get("phonenumber").flatMap(_.asInstanceOf[Option[String]]),
        email = ad.get("email").flatMap(_.asInstanceOf[Option[String]]),
        hours = ad("hours").asInstanceOf[Seq[BusinessHoursInput]]

      )
    }
  }
}



case class BusinessHoursInput(weekDay: Int, startTime: Time, endTime: Time)

object BusinessHoursInput {

  implicit val manual = new FromInput[BusinessHoursInput] {
    val marshaller = CoercedScalaResultMarshaller.default
    def fromResult(node: marshaller.Node) = {
      val ad = node.asInstanceOf[Map[String, Any]]
      System.out.println("HEY")

      BusinessHoursInput(
        weekDay = ad("weekDay").asInstanceOf[Int],
        startTime = Time.valueOf(ad("startTime").asInstanceOf[String]),
        endTime = Time.valueOf(ad("endTime").asInstanceOf[String])
      )
    }
  }


}

我的问题是,当我有一个具有自定义编组的嵌套InputObject时,我看不到在BusinessHoursInput被编组之前调用BusinessInput的编组。我注意到了这一点,因为在“BusinessInput”中“ad”的打印语句之前,“Hey”的打印语句从未执行过。当我尝试在数据库中插入BusinessInput的小时字段时,这会导致后来的问题,因为它无法将其转换为BusinessHoursInput对象。在Sangria中,是否无法在父对象编组之前自定义Marshal嵌套对象?

scala playframework sangria
2个回答
4
投票

您可能正在使用BusinessInput作为参数类型。实际的隐式查找发生在Argument定义时间,仅适用于BusinessInput类型。

由于FromInput是基于类的类反序列化,因此需要显式定义嵌​​套对象的反序列化之间的依赖关系。例如,您可以像这样重写反序列化器:

case类BusinessInput(userId:String,name:String,address:Option [String],phonenumber:Option [String],email:Option [String],hours:Seq [BusinessHoursInput])

object BusinessInput {
  implicit def manual(implicit hoursFromInput: FromInput[BusinessHoursInput]) = new FromInput[BusinessInput] {
    val marshaller = CoercedScalaResultMarshaller.default

    def fromResult(node: marshaller.Node) = {
      val ad = node.asInstanceOf[Map[String, Any]]

      BusinessInput(
        userId = ad("userId").asInstanceOf[String],
        name = ad("name").asInstanceOf[String],
        address = ad.get("address").flatMap(_.asInstanceOf[Option[String]]),
        phonenumber = ad.get("phonenumber").flatMap(_.asInstanceOf[Option[String]]),
        email = ad.get("email").flatMap(_.asInstanceOf[Option[String]]),
        hours = hoursFromInput.fromResult(ad("hours").asInstanceOf[Seq[hoursFromInput.marshaller.Node]])
      )
    }
  }
}

在这个版本中,我利用现有的FromInput[BusinessHoursInput]从原始输入反序列化BusinessHoursInput

另外,作为替代方案,您可以通过利用现有的基于JSON的反序列化器来完全避免定义手动FromInput反序列化器。例如,在大多数情况下,circe的自动推导工作正常。您只需要这两个导入(在您定义参数的文件中):

import sangria.marshalling.circe._
import io.circe.generic.auto._

这些导入将适当的FromInput实例放入范围。这些实例利用了circe自己的反序列化机制。


0
投票
import io.circe.Decoder
import io.circe.generic.semiauto.deriveDecoder
import sangria.macros.derive.deriveInputObjectType
import sangria.marshalling.circe._
import sangria.schema.{Argument, InputObjectType}


object XXX {

  // when you have FromInput for all types in case class (Int, String) you can derive it
  case class BusinessHoursInput(weekDay: Int, startTime: String, endTime: String)

  object BusinessHoursInput {
    implicit val decoder: Decoder[BusinessHoursInput] = deriveDecoder
    implicit val inputType: InputObjectType[BusinessHoursInput] = deriveInputObjectType[BusinessHoursInput]()
  }

  // the same here, you need InputObjectType also for BusinessHoursInput
  case class BusinessInput(userId: String, name: String, address: Option[String], phonenumber: Option[String], email: Option[String], hours: Seq[BusinessHoursInput])

  object BusinessInput {
    implicit val decoder: Decoder[BusinessInput] = deriveDecoder
    implicit val inputType: InputObjectType[BusinessInput] = deriveInputObjectType[BusinessInput]()
  }

  // for this to work you need to have in scope InputType BusinessInput and FromInput for BusinessInput
  // FromInput you can get by having Decoder in scope and import sangria.marshalling.circe._
  private val businessInputArg = Argument("businessInput", BusinessInput.inputType)


}

你不使用circe而是使用不同的json库,你当然应该有不同的类型和适当的范围导入

© www.soinside.com 2019 - 2024. All rights reserved.