All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sbuslab.http.directives.JsonMarshallers.scala Maven / Gradle / Ivy

package com.sbuslab.http.directives

import scala.reflect.ClassTag

import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller, ToResponseMarshaller}
import akka.http.scaladsl.model._
import akka.http.scaladsl.server._
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, FromRequestUnmarshaller, Unmarshaller}
import akka.util.ByteString
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.databind.ObjectMapper

import com.sbuslab.model.{BadRequestError, SecureString, SecureStringSerializer}
import com.sbuslab.utils.JsonFormatter
import com.sbuslab.utils.json.FacadeAnnotationIntrospector


object JsonMarshallers {
  private lazy val writerMapper: ObjectMapper = {
    val m = JsonFormatter.mapper.copy()
    m.setConfig(m.getSerializationConfig.withAppendedAnnotationIntrospector(new FacadeAnnotationIntrospector))

    val secureStringModule = new SimpleModule("SecureStringModule")
    secureStringModule.addSerializer(classOf[SecureString], new SecureStringSerializer())
    m.registerModule(secureStringModule)
  }
}


trait JsonMarshallers extends Directives {

  import JsonMarshallers._

  private val jsonStringUnmarshaller =
    Unmarshaller.byteStringUnmarshaller
      .mapWithCharset {
        case (ByteString.empty, _) ⇒ throw Unmarshaller.NoContentException
        case (data, charset)       ⇒ data.decodeString(charset.nioCharset.name)
      }

  implicit protected def unmarshaller[A](implicit ct: ClassTag[A]): FromEntityUnmarshaller[A] =
    jsonStringUnmarshaller.map(data ⇒ JsonFormatter.mapper.readValue(data, ct.runtimeClass).asInstanceOf[A])

  implicit protected val JsonMarshaller: ToEntityMarshaller[Any] =
    Marshaller.opaque[Any, MessageEntity] { m ⇒
      HttpEntity.Strict(ContentTypes.`application/json`, ByteString(writerMapper.writeValueAsBytes(m)))
    }

  implicit protected val StatusCodeMarshaller: ToResponseMarshaller[StatusCode] =
    Marshaller.opaque[StatusCode, HttpResponse] { status ⇒
      HttpResponse(status = status, entity = if (status.allowsEntity()) HttpEntity(ContentTypes.`application/json`, "{}") else HttpEntity.Empty)
    }

  implicit protected val UnitMarshaller: ToEntityMarshaller[Unit] =
    Marshaller.opaque[Unit, MessageEntity](_ ⇒ HttpEntity.Empty)

  implicit protected val VoidMarshaller: ToEntityMarshaller[Void] =
    Marshaller.opaque[Void, MessageEntity](_ ⇒ HttpEntity.Empty)


  /**
   * Filter by Content-Type header
   */
  def contentType[T](contentType: String): Directive0 =
    extract(_.request.entity) flatMap {
      case e if e.contentType.value equalsIgnoreCase contentType ⇒ pass
      case _ ⇒ reject(UnsupportedRequestContentTypeRejection(Set(MediaType.custom(contentType, binary = false)), None))
    }

  override def entity[T](um: FromRequestUnmarshaller[T]): Directive1[T] =
    mapRejections(rs ⇒ if (rs.nonEmpty) throw new BadRequestError(rs.mkString("; ")) else rs).tflatMap { _ ⇒
      super.entity(um)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy