Re: [spray-user] spray-json - serialize error for case class on Android

761 views
Skip to first unread message

Young Gu

unread,
Apr 27, 2013, 2:42:14 AM4/27/13
to spray...@googlegroups.com
Sorry, it don't work even no the error 'Cannot determine field order', comment the code will mess most of the parser,  I have to use jsonFormat instead it for case class.

It's strange for the difference between android and Sun JDK,  but it should awesome if we can use the jsonFormatN series for case class.

Thanks.


On Sat, Apr 27, 2013 at 12:31 PM, Young Gu <hyysg...@gmail.com> wrote:
Hi All,

I created some case class and serialize it , everything is OK on Sun JDK but I got  error on Android when there are more than two field with different type. 

Caused by: java.lang.RuntimeException: Cannot automatically determine case class field names and order for 'com.lifecosys.toolkit.Color', please use the 'jsonFormat' overload with explicit field name specification

The problem is that we pair fields and copy method within ProductFormats.extractFieldNames,  the copyDefaultMethods is sorted, but the fields is consistent with it, so the validation failed and throw error. Seems everything is OK after I override the extractFieldNames and comment the validation. 

One issue for this temporary patch is that the key order of generated json string is different with the case class constructor, but IMHO this is not a big issue.

Generated json for case class Color(red: Int = 0, green: Float = 0, blue: Double = 0):

{
        "blue": 0,
        "green": 0.0,
        "red": 0.0
}

Besides, I also checkout spray-json and comment the code, all test case is OK.

Anyone has better solution for this issue?


Below is the demo code:

import spray.json._

case class Location(x: Int = 0, y: Float = 0)

case class Color(red: Int = 0, green: Float = 0, blue: Double = 0)

case class Distance(x1: Int = 0, y1: Float = 0, x2: Double = 0, y2: Int = 0)

object TestJsonProtocol extends DefaultJsonProtocol {
  implicit val LocationJsonFormat = jsonFormat2(Location)
  implicit val ColorJsonFormat = jsonFormat3(Color)
  implicit val DistanceJsonFormat = jsonFormat4(Distance)

  override protected def extractFieldNames(classManifest: ClassManifest[_]): Array[String] = {
    val clazz = classManifest.erasure
    try {
      // copy methods have the form copy$default$N(), we need to sort them in order, but must account for the fact
      // that lexical sorting of ...8(), ...9(), ...10() is not correct, so we extract N and sort by N.toInt
      val copyDefaultMethods = clazz.getMethods.filter(_.getName.startsWith("copy$default$")).sortBy(
        _.getName.drop("copy$default$".length).takeWhile(_ != '(').toInt)
      val fields = clazz.getDeclaredFields.filterNot(_.getName.startsWith("$"))
      if (copyDefaultMethods.length != fields.length)
        sys.error("Case class " + clazz.getName + " declares additional fields")
      //Comment type validation to avoid the error
//      if (fields.zip(copyDefaultMethods).exists { case (f, m) => f.getType != m.getReturnType })
//        sys.error("Cannot determine field order of case class " + clazz.getName)
      fields.map(_.getName)
    } catch {
      case ex => throw new RuntimeException("Cannot automatically determine case class field names and order " +
        "for '" + clazz.getName + "', please use the 'jsonFormat' overload with explicit field name specification", ex)
    }
  }
}

class BookReader extends Activity {
  override def onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    import TestJsonProtocol._
  }
}



--
Please be free to contact with me for any question or suggestion.

Thanks & Best Regards,

Young Gu | Software Engineer | www.infor.com



--
Please be free to contact with me for any question or suggestion.

Thanks & Best Regards,

Young Gu | Software Engineer | www.infor.com

Young Gu

unread,
Apr 27, 2013, 12:31:21 AM4/27/13
to spray...@googlegroups.com

Johannes Rudolph

unread,
Apr 29, 2013, 5:57:19 AM4/29/13
to spray...@googlegroups.com
On Sat, Apr 27, 2013 at 8:42 AM, Young Gu <hyysg...@gmail.com> wrote:
> Sorry, it don't work even no the error 'Cannot determine field order',
> comment the code will mess most of the parser, I have to use jsonFormat
> instead it for case class.

Thanks for the report. I created an issue for this [1]. There seem to
be differences between how reflection works in detail on Android and
the standard JDK. I can't say for sure if this can be fixed at all.
Maybe you could help out debugging by printing out something like
that:

fields.zip(copyDefaultMethods).map { case (f, m) => f.getName+" f:
"+f.getType +" m:"+ m.getReturnType +" cond: "+(f.getType !=
m.getReturnType)}.mkString

in cases where the error is generated and add the log output to the issue?

Thanks,

--
Johannes

[1] https://github.com/spray/spray-json/issues/53

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net

Young Gu

unread,
May 1, 2013, 4:26:26 PM5/1/13
to spray...@googlegroups.com

Sorry for late reply,  the problem  is  that the order  of  the  fields  is not  same as the copy default  methods on  Android,  for  example,  the  generated fields for  class  Color  is blue, red, green, but  it  must  be  red,  green ,blue  t pass the  validation.

Maybe  we  can  try to use scala  reflection to  fix  it.

--
You received this message because you are subscribed to the Google Groups "spray-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to spray-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Young Gu

unread,
May 3, 2013, 2:55:01 AM5/3/13
to spray...@googlegroups.com
Hi Johannes

I have added the output log and code to the issue, thanks.

Abimbola Esuruoso

unread,
Mar 15, 2016, 5:30:03 AM3/15/16
to spray.io User List
Hi there,

My application is currently experiencing the same issue on Android where the class in question is 

case class CreateUser(email: String, gender: String, mobile: String, username: String)

The resulting JSON is has the fields mapped to the wrong values i.e, the username field is mapped to the email field etc.

Is there any resolution for this issue yet??

Thanks!

Jan-Pieter van den Heuvel

unread,
Mar 15, 2016, 6:32:26 PM3/15/16
to spray...@googlegroups.com
How do you specify the JsonFormat? The github issue referenced in this thread mentions a workaround: use the jsonFormat overload instead of the jsonFormat4 method.
Hope this helps.

Kind regards,
Jan-Pieter

--
You received this message because you are subscribed to the Google Groups "spray.io User List" group.

To unsubscribe from this group and stop receiving emails from it, send an email to spray-user+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages