package com.dropbox.client2.jsonextract;
/**
* (Internal class for extracting JSON.)
*
* <p>
* A utility class to let you extract your required structure out of an
* org.json.simple object.
* </p>
*
* <p>
* As you descend into the object and pull our your data, these classes keep
* track of where you are, so if there's an error in the JSON value, you'll get
* a "path" string describing exactly where the problem is.
* </p>
*/
public final class JsonThing extends JsonBase<Object> {
public JsonThing(Object internal, String path) {
super(internal, path);
}
public JsonThing(Object internal) {
super(internal, null);
}
private static final java.util.HashMap<Class,String> TypeNames = new java.util.HashMap<Class,String>();
static {
TypeNames.put(String.class, "a string");
TypeNames.put(Number.class, "a number");
TypeNames.put(Boolean.class, "a boolean");
TypeNames.put(java.util.Map.class, "an object");
TypeNames.put(java.util.List.class, "an array");
}
private static String typeNameForClass(Class<?> c) {
if (c == null) return "null";
String name = TypeNames.get(c);
assert name != null;
return name;
}
private static String typeNameForObject(Object o) {
if (o == null) return "null";
if (o instanceof Number) return "a number";
if (o instanceof String) return "a string";
if (o instanceof Boolean) return "a boolean";
if (o instanceof java.util.Map) return "an object";
if (o instanceof java.util.List) return "an array";
throw new IllegalArgumentException("not a valid org.json.simple type: " + o.getClass().getName());
}
private boolean is(Class<?> type) {
assert type != null;
return type.isInstance(internal);
}
private <T> T expect(Class<T> type) throws JsonExtractionException {
assert type != null;
if (type.isInstance(internal)) {
@SuppressWarnings("unchecked")
T recast = (T) internal;
return recast;
}
throw error("expecting " + typeNameForClass(type) + ", found " + typeNameForObject(internal));
}
public void expectNull() throws JsonExtractionException {
if (internal != null) {
throw error("expecting null");
}
}
public boolean isNull() {
return internal == null;
}
public JsonMap expectMap() throws JsonExtractionException {
@SuppressWarnings("unchecked")
java.util.Map<String,Object> mapInternal = (java.util.Map<String,Object>) expect(java.util.Map.class);
return new JsonMap(mapInternal, path);
}
public boolean isMap() {
return is(java.util.Map.class);
}
public JsonList expectList() throws JsonExtractionException {
@SuppressWarnings("unchecked")
java.util.List<Object> listInternal = (java.util.List<Object>) expect(java.util.List.class);
return new JsonList(listInternal, path);
}
public boolean isList() {
return is(java.util.List.class);
}
public Number expectNumber() throws JsonExtractionException {
return expect(Number.class);
}
public boolean isNumber() {
return is(Number.class);
}
public long expectInt64() throws JsonExtractionException {
if (internal instanceof Number) {
Number number = (Number) internal;
// TODO: Be robust, since JSON actually defines "number" to mean "IEEE double"
// - Make sure there's no fractional part.
// - Make sure there's no overflow.
return number.longValue();
}
else if (internal instanceof String) {
String string = (String) internal;
try {
return Long.parseLong(string, 16);
}
catch (NumberFormatException ex) {
throw error("couldn't parse string as hex (expecting a 64-bit signed integer value)");
}
}
else {
throw error("expecting an integer (or a hex string), found " + typeNameForObject(internal));
}
}
public boolean isInt64() {
try {
expectInt64();
return true;
}
catch (JsonExtractionException ex) {
return false;
}
}
public String expectString() throws JsonExtractionException {
return expect(java.lang.String.class);
}
public String expectStringOrNull() throws JsonExtractionException {
if (internal == null) return null;
return expect(java.lang.String.class);
}
public boolean isString() {
return is(java.lang.String.class);
}
public boolean expectBoolean() throws JsonExtractionException {
return expect(java.lang.Boolean.class);
}
public boolean isBoolean() {
return is(java.lang.Boolean.class);
}
static String pathConcat(String a, String b) {
if (a == null) return b;
return a + "/" + b;
}
public JsonExtractionException unexpected() {
return error("unexpected type: " + typeNameForObject(internal));
}
public static final class OptionalExtractor<T> extends JsonExtractor<T> {
public final JsonExtractor<T> elementExtractor;
public OptionalExtractor(JsonExtractor<T> elementExtractor) {
this.elementExtractor = elementExtractor;
}
public T extract(JsonThing jt) throws JsonExtractionException {
return jt.optionalExtract(this.elementExtractor);
}
}
public <T> T optionalExtract(JsonExtractor<T> extractor) throws JsonExtractionException {
if (isNull()) return null;
return extractor.extract(this);
}
}