private void merge(JsonObject genNode, JsonObject custNode, List<String> genPath) {

    for (Entry<String, JsonElement> entry : custNode.entrySet()) {

      JsonElement custChildNode = entry.getValue();

      JsonElement genChildNode = genNode.get(entry.getKey());

      if (genChildNode != null) {

        String nodePath = getPath(genPath, entry.getKey());

        if (replaceChildrenTags.contains(nodePath)) {

          if (custChildNode instanceof JsonObject && genChildNode instanceof JsonObject) {

            List<String> newPath = new ArrayList<String>(genPath);
            newPath.add(entry.getKey());

            merge((JsonObject) genChildNode, (JsonObject) custChildNode, newPath);
          }

        } else if (addChildrenTags.contains(nodePath)) {

          addChildren(custChildNode, genChildNode);

        } else if (includedInReplaceOrAdd(nodePath)) {

          if (custChildNode instanceof JsonObject && genChildNode instanceof JsonObject) {

            List<String> newPath = new ArrayList<String>(genPath);
            newPath.add(entry.getKey());

            merge((JsonObject) genChildNode, (JsonObject) custChildNode, newPath);
          }

        } else {

          // Replace entire node
          genNode.add(entry.getKey(), custChildNode);
        }

      } else {

        // Add new node
        genNode.add(entry.getKey(), custChildNode);
      }
    }
  }