0

I'm using Mule ESB (Java Based) and I have some scala components that modify and create data. My Data is represented in Case Classes. I'm trying to convert them to Java, however Just getting them to convert to Scala types is a challenge. Here's a simplified example of what I'm trying to do:

package com.echostar.ese.experiment


import scala.collection.JavaConverters

case class Resource(guid: String, filename: String)
case class Blackboard(name: String, guid:String, resource: Resource)

object CCC extends App {
    val res = Resource("4alskckd", "test.file")
    val bb = Blackboard("Test", "123asdfs", res)

    val myMap = getCCParams(bb)
    val result = new java.util.HashMap[String,Object](myMap)
    println("Result:"+result)

    def getCCParams(cc: AnyRef) =
        (Map[String, Any]() /: cc.getClass.getDeclaredFields) {(a, f) =>
            f.setAccessible(true)
            val value = f.get(cc) match {
                //  this covers tuples as well as case classes, so there may be a more specific way
                case caseClassInstance: Product => getCCParams(caseClassInstance): Map[String, Any]
                case x => x
            }
            a + (f.getName -> value)
        }
}

Current Error: Recursive method needs return type.

My Scala Foo isn't very strong. I grabbed this method from another answer here and basically know what it's doing, but not enough to change this to java.util.HashMap and java.util.List

Expected Output:

Result:{"name"="Test", "guid"="123asdfs", "resource"= {"guid"="4alskckd", "filename"="test.file"}}

UPDATE1: 1. Added getCCParams(caseClassInstance): Map[String, Any] to line 22 Above per @cem-catikkas. IDE syntax error still says "recursive method ... needs result type" and "overloaded method java.util.HashMap cannot be applied to scala.collection.immutable.Map". 2. Changed java.util.HashMap[String, Object]

Community
  • 1
  • 1
dlite922
  • 1,924
  • 3
  • 24
  • 60

3 Answers3

2

You should follow what the error tells you. Since getCCParams is a recursive method you need to declare its return type.

def getCCParams(cc: AnyRef): Map[String, Any]
Cem Catikkas
  • 7,171
  • 4
  • 29
  • 33
  • Added. Compiler still says could not find or load main class and IDE still shows the same error. I don't know enough Scala to change the method return type as well. How do I change that to Map[String, Any]. Even further once this works, what's the best way to change this to java types (my original problem) – dlite922 Apr 12 '15 at 22:45
  • What do you mean "how do you change that to Map[String, Any]"? Given your method body, that is the actual return type - you just have to declare it like in the answer above. – Cem Catikkas Apr 12 '15 at 23:50
  • Case classes are just plain Java classes, so you don't need to do anything. If I'm understanding correctly what you're really trying to do is to serialize your object graph to JSON. You can use any Java JSON serializer library you want if you're not familiar with Scala. You shouldn't need to convert your object graph to HashMap. – Cem Catikkas Apr 12 '15 at 23:52
  • I meant that it still throws that error, even with your change. I may have added it in the wrong place (did you see my updated post above?) Ok, if Scala case classes are Java classes and there is a better way to translate them to a Hash map, please show me how this can be done when you get a chance. Thank you for your replies! – dlite922 Apr 13 '15 at 04:38
  • Which IDE are you using? Did your IDE compile the code after the changes? Can you try to compile from command line? – Cem Catikkas Apr 13 '15 at 07:14
2

Answering this in case anyone else going through the issue ends up here (as happened to me).

I believe the error you were getting had to do with the fact that the return type was being declared at method invocation (line 22), however the compiler was expecting it at the method's declaration (in your case, line 17). The below seems to have worked:

def getCCParams(cc: AnyRef): Map[String, Any] = ...

Regarding the conversion from Scala Map to Java HashMap, by adding the ._ wildcard to the JavaConverters import statement, you manage to import all the methods of the object as single identifiers, which is a requirement for implicit conversions. This will include the asJava method which can then be used to convert the Scala Map to a Java one, and then this can be passed to the java.util.HashMap(Map<? extends K,? extends V> m) constructor to instantiate a HashMap:

import scala.collection.JavaConverters._
import java.util.{HashMap => JHashMap}

...

val myMap = getCCParams(bb)
val r = myMap.asJava    // converting to java.util.Map[String, Any]
val result: JHashMap[String,Any] = new JHashMap(r)
Claudius
  • 156
  • 1
  • 11
1

I wonder if you've considered going at it the other way around, by implementing the java.util.Map interface in your case class? Then you wouldn't have to convert back and forth, but any consumers downstream that are using a Map interface will just work (for example if you're using Groovy's field dot-notation).

Ryan
  • 11
  • 1
  • Creative solution as always, however I'm scared that this will also take me down a black hole that will have me write even more code. If I had time, this would be worth exploring. – dlite922 Apr 13 '15 at 16:08