7

I have this code:

static String createRequestJson(String apiKey, String apiSecret) {
  JsonNodeFactory factory = JsonNodeFactory.instance;
  ObjectNode root = factory.objectNode();
  root.set("auth", factory.objectNode()
      .put("api_key", apiKey)
      .put("api_secret", apiSecret));
  root.put("wait", true);
  return root.toString();
}

It works, but the code looks more complicated than necessary. In particular, I’d like to get rid of the root variable.

static String createRequestJson(String apiKey, String apiSecret) {
  JsonNodeFactory factory = JsonNodeFactory.instance;
  return factory.objectNode()
      .set("auth", factory.objectNode()
          .put("api_key", apiKey)
          .put("api_secret", apiSecret))
      .put("wait", true) // Compile error: JsonNode.put(String, boolean) undefined
      .toString();
}

The problem is that the set method does not return an ObjectNode but only a JsonNode, which breaks the method chaining.

Did I overlook something obvious, or is it not possible to create such nested objects in one go?

Roland Illig
  • 417
  • 1
  • 5
  • 15
  • Side note: many people find method chaining to be creating complicated code in the first place. You know, when you got 3, 5, 7 calls on one line, which one gave you that exception? In your case, I would simply pass the root object to another helper method that does make those configuration calls (which would also allow you to write a unit test for it). – GhostCat May 31 '16 at 10:34

2 Answers2

4

This is an unfortunate flaw in method signature, but unfortunately one that is not possible to change without breakage for existing code: if signature was changed (return type is part of signature), any existing code using this method would fail to load with newer versions of Jackson.

So, yes, it is a bug of sorts, but unfortunately one that is very difficult to fix.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • 3
    This is annoying as hell. I'm on 2.8.9 and still this hasn't been changed. – matsa Feb 16 '18 at 13:50
  • @matsa and can not be either as that would break existing binary compatibility. If it was easy it would have been already one. It can not be changed before next major version. – StaxMan Feb 16 '18 at 20:11
  • Yup, I know that. But there doesn't seem to be any 3.x.x planned as far as I can see. I guess I'll just have to live with those deprecation warning cause I'm gonna be using the method that actually can be used for chaining. – matsa Feb 19 '18 at 12:43
  • 1
    @matsa Not sure why you think no 3.x is planned, given that `master` branch is for version 3.0.0-SNAPSHOT... but it definitely is being planned. May take a while of course. – StaxMan Feb 20 '18 at 20:38
0

Using 2.14 at least, I seem to be able to assign an ObjectNode as a response type for the set method. Doing this you can actually do the chain.

static String createRequestJson(String apiKey, String apiSecret) {
  JsonNodeFactory factory = JsonNodeFactory.instance;
  return factory.objectNode()
      .<ObjectNode>set("auth", factory.objectNode()
          .put("api_key", apiKey)
          .put("api_secret", apiSecret))
      .put("wait", true)
      .toString();
}