mirror of https://github.com/apache/jclouds.git
allow SelectJson to specify multiple field names, in case the server renamed something
This commit is contained in:
parent
5aa41d07aa
commit
55a10d4c5d
|
@ -53,12 +53,16 @@ public class ParseFirstJsonValueNamed<T> implements Function<HttpResponse, T> {
|
||||||
|
|
||||||
private final GsonWrapper json;
|
private final GsonWrapper json;
|
||||||
private final TypeLiteral<T> type;
|
private final TypeLiteral<T> type;
|
||||||
private final String name;
|
private final ImmutableSet<String> nameChoices;
|
||||||
|
|
||||||
public ParseFirstJsonValueNamed(GsonWrapper json, TypeLiteral<T> type, String name) {
|
/**
|
||||||
|
* @param nameChoices
|
||||||
|
* tried in order, first match wins
|
||||||
|
*/
|
||||||
|
public ParseFirstJsonValueNamed(GsonWrapper json, TypeLiteral<T> type, String... nameChoices) {
|
||||||
this.json = checkNotNull(json, "json");
|
this.json = checkNotNull(json, "json");
|
||||||
this.type = checkNotNull(type, "type");
|
this.type = checkNotNull(type, "type");
|
||||||
this.name = checkNotNull(name, "name");
|
this.nameChoices = ImmutableSet.copyOf(checkNotNull(nameChoices, "nameChoices"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,20 +76,19 @@ public class ParseFirstJsonValueNamed<T> implements Function<HttpResponse, T> {
|
||||||
reader.setLenient(true);
|
reader.setLenient(true);
|
||||||
AtomicReference<String> name = Atomics.newReference();
|
AtomicReference<String> name = Atomics.newReference();
|
||||||
JsonToken token = reader.peek();
|
JsonToken token = reader.peek();
|
||||||
for (; token != JsonToken.END_DOCUMENT && nnn(this.name, reader, token, name); token = skipAndPeek(token,
|
for (; token != JsonToken.END_DOCUMENT && nnn(reader, token, name); token = skipAndPeek(token, reader)) {
|
||||||
reader)) {
|
|
||||||
}
|
}
|
||||||
if (name.get() == null) {
|
if (name.get() == null) {
|
||||||
logger.trace("did not object named %s in json from response %s", this.name, arg0);
|
logger.trace("did not object named %s in json from response %s", nameChoices, arg0);
|
||||||
return nothing();
|
return nothing();
|
||||||
} else if (name.get().equals(this.name)) {
|
} else if (nameChoices.contains(name.get())) {
|
||||||
return json.delegate().<T> fromJson(reader, type.getType());
|
return json.delegate().<T> fromJson(reader, type.getType());
|
||||||
} else {
|
} else {
|
||||||
return nothing();
|
return nothing();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(String.format(
|
throw new RuntimeException(String.format(
|
||||||
"error reading from stream, parsing object named %s from http response %s", this.name, arg0), e);
|
"error reading from stream, parsing object named %s from http response %s", nameChoices, arg0), e);
|
||||||
} finally {
|
} finally {
|
||||||
Closeables.closeQuietly(reader);
|
Closeables.closeQuietly(reader);
|
||||||
arg0.getPayload().release();
|
arg0.getPayload().release();
|
||||||
|
@ -93,7 +96,7 @@ public class ParseFirstJsonValueNamed<T> implements Function<HttpResponse, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected T nothing() {
|
private T nothing() {
|
||||||
if (type.getRawType().isAssignableFrom(Set.class))
|
if (type.getRawType().isAssignableFrom(Set.class))
|
||||||
return (T) ImmutableSet.of();
|
return (T) ImmutableSet.of();
|
||||||
else if (type.getRawType().isAssignableFrom(List.class))
|
else if (type.getRawType().isAssignableFrom(List.class))
|
||||||
|
@ -103,11 +106,10 @@ public class ParseFirstJsonValueNamed<T> implements Function<HttpResponse, T> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean nnn(String toFind, JsonReader reader, JsonToken token, AtomicReference<String> name)
|
private boolean nnn(JsonReader reader, JsonToken token, AtomicReference<String> name) throws IOException {
|
||||||
throws IOException {
|
|
||||||
if (token == JsonToken.NAME) {
|
if (token == JsonToken.NAME) {
|
||||||
String name2 = reader.nextName();
|
String name2 = reader.nextName();
|
||||||
if (toFind.equals(name2)) {
|
if (nameChoices.contains(name2)) {
|
||||||
name.set(name2);
|
name.set(name2);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -116,7 +118,7 @@ public class ParseFirstJsonValueNamed<T> implements Function<HttpResponse, T> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonToken skipAndPeek(JsonToken token, JsonReader reader) throws IOException {
|
private JsonToken skipAndPeek(JsonToken token, JsonReader reader) throws IOException {
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case BEGIN_ARRAY:
|
case BEGIN_ARRAY:
|
||||||
reader.beginArray();
|
reader.beginArray();
|
||||||
|
|
|
@ -36,9 +36,8 @@ import java.lang.annotation.Target;
|
||||||
public @interface SelectJson {
|
public @interface SelectJson {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Each of the keys are tried in order. This helps in the case the server renamed a field in json.
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
String value();
|
String[] value();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,19 @@ public class ParseFirstJsonValueNamedTest {
|
||||||
assertEquals(val.toString(), "[(name=GREETINGS, source=guest)]");
|
assertEquals(val.toString(), "[(name=GREETINGS, source=guest)]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scenario: server renames field from event to _event
|
||||||
|
*/
|
||||||
|
public void testParseRenamedField() throws IOException {
|
||||||
|
String nested = "{ \"count\":1 ,\"_event\" : [ {name:'GREETINGS',source:'guest'} ] }";
|
||||||
|
HttpResponse response = HttpResponse.builder().statusCode(200).message("goodie")
|
||||||
|
.payload(Payloads.newPayload(nested)).build();
|
||||||
|
|
||||||
|
List<Event> val = new ParseFirstJsonValueNamed<List<Event>>(json, new TypeLiteral<List<Event>>() {
|
||||||
|
}, "event", "_event").apply(response);
|
||||||
|
assertEquals(val.toString(), "[(name=GREETINGS, source=guest)]");
|
||||||
|
}
|
||||||
|
|
||||||
public void testParseNestedElementsWhenNotFoundIsEmpty() throws IOException {
|
public void testParseNestedElementsWhenNotFoundIsEmpty() throws IOException {
|
||||||
String nested = "{ \"count\":1 ,\"evant\" : [ {name:'GREETINGS',source:'guest'} ] }";
|
String nested = "{ \"count\":1 ,\"evant\" : [ {name:'GREETINGS',source:'guest'} ] }";
|
||||||
HttpResponse response = HttpResponse.builder().statusCode(200).message("goodie")
|
HttpResponse response = HttpResponse.builder().statusCode(200).message("goodie")
|
||||||
|
|
Loading…
Reference in New Issue