Random order of fields in generated Json

62 views
Skip to first unread message

Germán Ferrari

unread,
May 30, 2014, 6:57:11 AM5/30/14
to argona...@googlegroups.com
Hi.

I have this case class:

  case class Version(major: Int, minor: Int, patch: Int, preReleaseVersion: Option[String], buildVersion: Option[String])

and this CodecJson:

  implicit def VersionCodecJson: CodecJson[Version] = casecodec5(projs.Version.apply, projs.Version.unapply)("major", "minor", "patch", "preReleaseVersion", "buildVersion")

but when I convert an instance to json, the fields appear in random order. For example:

   Version(3, 0, 0, Some("M1"), None).asJson
   // > res11: argonaut.Json = {"buildVersion":null,"patch":0,"preReleaseVersion":"M1","major":3,"minor":0}

The `null` in `buildVersion` is also anboying, but I have seen that you are working on it.

Is there any way to make the fields in the Json to be in the order specified in the Codec?

Thank you.

Regards,
Germán.

Mark Hibberd

unread,
May 30, 2014, 7:11:46 AM5/30/14
to argona...@googlegroups.com


On Friday, 30 May 2014 20:57:11 UTC+10, Germán Ferrari wrote:
Hi.

I have this case class:

  case class Version(major: Int, minor: Int, patch: Int, preReleaseVersion: Option[String], buildVersion: Option[String])

and this CodecJson:

  implicit def VersionCodecJson: CodecJson[Version] = casecodec5(projs.Version.apply, projs.Version.unapply)("major", "minor", "patch", "preReleaseVersion", "buildVersion")

but when I convert an instance to json, the fields appear in random order. For example:

   Version(3, 0, 0, Some("M1"), None).asJson
   // > res11: argonaut.Json = {"buildVersion":null,"patch":0,"preReleaseVersion":"M1","major":3,"minor":0}

The `null` in `buildVersion` is also anboying, but I have seen that you are working on it.


You can remove the null in two different ways: Either filter out null fields from the json, or change your codec to not add None fields to the json. 

We are planning on adding a convenience method to make it easier to do the first, but it is possible to do now with a bit of extra effort, (see the operations on Json like withObject).

 There are also some combinators to help with the second one, such as :=? and ->?:.
 
Is there any way to make the fields in the Json to be in the order specified in the Codec?

You change the PrettyParams for printing. Note that you _will_ pay a performance cost for this, if that is ok in this case, you can do it with something like:
  val ordered = preserveOrderL.set(PrettyParams.nospace, true)
  json.pretty(ordered)

Note that the json toString in your example above will remain unordered, but you should use an explicit print method and not rely on toString in general.

Hope that helps.

Cheers
Mark

Germán Ferrari

unread,
May 31, 2014, 1:41:33 PM5/31/14
to argona...@googlegroups.com

On Friday, May 30, 2014 8:11:46 AM UTC-3, Mark Hibberd wrote:

On Friday, 30 May 2014 20:57:11 UTC+10, Germán Ferrari wrote:
Hi.

I have this case class:

  case class Version(major: Int, minor: Int, patch: Int, preReleaseVersion: Option[String], buildVersion: Option[String])

and this CodecJson:

  implicit def VersionCodecJson: CodecJson[Version] = casecodec5(projs.Version.apply, projs.Version.unapply)("major", "minor", "patch", "preReleaseVersion", "buildVersion")

but when I convert an instance to json, the fields appear in random order. For example:

   Version(3, 0, 0, Some("M1"), None).asJson
   // > res11: argonaut.Json = {"buildVersion":null,"patch":0,"preReleaseVersion":"M1","major":3,"minor":0}

The `null` in `buildVersion` is also anboying, but I have seen that you are working on it.


You can remove the null in two different ways: Either filter out null fields from the json, or change your codec to not add None fields to the json. 

We are planning on adding a convenience method to make it easier to do the first, but it is possible to do now with a bit of extra effort, (see the operations on Json like withObject).


Interesting.

I am  very new to Argonaut and Scalaz. I came out with this code, which works, but surely there is a better (or at least shorter) way to do it:

   json.withObject { c => val d = c.toList.filter { case (f, v) => !v.isNull }; JsonObject(InsertionMap(d: _*)) }

 
 There are also some combinators to help with the second one, such as :=? and ->?:.

I have tried :=? and ->?, and they do what I want, but I lose the convenience of the casecodec methods ... Maybe I should give up on casecodec, and simply use these combinators ...
 
 
Is there any way to make the fields in the Json to be in the order specified in the Codec?

You change the PrettyParams for printing. Note that you _will_ pay a performance cost for this, if that is ok in this case, you can do it with something like:
  val ordered = preserveOrderL.set(PrettyParams.nospace, true)
  json.pretty(ordered)

Note that the json toString in your example above will remain unordered, but you should use an explicit print method and not rely on toString in general.


Excelent. It works :).

Any hint about the order of the performance cost you mention?

Thank you.
 

Sean Parsons

unread,
May 31, 2014, 3:19:26 PM5/31/14
to Germán Ferrari, argona...@googlegroups.com

It'll be about 20-30% slower if you want to preserve field ordering.

Sean.

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

Germán Ferrari

unread,
May 31, 2014, 4:02:16 PM5/31/14
to argona...@googlegroups.com, german....@gmail.com
On Saturday, May 31, 2014 4:19:26 PM UTC-3, seantparsons wrote:

It'll be about 20-30% slower if you want to preserve field ordering.

Sean.

Thank you.

Germán
Reply all
Reply to author
Forward
0 new messages