macro for scala Json, field names to camelcase, or manual mapping

704 views
Skip to first unread message

David Portabella

unread,
May 17, 2013, 4:33:12 AM5/17/13
to play-fr...@googlegroups.com
The macro for scala Json is great! 

I do as follows:
case class TestUser(id: String, loginUrl: String)
implicit val testUserReads = Json.reads[TestUser]
jsValue.as[TestUser]

however,
{ id: 34242, login_url: "fsdafsa" } will not work, because the names "login_url" and "loginUrl" do not match.

Is it possible to tell the json macro to convert field names to their camelcase version?

If not, is it possible to manually override the field name mapping?



Pascal Voitot Dev

unread,
May 17, 2013, 7:34:53 AM5/17/13
to play-fr...@googlegroups.com
On Fri, May 17, 2013 at 10:33 AM, David Portabella <david.po...@gmail.com> wrote:
The macro for scala Json is great! 

I do as follows:
case class TestUser(id: String, loginUrl: String)
implicit val testUserReads = Json.reads[TestUser]
jsValue.as[TestUser]

however,
{ id: 34242, login_url: "fsdafsa" } will not work, because the names "login_url" and "loginUrl" do not match.

Is it possible to tell the json macro to convert field names to their camelcase version?

no it's not because the macro is stupid and automatic and most important compiled :)
 
If not, is it possible to manually override the field name mapping?


you must write your own Reads[TestUser]

implicit val rds = ((__ \ "id").read[String] and (__ \ "login_url").read[String])(TestUser.apply _)

BR
Pascal
 


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

David Portabella

unread,
May 17, 2013, 7:43:33 AM5/17/13
to play-fr...@googlegroups.com
> no it's not because the macro is stupid and automatic and most important compiled :)

ok, it is not possible with the *current* version of the macro.

maybe the developers of the (still experimental) json macro could consider adding such configuration issues (as Jackson can do).
:)


Pascal Voitot Dev

unread,
May 17, 2013, 7:52:54 AM5/17/13
to play-fr...@googlegroups.com
I'm the developer of it so I might be able to speak ;)
Actually what you ask is a runtime behavior and not a compile-time behavior.
By default the reader searches for a specific key in JsObject and doesn't try other possibilities such as case-sensitivity or camelcase. Doing this by default would impact performance.
I think writing your own Reads taking this special requirement is not so complicated and quite specific to your use-case.
But if it becomes the most wanted feature required by many people, we could think about adding a helper for that ;)

Pascal

Julien Richard-Foy

unread,
May 17, 2013, 7:58:16 AM5/17/13
to play-fr...@googlegroups.com
@pascal, maybe we could add a parameter to the macro, indicating which naming translation scheme use (e.g. camel_case to lowerCamelCase, or identity — which would be the default)

Pascal Voitot Dev

unread,
May 17, 2013, 8:00:08 AM5/17/13
to play-fr...@googlegroups.com
On Fri, May 17, 2013 at 1:58 PM, Julien Richard-Foy <j...@zenexity.com> wrote:
@pascal, maybe we could add a parameter to the macro, indicating which naming translation scheme use (e.g. camel_case to lowerCamelCase, or identity — which would be the default)


This is not only changing the macro but also chaging the JsPath Reads because they don't care about that scheme at all.

Haoyi Li

unread,
May 17, 2013, 8:00:57 AM5/17/13
to play-fr...@googlegroups.com
If this was a democracy and I had a vote I would vote for having it customizable through an @annotation or something.

Writing your own Reads is fine if it is a special requirement, but if you are primarily interfacing with a big system which uses under_score_convention (e.g. lots of Python/Ruby projects!), you'll be writing a Reads for everything. Which is to say, the macros become entirely useless, and you are throwing them out and rewriting everything by hand.

With a (tiny) bit of flexibility, they could remain being useful even in such situations. But I don't have a vote, so all I can do is offer my opinion.

Pascal Voitot Dev

unread,
May 17, 2013, 8:06:37 AM5/17/13
to play-fr...@googlegroups.com
But if this feature becomes an identified requirement, let's think about the best way to implement it (without annotations if possible ;)) because it's not just modifying the macro IMHO. We can also develop new extended macros without breaking any existing API.

Pascal

Julien Richard-Foy

unread,
May 17, 2013, 8:11:09 AM5/17/13
to play-fr...@googlegroups.com
On Fri, May 17, 2013 at 2:06 PM, Pascal Voitot Dev <pascal.v...@gmail.com> wrote:
But if this feature becomes an identified requirement, let's think about the best way to implement it (without annotations if possible ;)) because it's not just modifying the macro IMHO.

