Scala 从层次结构接收对象列表的端点

Scala 从层次结构接收对象列表的端点,scala,akka,json-deserialization,akka-http,circe,Scala,Akka,Json Deserialization,Akka Http,Circe,Akka Http中的端点如下所示: pathPrefix("somePath" / Segment) { someData => post { entity(as[SMS]) { sms => // some code here ... complete(StatusCodes.OK) } } } SMS的定义为: sealed trait Message case class SMS(numFrom: Stri

Akka Http中的端点如下所示:

pathPrefix("somePath" / Segment) { someData =>
  post {
    entity(as[SMS]) { sms =>
      // some code here ...
      complete(StatusCodes.OK)
    }
  }
}
SMS的定义为:

sealed trait Message
case class SMS(numFrom: String, message:String) extends Message
case class Email(emailFrom: String, message: String) extends Message
如果我想收到短信列表,我可以执行以下操作:

type SMSList = List[SMS]
...

pathPrefix("somePath" / Segment) { someData =>
  post {
    entity(as[SMSList]) { listOfSMSs =>
      // some code here ...
      complete(StatusCodes.OK)
    }
  }
}
如果我想同时收到SMS和电子邮件列表,该怎么办? 我试过这个,但没用:

type MessageList = List[Message]

pathPrefix("somePath" / Segment) { someData =>
  post {
    entity(as[MessageList]) { listOfMessages =>
      // some code here ...
      complete(StatusCodes.OK)
    }
  }
}
是否可以接收属于同一层次结构的对象列表

图书馆:

circe = 0.13.0
heikoseeberger = 1.35.3
akka http = 10.2.3
Json:

[ {numForm:123 456,message:sms message}, {电邮地址:some@mail.com,电子邮件} ]
假设您使用的是akka http-spray json中的默认一个json序列化库,那么您在根据代码和源代码组合多个json读取器时会受到很大限制。您所能做的最好的事情可能是手动编写一些格式化程序,或者只是为消息编写读取器

我还建议您看看这个库,它的代码更易于组合。它也很容易与akka http集成

更新1:指定精确库后:

有几个选择:

合并几个解码器

  import io.circe.generic.auto._
  import io.circe.{Decoder, HCursor}

  class CirceExample extends App {

    sealed trait Message

    case class SMS(numFrom: String, message: String) extends Message

    case class Email(emailFrom: String, message: String) extends Message

    val smsDecoder = implicitly[Decoder[SMS]]
    val emailDecoder = implicitly[Decoder[Email]]

    val messageDecoder: Decoder[Message] = (c: HCursor) => smsDecoder(c).orElse(emailDecoder(c))
  }
这很容易实现,因为解码器的解码结果为

创建自定义解码器,明确检查所需字段-。这种方法有点类似于前面使用spray json的示例

更新2:

import cats.syntax.functor._
import io.circe.Decoder
import io.circe.generic.auto._
import io.circe.parser._

object CirceExample extends App {

  sealed trait Message

  case class SMS(numFrom: String, message: String) extends Message

  case class Email(emailFrom: String, message: String) extends Message

  implicit val messageDecoder: Decoder[Message] = List[Decoder[Message]](Decoder[SMS].widen, Decoder[Email].widen).reduceLeft(_ or _)
  // or without list..
  //implicit val messageDecoder: Decoder[Message] = Decoder[SMS].widen or Decoder[Email].widen

  val payload = """[{"emailFrom":"a","message":"b"}]"""
  val result = decode[List[Message]](payload)
  println(result)
}

假设您使用的是akka http-spray json中的默认一个json序列化库,那么您在根据代码和源代码组合多个json读取器时会受到很大限制。您所能做的最好的事情可能是手动编写一些格式化程序,或者只是为消息编写读取器

我还建议您看看这个库,它的代码更易于组合。它也很容易与akka http集成

更新1:指定精确库后:

有几个选择:

合并几个解码器

  import io.circe.generic.auto._
  import io.circe.{Decoder, HCursor}

  class CirceExample extends App {

    sealed trait Message

    case class SMS(numFrom: String, message: String) extends Message

    case class Email(emailFrom: String, message: String) extends Message

    val smsDecoder = implicitly[Decoder[SMS]]
    val emailDecoder = implicitly[Decoder[Email]]

    val messageDecoder: Decoder[Message] = (c: HCursor) => smsDecoder(c).orElse(emailDecoder(c))
  }
这很容易实现,因为解码器的解码结果为

创建自定义解码器,明确检查所需字段-。这种方法有点类似于前面使用spray json的示例

更新2:

import cats.syntax.functor._
import io.circe.Decoder
import io.circe.generic.auto._
import io.circe.parser._

object CirceExample extends App {

  sealed trait Message

  case class SMS(numFrom: String, message: String) extends Message

  case class Email(emailFrom: String, message: String) extends Message

  implicit val messageDecoder: Decoder[Message] = List[Decoder[Message]](Decoder[SMS].widen, Decoder[Email].widen).reduceLeft(_ or _)
  // or without list..
  //implicit val messageDecoder: Decoder[Message] = Decoder[SMS].widen or Decoder[Email].widen

  val payload = """[{"emailFrom":"a","message":"b"}]"""
  val result = decode[List[Message]](payload)
  println(result)
}

这里有几个步骤,所以我会尽量保持简单

首先,我们需要定义电子邮件和短信的编码器和解码器:

我在链接中发现了这一点,之前的所有尝试都没有成功

我们继续吧。我们必须在一个单独的模块中找到它。否则,我们将获得enable macro paradise以展开宏注释错误。在阅读了post(基本上解释了宏不能在同一个模块中声明和使用)之后,我将上面的代码移到了另一个模块中,这使得代码可以编译

在使用上述代码创建了一个单独的模块之后,我们需要定义一个新模块,以依赖于第一个模块

现在,在最后一个模块中,我们需要首先导入:

import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport.unmarshaller
然后我们可以创建一条路线:

val routes = pathPrefix("somePath" / Segment) { someData =>
  post {
    entity(as[List[Message]]) { listOfMessages =>
      // some code here ...
      complete(StatusCodes.OK)
    }
  }
}

这里有几个步骤,所以我会尽量保持简单

首先,我们需要定义电子邮件和短信的编码器和解码器:

我在链接中发现了这一点,之前的所有尝试都没有成功

我们继续吧。我们必须在一个单独的模块中找到它。否则,我们将获得enable macro paradise以展开宏注释错误。在阅读了post(基本上解释了宏不能在同一个模块中声明和使用)之后,我将上面的代码移到了另一个模块中,这使得代码可以编译

在使用上述代码创建了一个单独的模块之后,我们需要定义一个新模块,以依赖于第一个模块

现在,在最后一个模块中,我们需要首先导入:

import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport.unmarshaller
然后我们可以创建一条路线:

val routes = pathPrefix("somePath" / Segment) { someData =>
  post {
    entity(as[List[Message]]) { listOfMessages =>
      // some code here ...
      complete(StatusCodes.OK)
    }
  }
}

哎呀,我忘了提到库:circe0.13.0和heikoseeberger 1.35.3,akka http 10.2.3这对你有帮助吗?谢谢你,但我认为这是一个不同的问题。在代码中可以看到{\n某物:…}。这是一个不同的输入,我没有字符串。我已经用调用的json更新了文本。如果我错了,请纠正我哦,我忘了提到库:circe0.13.0和heikoseeberger 1.35.3,akka http 10.2.3这对您有帮助吗?谢谢你,但我认为这是一个不同的问题。在代码中可以看到{\n某物:…}。这是一个不同的输入,我没有字符串。我已经用调用的json更新了文本。如果我错了,请纠正我。我忘了提到我正在使用哪些库,事实上我正在使用circe。我无法让它工作。我将代码改编为我的示例,我创建了带有编码器的对象消息,导入了它,但它不起作用……它应该起作用,因为circe中的解码器是可组合的。也就是说,若您声明List[Message],circe将为List使用现有的预定义解码器,并将为Message搜索隐式解码器。或者,您可以显式指定所有解码器。你应该检查解码器的分辨率。在Intellij Idea中,您可以通过查看->显示隐式提示菜单来执行此操作。如果你把它贴出来会很有帮助
e这里有错误。@M.G.好的,你说得对,它不起作用。详细情况和你的案子都在这里。添加了关于其外观的更新。请注意明确指定要使用的解码器。哦,第二次更新非常有效!!非常感谢你!!我忘了提到我正在使用哪些库,事实上我正在使用circe。我无法让它工作。我将代码改编为我的示例,我创建了带有编码器的对象消息,导入了它,但它不起作用……它应该起作用,因为circe中的解码器是可组合的。也就是说,若您声明List[Message],circe将为List使用现有的预定义解码器,并将为Message搜索隐式解码器。或者,您可以显式指定所有解码器。你应该检查解码器的分辨率。在Intellij Idea中,您可以通过查看->显示隐式提示菜单来执行此操作。如果您在此处发布错误,这将很有帮助。@M.G.好的,您是对的,它不起作用。详细情况和你的案子都在这里。添加了关于其外观的更新。请注意明确指定要使用的解码器。哦,第二次更新非常有效!!非常感谢你!!我尝试了你的代码,但没有编译,我必须为SMS和电子邮件案例类定义隐式编解码器。然后,它工作得很好,但只接受一个对象,它不适用于entityas[List[Message]]{……此外,这是一个很好的代码我尝试了你的代码,但没有编译,我必须为SMS和电子邮件案例类定义隐式编解码器。然后,它工作得很好,但只接受一个对象,它不适用于entityas[List[Message]]{…除此之外,这是一个很好的代码