akka-http custom PathMatcher - scala

Many of directives (e.g., parameters) gives very convenient unmarshalling mechanism.
But I failed to find similar DSL for the Path Matcher from the documentation.
I thought that given proper Unmarshaller, I would something like below,
implicit val userStatusUnmarshaller: FromStringUnmarshaller[UserStatus] = ???
val route = path("user" / Segment.as[UserStatus]) { status: UserStatus =>
...
}
expecially when the custom unmarshalling result is Enumeration.
Do they give such a way but I couldn't find or is there another way to do the same thing?

You can flatMap segment to UserStatus like so:
Segment.flatMap(UserStatus.fromString)
fromString should return Option[UserStatus]

What about implicitly extend PathMatcher1[String] asking for something String => Option[T].
implicit class PimpedSegment(segment: PathMatcher1[String]) {
def as[T](implicit asT: String => Option[T]): PathMatcher1[T] =
segment.flatMap(asT)
}
For example you could implicitly require a JsonReader[T]:
implicit class JsonSegment(segment: PathMatcher1[String]) {
def as[T: JsonReader]: PathMatcher1[T] = segment.flatMap { string =>
Try(JsString(string).convertTo[T]).toOption
}
}
Then it can be used as Segment.as[UserStatus].

Related

Get a Type from a String

I am trying to switch my code to a component-oriented design.
My point of contention is the following function do() which matches its s argument with some priorily known Strings and calls compute() with the adequate type parameter.
def do(s: String, summoner: Summoner): String = {
s match {
case "a" => summoner.compute[Type_A](outOfScopeVal)
case "b" => summoner.compute[Type_B](outOfScopeVal)
case _ => ""
}
}
I would like to transpose it to a generic trait that can be extended if any new Type_x is required.
[EDIT] It would be a library that external developers can enrich at will, adding a new match between a String identifier and a type.
[EDIT2] I call a library defined like the following:
trait TypeHolder[T <: Type_top] {def score(...): String}
object Converters {
implicit object ConverterOfA extends TypeHolder[Type_A] {
def convertAndMore(...): String = {
/*
compute and return a String
*/
}
}
implicit object ConverterOfB extends TypeHolder[Type_B] {
def convertAndMore(...): String = {
/*
compute and return a String
*/
}
}
}
case class Summoner(...) {
def compute[T <: Type_top](...)(implicit summoner: TypeHolder[T]): String = {
summoner.convertAndMore(...)
}
}
This problem can be reduced to getting a generic tool that returns (some kind of) a type based on an input String.
This question: https://stackoverflow.com/a/23836385/3896166, nears the expected solution but I can not match the requirement of "know[ing] the type of object mapping names ahead of time" as the input String is received dynamically...
Also, Shapeless might be the path to follow, but I merely started going down that path.
Is it even possible?
You could solve this by converting a String to a type (if that were possible), but it is not the only way of solving your underlying problem. (This is therefore an XY question)
Instead, you need to build a Map that takes you from the String to a method that computes the appropriate function. It might work something like this:
def computeFn[T <: Type_top] =
(summoner: Summoner, value: ???) => summoner.compute[T](value)
val computeMap = Map(
"a" -> computeFn[Type_A],
"b" -> computeFn[Type_B]
)
def do(s: String, summoner: Summoner): String =
computeMap(s)(summoner, outOfScopeVal)
It should be straightforward to adapt this so that subclasses can add to the computeMap object in order to define their own mappings.

How to create my own custom converts class