Why isn’t it just modifying the macro?

The following call:

Json.reads[User]

currently expands to:

 ((__ \ "id").read[String] and (__ \ "loginUrl").read[String])(TestUser.apply _)

The macro could have a parameter, e.g.:

Json.reads[User](namingConvention = CamelCase)

That would lead to the following expansion:

 ((__ \ "id").read[String] and (__ \ "login_url").read[String])(TestUser.apply _)

The JsPath API does not need to be modified, unless I’m wrong?

David Portabella

unread,
May 17, 2013, 8:12:56 AM5/17/13
to play-fr...@googlegroups.com
> Actually what you ask is a runtime behavior and not a compile-time behavior.
not at all, I am asking for a configuration used at compile-time behavior.
the configuration could allow to override some fields of the mappings, such as (login_url <> "loginUrl).
a camelCase to under_score_convention automatic mapping is also possible at compile-time,
meaning that if it finds login_url, it will not try to find a val in the case class named "login_url", but "loginUrl".
(and without using annotations)

I agree with Haoyi Li, the library needs to be parametrizable (as in Jackson) so that the library is actually useful for most situations.
and the macro substitution can be done at compile-time, not penalized at run-time

Pascal Voitot Dev

unread,
May 17, 2013, 8:16:51 AM5/17/13
to play-fr...@googlegroups.com
Oh I see your point, sorry I was thinking about something else following my idea about managing all cases at the same time...

Restricting precisely as you do would be possible yes!
So the most complicated is modifying the macro now (or creating another macro besides) ;););)

Pascal Voitot Dev

