javajsonscalaimplicitscala-java-interop

Use functions from a Scala object that have implicit parameters in java code


Is there a way that I can use the fromJson and toJson methods in my java code? I would want to call it to transform a bson document that I get from mongoldb to a model class that I have in Scala

My Scala object is below,

import com.fasterxml.jackson.databind.{DeserializationFeature, ObjectMapper}
import com.fasterxml.jackson.module.scala.{DefaultScalaModule, ScalaObjectMapper}

object JsonUtils {

  val mapper = new ObjectMapper() with ScalaObjectMapper

  mapper.registerModule(DefaultScalaModule)
  mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

  def toJson(value: Map[Symbol, Any]): String = {
    toJson(value map { case (k,v) => k.name -> v})
  }

  def toJson(value: Any): String = {
    mapper.writeValueAsString(value)
  }

  def toMap[V](json:String)(implicit m: Manifest[V]) = fromJson[Map[String,V]](json)

  def fromJson[T](json: String)(implicit m : Manifest[T]): T = {
    mapper.readValue[T](json)
  }

  implicit class Marshallable[T](marshallMe: T) {
    def toJson: String = JsonUtils.toJson(marshallMe)
  }

  implicit class Unmarshallable(unMarshallMe: String) {
    def toMap: Map[String,Any] = JsonUtils.toMap(unMarshallMe)
    def fromJson[T]()(implicit m: Manifest[T]): T =  JsonUtils.fromJson[T](unMarshallMe)
  }
}

Solution

  • In Java code you have to resolve Scala implicits manually.

    Try to call fromJson like

    JsonUtils.fromJson("a", scala.reflect.Manifest.classType(LocalUser.class));
    

    or

    JsonUtils$.MODULE$.fromJson("a", scala.reflect.Manifest$.MODULE$.classType(LocalUser.class));
    

    Based on Calling a Scala from Java Play Framework which takes a ClassTag

    Regarding toJson I can't see problems. Although if you call overloaded version of toJson with Map argument, maybe you'll have to convert between scala.Predef.Map aka scala.collection.immutable.Map and java.util.Map

    Convert Java Map to Scala Map

    How can I convert Scala Map to Java Map with scala.Float to java.Float k/v conversion

    By the way, Manifest is deprecated in favor of ClassTag/TypeTag

    https://docs.scala-lang.org/overviews/reflection/typetags-manifests.html