如何创建自己的自定义转换
问题描述:
类
我有一个非常普通的消息对象,我得到一个队列就像回到:如何创建自己的自定义转换
case class Message(key: String, properties: Map[String, String])
然后我有一堆代表的消息非常具体的类,我使用properties.get(“类型”),以确定它是特定消息:
sealed trait BaseMessage
case class LoginMessage(userId: Int, ....) extends BaseMessage
case class RegisterMessage(email: String, firstName: String, ....) extends BaseMessage
现在在我的代码,我不得不从通用消息转换为在许多地方一个特定的消息,我想创建此在一个地方如:
目前,我做这样的事情:
val m = Message(....)
val myMessage = m.properties.get("type") match {
case Some("login") => LoginMessage(m.properties("userID"), ...)
case ...
}
我必须在作出这一阶不太麻烦什么选择?
答
您可以将properties
地图转换为Json并将其作为案例类读取。假设键映射具有相同的名称为您的案件类字段,你可以使用playjson写格式化:
object LoginMessage {
implicit val fmtLoginMessage = Json.format[LoginMessage]
}
如果字段不具有相同的名称,你将不得不手动指定的读取对象。您的代码将其转换成一个案例类会是这样的:
object BaseMessageFactory {
def getMessage(msg: Message): Option[BaseMessage] = {
val propertiesJson = Json.toJson(msg.properties)
msg.properties.get("type").map {
case "login" => propertiesJson.as[LoginMessage]
...
case _ => //Some error
}
}
}
签名可能取决于您希望如何处理错误处理不同。
答
我不知道你在这里的所有情况,但我可以建议使用隐式转换,如果你不想在你的项目中带来另一个库。无论如何,隐式转换可以帮助您分离很多实现,或根据需要“实时”覆盖它。
我们可以通过定义一个MessageConverter
特征,实际上是一个函数开始:
/**
* Try[T] here is useful to track deserialization errors. If you don't need it you can use Option[T] instead.
*/
trait MessageConverter[T <: BaseMessage] extends (Message => Try[T])
现在定义是同时拥有的实现目标,也实现了不错的#as[T]
方法上Message
实例:
object MessageConverters {
/**
* Useful to perform conversions such as:
* {{{
* import MessageConverters._
*
* message.as[LoginMessage]
* message.as[RegisterMessage]
* }}}
*/
implicit class MessageConv(val message: Message) extends AnyVal {
def as[T <: BaseMessage : MessageConverter]: Try[T] =
implicitly[MessageConverter[T]].apply(message)
}
// Define below message converters for each particular type
implicit val loginMessageConverter = new MessageConverter[LoginMessage] {
override def apply(message: Message): Try[LoginMessage] = {
// Parse the properties and build the instance here or fail if you can't.
}
}
}
就是这样!它可能不是最好的解决方案,因为这会带来复杂性,并使代码难以遵循。但是,如果您遵循一个定义良好的结构来存储这些隐式值,并小心如何传递它们,那么您就不应该有任何问题。
不使用'Map [String,String]'来存储初学者的任意属性。恢复这些信息并不容易。 –
无形可能可以帮助,如果你想保持类型安全 – LMeyer
@MichaelZajac该类是从消息队列系统,不能改变。 – Blankman