I have a very generic message object that I get back from a queue like:
case class Message(key: String, properties: Map[String, String])
I then have a bunch of very specific classes that represent a message, and I use properties.get("type") to determine which particular message it is:
sealed trait BaseMessage
case class LoginMessage(userId: Int, ....) extends BaseMessage
case class RegisterMessage(email: String, firstName: String, ....) extends BaseMessage
Now in my code I have to convert from a generic Message to a particular message in many places, and I want to create this in a single place like:
Currently I am doing something like:
val m = Message(....)
val myMessage = m.properties.get("type") match {
case Some("login") => LoginMessage(m.properties("userID"), ...)
case ...
}
What options do I have in making this less cumbersome in scala?
I don't know all your context here, but I can suggest using implicit conversions if you don't want to bring another library in your project. Anyway, implicit conversions can help you separate a lot the implementation or override it "on-the-fly" as needed.
We can start by defining a MessageConverter trait that is actually a function:
/**
* 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])
Now define an object that holds both the implementations and also enables a nice #as[T] method on Message instances:
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.
}
}
}
That's it! It may not be the best solution as implicits bring complexity and they make code harder to follow. However, if you follow a well-defined structure for storing these implicit values and be careful how you pass them around, then you shouldn't have any issues.
You can convert the properties map to Json and read it as a case class. Assuming that the keys to the map have the same name as your case class fields you can write a formatter using playjson:
object LoginMessage {
implicit val fmtLoginMessage = Json.format[LoginMessage]
}
If the fields don't have the same name you will have to specify the reads object manually. Your code to convert it into a case class would be something like:
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
}
}
}
The signature may differ depending on how you want to deal with error handling.

How to override the toString() method on JS objects to use JSON.stringify()?

I'm tired of writing blah: "${JSON.stringify(target)}" when I deal with my DTO objects, I just want to write blah: "$target".
My DTOs look like:
#js.native
trait AuthConnectionDetails extends js.Object {
def clientId: String = js.native
def accountHostname: String = js.native
}
These DTOs are used to parse the content of some REST API calls, like:
val response = js.JSON.parse(xmlHttpRequest.responseText).
asInstanceOf[AuthConnectionDetails]
I don't mind changing how I define my DTO objects to do this (maybe I should be using case classes for my DTOs or something, instead of native js traits?), but I can't figure out how to do it.
I tried writing a trait that I could mixin, but that didn't work and I tried writing an implicit extension method but that didn't work either.
My implicit code that didn't seem to work for toString:
object JsonToString {
implicit class JsObjectExtensions(val target: js.Object) extends AnyVal {
override def toString:String = JSON.stringify(target)
def json:String = JSON.stringify(target)
}
}
So I can do blah: "${target.json}", which is better - but I'd especially like to get rid of those braces.
Is there any way to do this with scala.js?
No, there is no way to do this. That's because string interpolation will always use the toString() method of the object itself, no matter what is declared in its types or in implicit classes (this is a Scala thing in general).
The only way you could achieve this would be to actually modify the objects by patching them up with a custom toString() method every time you create one. That would include when you parse them from a JSON string. I'm pretty sure that would be worse than calling .json when you stringify them.
If you really want to, you could write your custom string interpolator:
implicit class JsonHelper(private val sc: StringContext) extends AnyVal {
def dejson(args: Any*): JSONObject = {
sc.checkLengths(args)
s(args.map(jsonify))
}
private def jsonify(arg: Any) = arg match {
case obj: js.Object => JSON.stringify(obj)
case _ => arg.toString
}
}
You can now use this like this:
dejson"hello: $target, world: $target2"

How do I pass ParseResults to other methods?

void whatever() {
// ...
val parser = new MyParser
val parse = parser.parse(input)
if (parse successful) {
semanticAnalysis(parse)
}
}
void semanticAnalysis(parse: DontKnowTheCorrectType) {
// ...
}
What type do I have to give to the formal parameter parse? Hovering over parse inside whatever says val parse: parser.ParseResult[parsing.Program], but of course that doesn't work as a parameter type of semanticAnalysis, because the local variable parse is not in scope there.
Parse results are path-dependent types because they are results of this specific parser and there's no guarantee they are compatible.
This is why parsers are usually not instantiated the way you use them (new MyParser), but as object.
object MyParser extends RegexParsers {
def statements : Parser[List[Statement]] = // ...
}
def handleResult(res: MyParser.ParseResult[List[Statement]]) = { // ... }
val res = MyParser.parseAll(MyParser.statements, "/* */")
If you need more dynamic behaviour (or want concurrent parsing, parser combinators aren't thread-safe, ouch), you'll just have to keep the parser object accessible (and stable) wherever you want to use its results.
Sadly, passing a parser and its result around together is not trivial because you run into the prohibition of dependent method types, e.g.
def fun(p: scala.util.parsing.combinator.Parsers, res: p.ParseResult[_]) = {}
won't compile ("illegal dependent method type"), but there are ways to get around that if you must, like the answer to this question.
You should be able to define semanticAnalysis as:
def semanticAnalysis(parse: MyParser#ParseResult[parsing.Program]) = {
...
}
Note the use of # instead of . for the type. There are more details about type projections here, but basically, parser.ParseResult is different for each parser, while MyParser#ParseResult is the same for all parser instances.
But, as themel says, you should probably be using object instead of class.
You can rewrite it like this:
def whatever() {
// ...
val parser = new MyParser
def semanticAnalysis(parse: parser.ParseResult) {
// ...
}
val parse = parser.parse(input)
if (parse successful) {
semanticAnalysis(parse)
}
}
If you have this being called from multiple places, then maybe this:
class SemanticAnalysis(parser: Parser) {
def apply(parse: parser.ParseResult) {
// ...
}
}
And then
if (parse successful) {
new SemanticAnalysis(parser)(parse)
}
When I need to use the result of parser combinators in other parts of a program, I extract the success result or error message from the path-dependent ParseResult and put the data into an independent type. It's more verbose than I like, but I want to keep the combinator instance an implementation detail of the parser.
sealed abstract class Result[+T]
case class Success[T](result: T) extends Result[T]
case class Failure(msg: String) extends Result[Nothing]
case class Error(msg: String) extends Result[Nothing]
/** Parse the package declarations in the file. */
def parse(file: String): Result[List[Package]] = {
val stream = ... // open the file...
val parser = new MyParser
val result = parser.parseAll(parser.packages, stream)
stream.close()
result match {
case parser.Success(packages, _) => Success(packages)
case parser.Failure(msg, _) => Failure(msg)
case parser.Error(msg, _) => Error(msg)
}
}

Any way to access the type of a Scala Option declaration at runtime using reflection?

So, I have a Scala class that looks like this:
class TestClass {
var value: Option[Int] = None
}
and I'm tackling a problem where I have a String value and I want to coerce it into that Option[Int] at runtime using reflection. So, in another piece of code (that knows nothing about TestClass) I have some code like this:
def setField[A <: Object](target: A, fieldName: String, value: String) {
val field = target.getClass.getDeclaredField(fieldName)
val coercedValue = ???; // How do I figure out that this needs to be Option[Int] ?
field.set(target, coercedValue)
}
To do this, I need to know that the field is an Option and that the type parameter of the Option is Int.
What are my options for figuring out that the type of 'value' is Option[Int] at runtime (i.e. using reflection)?
I have seen similar problems solved by annotating the field, e.g. #OptionType(Int.class). I'd prefer a solution that didn't require annotations on the reflection target if possible.
It's quite streightforward using Java 1.5 reflection API:
def isIntOption(clasz: Class[_], propertyName: String) = {
var result =
for {
method <- cls.getMethods
if method.getName==propertyName+"_$eq"
param <- method.getGenericParameterTypes.toList.asInstanceOf[List[ParameterizedType]]
} yield
param.getActualTypeArguments.toList == List(classOf[Integer])
&& param.getRawType == classOf[Option[_]]
if (result.length != 1)
throw new Exception();
else
result(0)
}
At the byte code level, Java hasn't got Generics. Generics are implemented with polymorphism, so once your source code (in this case Scala) is compiled, generic types disappear (this is called type erasure ). This makes no possible to gather Generic runtime type information via reflection.
A possible --though little dirty-- workaround is to obtain the runtime type of a property you know it has the same type as the Generic parameter. For Option instances we can use get member
object Test {
def main(args : Array[String]) : Unit = {
var option: Option[_]= None
println(getType(option).getName)
option = Some(1)
println(getType(option).getName)
}
def getType[_](option:Option[_]):Class[_]= {
if (option.isEmpty) classOf[Nothing] else (option.get.asInstanceOf[AnyRef]).getClass
}
}
class TestClass {
var value: Option[Int] = None
// ...
def doSomething {
value match {
case Some(i) => // i is an Int here
case None =>
// No other possibilities
}
}
}
The problem is that JVM implements generics through type erasure. So it's impossible to discover through reflection that the type of value is Option[Int] because at the run-time it actually isn't: it's just Option!
In 2.8 you should be able to use Manifests like this:
var value: Option[Int] = None
val valueManifest = implicitly[scala.reflect.Manifest[Option[Int]]]
valueManifest.typeArguments // returns Some(List(Int))