skip to Main Content

I have an input json like:

{
    "Employee": [
      {
        "employee1.id": 1
      },
      {
        "employee1.name": "John"
      },
      {
        "employee1.address.street": "main street"
      },
      {
        "employee1.address.pin": "123456"
      },
      {
        "employee2.id": 2
      },
      {
        "employee2.name": "Mike"
      },
      {
        "employee2.address.street": "51 street"
      },
      {
        "employee2.address.pin": "234543"
      }
    ]
}

And I am trying to convert it into:

{
    "employee1":{
        "id": 1,
        "name": "John",
        "address": {
            "street": "main street",
            "pin": "123456"
        }
    },
        "employee2":{
        "id": 2,
        "name": "Mike",
        "address": {
            "street": "51 street",
            "pin": "234543"
        }
    }
}

I tried to split the key from input json with dot i.e. ‘.‘ and tried to iterate over to construct a map: Map<String, Object>
But the problem is the input json key depth can go beyond 2 i.e. in future the input key can be like:

{
    "employee1.address.tempAddress.street": "main street"
},
{
    "employee1.address.permanentAddress.street": "main street"
}

So, is there any library available to achieve this, or anything closely related to this using which I can achieve this?

2

Answers


  1. The comments about the input format being "weird" (to put it politely) are spot-on: This is a convoluted way to represent simple hierarchical data.

    But sometimes we have to deal with sub-optimal input formats, that’s why we can fix them like this:

      private static JSONObject arrayToStructure(JSONArray inputArray) {
        JSONObject output = new JSONObject();
        for (Object o : inputArray) {
          assert o instanceof JSONObject;
          JSONObject jso = (JSONObject) o;
          assert jso.length() == 1;
          String key = jso.keys().next();
          Object value = jso.get(key);
          setJsonPath(output, key, value);
        }
        return output;
      }
    
      private static void setJsonPath(JSONObject target, String key, Object value) {
        String[] keyParts = key.split("\.");
        JSONObject parent = target;
        for (int i = 0; i < keyParts.length - 1; i++) {
          String keyPart = keyParts[i];
          if (parent.has(keyPart)) {
            parent = parent.getJSONObject(keyPart);
          } else {
            JSONObject child = new JSONObject();
            parent.put(keyPart, child);
            parent = child;
          }
        }
        assert !parent.has(keyParts[keyParts.length - 1]);
        parent.put(keyParts[keyParts.length - 1], value);
      }
    

    This code uses JSON-Java, probably better known as org.json:json.

    And it can be used like this:

      public static void main(String[] args) {
        String input = """
            [
              {
                "employee1.id": 1
              },
              {
                "employee1.name": "John"
              },
              {
                "employee1.address.street": "main street"
              },
              {
                "employee1.address.pin": "123456"
              },
              {
                "employee2.id": 2
              },
              {
                "employee2.name": "Mike"
              },
              {
                "employee2.address.street": "51 street"
              },
              {
                "employee2.address.pin": "234543"
              }
            ]""";
        JSONArray inputArray = new JSONArray(input);
        JSONObject structure = arrayToStructure(inputArray);
        System.out.println(structure.toString(2));
      }
    

    Note that this code is lacking proper sanity checks (some of which I’ve hinted at using assert) and the nature of this "protocol" means that you can get misleading, ambiguous or straight up malicious inputs. For example nothing stops the input from having both "employee1.id": 1 and "employee1.id": 2 in there. How that is to be interpreted is up to the parser and such ambiguity is a great source of bugs and potential security issues.

    Login or Signup to reply.
  2. Library Josson can do the transformation by one expression.

    https://github.com/octomix/josson

    Josson josson = Josson.fromJsonString(
        "{" +
        "  "Employee": [" +
        "    {" +
        "      "employee1.id": 1" +
        "    }," +
        "    {" +
        "      "employee1.name": "John"" +
        "    }," +
        "    {" +
        "      "employee1.address.street": "main street"" +
        "    }," +
        "    {" +
        "      "employee1.address.pin": "123456"" +
        "    }," +
        "    {" +
        "      "employee2.id": 2" +
        "    }," +
        "    {" +
        "      "employee2.name": "Mike"" +
        "    }," +
        "    {" +
        "      "employee2.address.street": "51 street"" +
        "    }," +
        "    {" +
        "      "employee2.address.pin": "234543"" +
        "    }" +
        "  ]" +
        "}");
    JsonNode node = josson.getNode("Employee.mergeObjects().unflatten('.')");
    System.out.println(node.toPrettyString());
    

    Output

    {
      "employee1" : {
        "id" : 1,
        "name" : "John",
        "address" : {
          "street" : "main street",
          "pin" : "123456"
        }
      },
      "employee2" : {
        "id" : 2,
        "name" : "Mike",
        "address" : {
          "street" : "51 street",
          "pin" : "234543"
        }
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search