0

I have a hash that looks like:

require 'json'
h = {  :foo => 1, :bar => 1 }
h.to_json # will do '{ "foo" : 1, "bar" 1 }'

The best way I've found is to rekey and serialize: https://stackoverflow.com/a/4137966/887836

In java there is an annotation to rename "foo" into "Foo" to have a specific serialized view. Is there a standard way of doing this in ruby? I'd prefer a declarative way of specifying this if that's available.

public class MyClass {
  @SerializedName("Foo") String foo;

  public MyClass(String foo) {
    this.foo = foo;
  }
}
Alexander Oh
  • 24,223
  • 14
  • 73
  • 76
  • 1
    I would argue that a class should know about how it might be serialized to JSON. IMO that is a violation of the separation of concerns design principle. If you want to serialize a thing (in this case that hash) in a special way, then I suggest writing an explicit Serializer class to handle the transformation. It really depends on the reason why you need to transform keys and what the expected output format looks like. But there are many serializer gems out there that do even complex transformations (for example to JSON:API recommendations) on the fly. – spickermann Apr 04 '19 at 10:53
  • I agree, but that then boils down to the same question in the specific serializer right? I fail to find a somewhat decent way of declaring that in ruby (also version 2.0.0). I currently do the mapping manually and building a serializer class creates much more code than I want for now. – Alexander Oh Apr 04 '19 at 11:04
  • Can you use String keys, so `"Foo" => 1`? – Kris Apr 04 '19 at 11:39
  • 2
    Might be too simple but : `h.transform_keys { |k| k.to_s.capitalize }.to_json` – Kris Apr 04 '19 at 11:41
  • I'm transforming keys currently. I can use strings, but other parts of the application use the strings already so I effectively copy the hashtable to use the json converter. It seems wasteful to copy to a new hashtable for like 1 operation and then bin it again. If I need to I'll probably 'just do a `"{\"Foo\":#{h[:foo]},\"Bar\":#{h[:bar]}}"` as this elides the hashmap copy. – Alexander Oh Apr 04 '19 at 11:51
  • If I understand your comment correctly then your question is how to transfer data in your system das uses different formats. It is not really about how to do this with JSON, because there might be other ways to transfer that data. Is this a xy problem? Perhaps you can give us an example of your input and output format? And elaborate on the transformation. From your question, I got that the `foo` needs to be translated to 'Foo', but the 'bar' should stay the same. – spickermann Apr 04 '19 at 12:46
  • @spickermann yes I all do that. so I have a common model class, and it needs custom serializers for its json output. – Alexander Oh Apr 04 '19 at 14:58

1 Answers1

1

I think in your question you are comparing "apples" to "oranges". In the java case you have a class that you define in which you are free to add annotations. Those annotations can then be used by a library such as gson to customize the serialization of instances of that class.

In the ruby case you are talking about instances of a built in class (Hash) which you are not free to annotate (unless you want to monkey path Hash).

If you create a custom class to represent your Hash instances then you would open up more options, such as overriding the .to_json method for your classes, or even implementing your own delarive scheme such as providing a mapping hash within your class.

If you want to stick with keeping your data as instances of a Hash, then I think you should stick to the various transformations that you found and have been proposed in the comments.

nPn
  • 16,254
  • 9
  • 35
  • 58