unread,
May 17, 2013, 8:18:01 AM5/17/13
to play-fr...@googlegroups.com
On Fri, May 17, 2013 at 2:12 PM, David Portabella <david.po...@gmail.com> wrote:
> Actually what you ask is a runtime behavior and not a compile-time behavior.
not at all, I am asking for a configuration used at compile-time behavior.
the configuration could allow to override some fields of the mappings, such as (login_url <> "loginUrl).
a camelCase to under_score_convention automatic mapping is also possible at compile-time,
meaning that if it finds login_url, it will not try to find a val in the case class named "login_url", but "loginUrl".
(and without using annotations)

I agree with Haoyi Li, the library needs to be parametrizable (as in Jackson) so that the library is actually useful for most situations.
and the macro substitution can be done at compile-time, not penalized at run-time


Yes I've understood your point of view now... Stupid I am ;)
From this point of view, yes it's possible I think!
 



On Friday, May 17, 2013 10:33:12 AM UTC+2, David Portabella wrote:
The macro for scala Json is great! 

I do as follows:
case class TestUser(id: String, loginUrl: String)
implicit val testUserReads = Json.reads[TestUser]
jsValue.as[TestUser]

however,
{ id: 34242, login_url: "fsdafsa" } will not work, because the names "login_url" and "loginUrl" do not match.

Is it possible to tell the json macro to convert field names to their camelcase version?

If not, is it possible to manually override the field name mapping?



Pascal Voitot Dev

unread,
May 17, 2013, 8:20:23 AM5/17/13
to play-fr...@googlegroups.com
On Fri, May 17, 2013 at 2:18 PM, Pascal Voitot Dev <pascal.v...@gmail.com> wrote:



On Fri, May 17, 2013 at 2:12 PM, David Portabella <david.po...@gmail.com> wrote:
> Actually what you ask is a runtime behavior and not a compile-time behavior.
not at all, I am asking for a configuration used at compile-time behavior.
the configuration could allow to override some fields of the mappings, such as (login_url <> "loginUrl).
a camelCase to under_score_convention automatic mapping is also possible at compile-time,
meaning that if it finds login_url, it will not try to find a val in the case class named "login_url", but "loginUrl".
(and without using annotations)

I agree with Haoyi Li, the library needs to be parametrizable (as in Jackson) so that the library is actually useful for most situations.
and the macro substitution can be done at compile-time, not penalized at run-time


Yes I've understood your point of view now... Stupid I am ;)
From this point of view, yes it's possible I think!
 

Actually are there other conventions like this one that could be taken into account in future evolutions?
 
Pascal

Haoyi Li

unread,
May 17, 2013, 8:30:10 AM5/17/13
to play-fr...@googlegroups.com
I guess the most common are:

camelCase
PascalCase
under_scored
dash-separated
allsmall
ALLCAPS

This isn't just a thought experiment; working with Python/Javascript/HTML/CSS/SQL application, you end up with a mix of *every single one of those* conventions in the same code base! It's horrible!

I think ideally, instead of hard-coding in which ones we want to support, the user would be able to pass in a (String) => String function, maybe as an implicit parameter, that will do the transformation for him? That would be really elegant and generic. it should then be pretty easy to provide the common ones (i.e. those above) since writing the (String) => String transforms isn't that hard really.

Pascal Voitot Dev

unread,
May 17, 2013, 8:32:51 AM5/17/13
to play-fr...@googlegroups.com
On Fri, May 17, 2013 at 2:30 PM, Haoyi Li <haoy...@gmail.com> wrote:
I guess the most common are:

camelCase
PascalCase
under_scored
dash-separated
allsmall
ALLCAPS

This isn't just a thought experiment; working with Python/Javascript/HTML/CSS/SQL application, you end up with a mix of *every single one of those* conventions in the same code base! It's horrible!

I think ideally, instead of hard-coding in which ones we want to support, the user would be able to pass in a (String) => String function, maybe as an implicit parameter, that will do the transformation for him? That would be really elegant and generic. it should then be pretty easy to provide the common ones (i.e. those above) since writing the (String) => String transforms isn't that hard really.


This approach was the one I was thinking about and this one requires much more modifications.
Let's begin simple and improve it if necessary ;)

David Portabella

unread,
May 17, 2013, 8:36:03 AM5/17/13
to play-fr...@googlegroups.com
> Actually are there other conventions like this one that could be taken into account in future evolutions?
it should be an abstract function string to string. (from json to case class, and another function from case class to json).

and for the configuration in general, there are other issues that developers might be interested in also. see here:

some examples: field names mapping, fail on unknown fields, field property order (for serializing to json), polymorphic type handling...

Markus Jura

unread,
Nov 14, 2013, 6:26:17 PM11/14/13
to play-fr...@googlegroups.com
I would find it very useful as well if we would have this feature. Is it somehow planned for one of the next releases?

Cheers
Markus

David Bouyssié

unread,
Feb 5, 2014, 7:27:36 AM2/5/14
to play-fr...@googlegroups.com
+1 for this feature

Writing specific readers/writers is painfull and I don't want to use a lower_case convention in my case classes, I just want to produce lower_cased JSON.

So as already suggested something like
"Json.format[User](namingConvention = MyNamingConvention )"

One can imagine that MyNamingConvention must implement a given method required by a given trait :

trait JsonNamingConvention {

  // Convert a field name into a string using a custom convetnion (used by the writer)
  def fieldNameToJsonKey( s: String ): String


  // Parse a string into a field name using a custom convention (used by the reader)
  def jsonKeyToFieldName( s: String ): String

}

jakob dobrzynski

unread,
Apr 7, 2014, 10:16:27 AM4/7/14
to play-fr...@googlegroups.com
Hi there!

+1

I'm currently doing some implementation towards an API that uses under_score notation. 
I'm using reactiveMongo, with json coast to coast and since all my reads and writes
are camelCase I would love this feature.

Any news?

Kind regards,
Jakob

jakob dobrzynski

unread,
Apr 7, 2014, 2:15:39 PM4/7/14
to play-fr...@googlegroups.com
Hello again. Forgot to show you how I do right now to create camel_case objects:

def createCustomer(customer: Customer) = {

    implicit val addressWrites = new Writes[Address] {
      def writes(address: Address): JsValue = {
        Json.obj("city" -> address.city,
          "country" -> address.country,
          "zipcode" -> address.zipcode,
          "street_address" -> address.streetAddress
        )
      }
    }

    implicit val customerWrites = new Writes[Customer] {
      def writes(customer: Customer): JsValue = {
        Json.obj("customer_no" -> customer.customerNo,
          "org_no" -> customer.orgNr,
          "name" -> customer.name,
          "address" -> customer.address,
          "contact" -> customer.contact
        )
      }
    }

    Logger.info(""+Json.toJson(customer))

    val future = WS.url(billogramResource + customerResource)
      .withAuth("secret", "secret", Realm.AuthScheme.BASIC)
      .withHeaders("Content-Type" -> "application/json; charset=utf-8")
      .post(Json.toJson(customer))

    future.map { response =>
      Logger.info("YEE HAA: " + response.json)

    }

As you can see. A lot of boilerplate =).

Regards,
Jakob

Boris Capitanu

unread,
Oct 4, 2014, 6:58:10 AM10/4/14
to play-fr...@googlegroups.com
+1 for adding a parameter to the macro as suggested...    

Is there a plan for adding this in a future version of play-json?
Reply all
Reply to author
Forward
0 new messages