I am using a spray-routing which is pretty elegant with using symbols for parameters. However I am dealing with some legacy code and need to use java enum. Is there some elegant way how to convert scala symbol to java enum?
So the desired code would look as follows:
post {
parameters(('adId.as[String], 'propertyType.as[TypNe])).as(Import) { imp:Import =>
complete {
adImporterService ! imp
StatusCodes.Accepted
}
}
where TypNem is java enum and Import is a scala case class. Instead of
post {
parameters(('adId.as[String], 'propertyType.as[String])) { (aId,pType) =>
complete {
adImporterService ! Import(aId,TypNe.valueOf(pType.toUpperCase()))
StatusCodes.Accepted
}
}
}
For Java Enum PropertyType
public enum PropertyType {
AAA, BBB, CCC
}
You need to provide custom Deserializer
implicit val propertyTypeDeserializer =
new Deserializer[String, PropertyType] {
def apply(s: String): Deserialized[PropertyType] = {
Try(PropertyType.valueOf(s)) match {
case Success(pt) =>
Right(pt)
case Failure(err) =>
Left(MalformedContent("Wrong property type. Accepted values: ${PropertyType.values}", Some(err)))
}
}
}
def receive: Receive = runRoute {
path("test") {
parameter('prop.as[PropertyType]) { case prop =>
get {
complete(s"Result: $prop. Class: ${prop.getClass}")
}
}
}
}
Solution from #Dici also works and much smaller, but with custom Deserializer you are more flexible with error handling
You can use an implicit declaration to improve the readability :
implicit def strToTypeNe = TypNe.valueOf(pType.toUpperCase())
Related
This is my kotlin class:
class example {
var a = 0
fun add(b: Int, callback: (Int) -> Unit){
a += b
callback(a)
}
}
How do I use this function in a java code?
Edit:
As #Drawn Raccoon mentioned in the comments, you can call the add method from java code simply by returning Unit.INSTANCE:
Java:
example e = new example();
e.add(16, a -> {
// do some work with 'a'
return Unit.INSTANCE;
});
Or call it from kotlin without returning any value:
Kotlin:
add(16) {
a -> // do some work with 'a'
}
Not correct(for correct answer refer to Edit section):
I think you can't use Unit type for output type of callback that will be called from java code. Unit is not recognized in Java.
Instead you can use Void? (I don't know about 'Void' and now I can't test it).
Code in kotlin:
class example {
var a = 0
fun add(b: Int, callback: (Int) -> Void?){
a += b
callback(a)
}
}
And calling it from java:
example e = new example();
e.add(16, a -> {
// do some work with 'a'
return null;
})
And call from kotlin:
val example = example()
e.add(16, { a ->
// do some work with 'a'
null
})
[ In addition, the 'example' is not a good name for kotlin or java classes and try to use upper case, like 'Example' ]
I have a method which converts a string to an int and a Java enum to an int. For other data types, it doesn't do any conversion.
def myConverter[T](attributeValue: T) = {
if (attributeValue.isInstanceOf[String]) {
attributeValue.asInstanceOf[String].toInt
} else if (attributeValue.isInstanceOf[Enumeration$Value]) {
CodeReferenceEx.toInteger(attributeValue.asInstanceOf[Enumeration$Value])
} else {
attributeValue
}
}
The method never enters the elseif block (Enumeration$Value) because the condition is always evaluated to false. I am using a java enumeration object.
Does anyone have any idea? Thanks
Given a Java enum:
public enum C {
ONE, TWO
}
And a Scala enum:
object E extends Enumeration {
val A = Value
}
The following works for both:
def myConverter[T](attributeValue: T) = {
attributeValue match {
case str: String =>
str.toInt
case _: Enumeration =>
println("Scala Enum!")
case _: Enumeration#Value =>
println("Scala Enumeration Value!")
case _ if attributeValue.getClass.isEnum =>
println("Java Enum!")
case _ => println("oops")
}
}
def main(args: Array[String]): Unit = {
myConverter(E)
myConverter(E.A)
myConverter(C.ONE)
}
Yields:
Scala Enum!
Scala Enumeration Value!
Java Enum!
For java enum cast to java.lang.Enum
Assume Scala 2.11. I'm writing a class that will persist a Scala value. It's intention is to be used as such:
class ParentClass {
val instanceId: String = "aUniqueId"
val statefulString: Persisted[String] = persisted { "SomeState" }
onEvent {
case NewState(state) => statefulString.update(state)
}
}
Persisted is a class with a type parameter that is meant to persist that specific value like a cache, and Persist handles all of the logic associated with persistence. However, to simply the implementation, I'm hoping to retrieve information about it's instantiation. For example, if it's instance in the parent class is named statefulString, how can I access that name from within the Persisted class itself?
The purpose of doing this is to prevent collisions in automatic naming of persisted values while simplifying the API. I cannot rely on using type, because there could be multiple values of String type.
Thanks for your help!
Edit
This question may be helpful: How can I get the memory location of a object in java?
Edit 2
After reading the source code for ScalaCache, it appears there is a way to do this via WeakTypeTag. Can someone explain what exactly is happening in its macros?
https://github.com/cb372/scalacache/blob/960e6f7aef52239b85fa0a1815a855ab46356ad1/core/src/main/scala/scalacache/memoization/Macros.scala
I was able to do this with the help of Scala macros and reflection, and adapting some code from ScalaCache:
class Macros(val c: blackbox.Context) {
import c.universe._
def persistImpl[A: c.WeakTypeTag, Repr: c.WeakTypeTag](f: c.Tree)(keyPrefix: c.Expr[ActorIdentifier], scalaCache: c.Expr[ScalaCache[Repr]], flags: c.Expr[Flags], ec: c.Expr[ExecutionContext], codec: c.Expr[Codec[A, Repr]]) = {
commonMacroImpl(keyPrefix, scalaCache, { keyName =>
q"""_root_.persistence.sync.caching($keyName)($f)($scalaCache, $flags, $ec, $codec)"""
})
}
private def commonMacroImpl[A: c.WeakTypeTag, Repr: c.WeakTypeTag](keyPrefix: c.Expr[ActorIdentifier], scalaCache: c.Expr[ScalaCache[Repr]], keyNameToCachingCall: (c.TermName) => c.Tree): Tree = {
val enclosingMethodSymbol = getMethodSymbol()
val valNameTree = getValName(enclosingMethodSymbol)
val keyName = createKeyName()
val scalacacheCall = keyNameToCachingCall(keyName)
val tree = q"""
val $keyName = _root_.persistence.KeyStringConverter.createKeyString($keyPrefix, $valNameTree)
$scalacacheCall
"""
tree
}
/**
* Get the symbol of the method that encloses the macro,
* or abort the compilation if we can't find one.
*/
private def getValSymbol(): c.Symbol = {
def getValSymbolRecursively(sym: Symbol): Symbol = {
if (sym == null || sym == NoSymbol || sym.owner == sym)
c.abort(
c.enclosingPosition,
"This persistence block does not appear to be inside a val. " +
"Memoize blocks must be placed inside vals, so that a cache key can be generated."
)
else if (sym.isTerm)
try {
val termSym = sym.asInstanceOf[TermSymbol]
if(termSym.isVal) termSym
else getValSymbolRecursively(sym.owner)
} catch {
case NonFatal(e) => getValSymbolRecursively(sym.owner)
}
else
getValSymbolRecursively(sym.owner)
}
getValSymbolRecursively(c.internal.enclosingOwner)
}
/**
* Convert the given method symbol to a tree representing the method name.
*/
private def getValName(methodSymbol: c.Symbol): c.Tree = {
val methodName = methodSymbol.asMethod.name.toString
// return a Tree
q"$methodName"
}
private def createKeyName(): TermName = {
// We must create a fresh name for any vals that we define, to ensure we don't clash with any user-defined terms.
// See https://github.com/cb372/scalacache/issues/13
// (Note that c.freshName("key") does not work as expected.
// It causes quasiquotes to generate crazy code, resulting in a MatchError.)
c.freshName(c.universe.TermName("key"))
}
}
I'm trying to update some of my old Scala code to new APIs.
In one of the libraries I use, a case class has been converted to a simple POJO for compatibility reasons.
I was wondering if it is still possible somehow to use pattern matching for the Java class.
Imagine I have a simple Java class like:
public class A {
private int i;
public A(int i) {
this.i = i;
}
public int getI() {
return i;
}
}
After compilation, I would like to use it in pattern matching somehow like:
class Main extends App {
val a = ...
a match {
case _ # A(i) =>
println(i);
}
}
For the code above, I obviously get an error: Main.scala:7: error: object A is not a case class constructor, nor does it have an unapply/unapplySeq method.
Is there any trick I could use here?
Thanks in advance!
It's a little late in the night here for subtlety, but
object `package` {
val A = AX
}
object AX {
def unapply(a: A): Option[Int] = Some(a.getI)
}
object Test extends App {
Console println {
new A(42) match {
case A(i) => i
}
}
}
Write unapply yourself:
object A {
def unapply(x: A) = Some(x.getI)
}
#som-snytt's answer is correct - but if you are doing this just for e.g. pattern-matching then I prefer the more succinct approach:
import spray.httpx.{UnsuccessfulResponseException => UrUnsuccessfulResponseException}
object UnsuccessfulResponseException {
def unapply(a: UrUnsuccessfulResponseException): Option[HttpResponse]
= Some(a.response)
}
... match {
case Failure(UnsuccessfulResponseException(r)) => r
case ...
}
Ur is a pretentious way of saying "original", but it only takes two letters.
Following Scala mailing lists, different people often say: "compiler rewrites this [scala] code into this [java/scala??] code". For example, from one of the latest threads, if Scala sees
class C(i: Int = 4) { ... }
then the compiler rewrites this as (effectively):
class C(i: Int) { ... }
object C {
def init$default$1: Int = 4
}
How can I find out, what will be the compiler output for my code? Should I decompile the resulting bytecode for that?
You can use "-print" as compiler option, and scalac will remove all Scala-specific features.
For example, here is the original code:
class Main
{
def test (x: Any) = x match {
case "Hello" => println ("Hello World")
case e: String => println ("String")
case i: Int => println ("Int")
case _ => println ("Something else")
}
}
And if you use "scalac -print" to compile it, you will get the following Scala code.
[[syntax trees at end of cleanup]]// Scala source: Test.scala
package <empty> {
class Main extends java.lang.Object with ScalaObject {
def test(x: java.lang.Object): Unit = {
<synthetic> val temp1: java.lang.Object = x;
if (temp1.==("Hello"))
{
scala.this.Predef.println("Hello World")
}
else
if (temp1.$isInstanceOf[java.lang.String]())
{
scala.this.Predef.println("String")
}
else
if (temp1.$isInstanceOf[Int]())
{
scala.this.Predef.println("Int")
}
else
{
scala.this.Predef.println("Something else")
}
};
def this(): Main = {
Main.super.this();
()
}
}
}
One can look at the generated bytecode with
javap -c -private ClassNameWithoutDotClass