Skip to content

JSON Pointer spec (RFC 6901) support #1443

Description

@markkolich

Consider the following JSON object:

{
  "foo": {
    "bar": {
       "baz": "bat"
    }
  }
}

Using GSON, without registering a custom type adapter, if I want to safely access member foo.bar.baz I end up with something like this:

final JsonObject object = new GsonBuilder().create().fromJson("{...}", JsonObject.class);

final JsonObject foo = object.getAsJsonObject("foo");
if (foo != null) {
  final JsonObject bar = foo.getAsJsonObject("bar");
  if (bar != null) {
    final JsonElement baz = bar.get("baz");
    if (baz != null && baz.isJsonPrimitive()) {
      final String bat = baz.getAsString();
      // ...
    }
  }
}

Instead, I'd love to be able to call a single method on the initial JsonObject itself, something like getStringAtPath():

final JsonObject object = new GsonBuilder().create().fromJson("{...}", JsonObject.class);

final String baz = object.getStringAtPath("foo.bar.baz"); // <<-- !!
if (baz == null) {
  // ... didn't exist.
}

In lieu of this missing API, I cooked up a simple helper method for String primitives:

import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;

@Nullable
public static final String getStringAtPath(
    final JsonObject object,
    final String path) {
  Preconditions.checkNotNull(object, "JSON object cannot be null.");
  Preconditions.checkNotNull(path, "JSON object path cannot be null.");

  JsonObject base = object;
  final Iterable<String> segments = Splitter.on(".").split(path);
  for (final String segment : segments) {
    final JsonElement element = base.get(segment);
    if (element == null) {
      return null;
    }

    if (element.isJsonPrimitive()) {
      final JsonPrimitive primitive = element.getAsJsonPrimitive();
      return primitive.getAsString();
    } else if (element.isJsonObject()) {
      base = element.getAsJsonObject();
    } else {
      return null;
    }
  }

  return null;
}

It would be tremendously helpful if similar methods were conveniently folded into the JsonObject API itself. It could easily be extended for the other types as well: int, boolean, char, double, etc. Admittedly, things get a bit hairy with arrays but I'd imagine support for paths like foo.bar[8].baz could work.

Apologies if this is a dupe, I did briefly search the existing set of issues but didn't immediately find anything related.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions