mirror of https://github.com/apache/jclouds.git
Issue 658:new annotations @SelectJson @OnlyElement
This commit is contained in:
parent
39f4817b66
commit
6b02b93cf7
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.functions;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class OnlyElementOrNull<T> implements Function<Iterable<T>, T> {
|
||||
|
||||
@Override
|
||||
public T apply(Iterable<T> arg0) {
|
||||
if (arg0 == null || Iterables.size(arg0) == 0)
|
||||
return null;
|
||||
return Iterables.getOnlyElement(arg0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.http.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.json.internal.GsonWrapper;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseFirstJsonValueNamed<T> implements Function<HttpResponse, T> {
|
||||
|
||||
private final GsonWrapper json;
|
||||
private final TypeLiteral<T> type;
|
||||
private final String name;
|
||||
|
||||
public ParseFirstJsonValueNamed(GsonWrapper json, TypeLiteral<T> type, String name) {
|
||||
this.json = checkNotNull(json, "json");
|
||||
this.type = checkNotNull(type, "type");
|
||||
this.name = checkNotNull(name, "name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(HttpResponse arg0) {
|
||||
if (arg0.getPayload() == null)
|
||||
return nothing();
|
||||
JsonReader reader = null;
|
||||
try {
|
||||
reader = new JsonReader(new InputStreamReader(arg0.getPayload().getInput()));
|
||||
// in case keys are not in quotes
|
||||
reader.setLenient(true);
|
||||
AtomicReference<String> name = new AtomicReference<String>();
|
||||
JsonToken token = reader.peek();
|
||||
for (; token != JsonToken.END_DOCUMENT && nnn(this.name, reader, token, name); token = skipAndPeek(token,
|
||||
reader))
|
||||
;
|
||||
if (name.get().equals(this.name)) {
|
||||
return json.delegate().fromJson(reader, type.getType());
|
||||
} else {
|
||||
return nothing();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(String.format(
|
||||
"error reading from stream, parsing object named %s from http response %s", this.name, arg0), e);
|
||||
} finally {
|
||||
Closeables.closeQuietly(reader);
|
||||
arg0.getPayload().release();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T nothing() {
|
||||
if (type.getRawType().isAssignableFrom(Set.class))
|
||||
return (T) ImmutableSet.of();
|
||||
else if (type.getRawType().isAssignableFrom(List.class))
|
||||
return (T) ImmutableList.of();
|
||||
else if (type.getRawType().isAssignableFrom(Map.class))
|
||||
return (T) ImmutableMap.of();
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean nnn(String toFind, JsonReader reader, JsonToken token, AtomicReference<String> name)
|
||||
throws IOException {
|
||||
if (token == JsonToken.NAME) {
|
||||
String name2 = reader.nextName();
|
||||
if (toFind.equals(name2)) {
|
||||
name.set(name2);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public JsonToken skipAndPeek(JsonToken token, JsonReader reader) throws IOException {
|
||||
switch (token) {
|
||||
case BEGIN_ARRAY:
|
||||
reader.beginArray();
|
||||
break;
|
||||
case END_ARRAY:
|
||||
reader.endArray();
|
||||
break;
|
||||
case BEGIN_OBJECT:
|
||||
reader.beginObject();
|
||||
break;
|
||||
case END_OBJECT:
|
||||
reader.endObject();
|
||||
break;
|
||||
case NAME:
|
||||
// NOTE that we have already advanced on NAME in the eval block;
|
||||
break;
|
||||
case STRING:
|
||||
reader.nextString();
|
||||
break;
|
||||
case NUMBER:
|
||||
reader.nextString();
|
||||
break;
|
||||
case BOOLEAN:
|
||||
reader.nextBoolean();
|
||||
break;
|
||||
case NULL:
|
||||
reader.nextNull();
|
||||
break;
|
||||
case END_DOCUMENT:
|
||||
break;
|
||||
}
|
||||
return reader.peek();
|
||||
}
|
||||
}
|
|
@ -38,8 +38,8 @@ import org.jclouds.json.internal.EnumTypeAdapterThatReturnsFromValue;
|
|||
import org.jclouds.json.internal.GsonWrapper;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
|
|
@ -25,13 +25,14 @@ import javax.inject.Singleton;
|
|||
|
||||
import org.jclouds.json.Json;
|
||||
|
||||
import com.google.common.collect.ForwardingObject;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class GsonWrapper implements Json {
|
||||
public class GsonWrapper extends ForwardingObject implements Json {
|
||||
|
||||
private final Gson gson;
|
||||
|
||||
|
@ -61,4 +62,9 @@ public class GsonWrapper implements Json {
|
|||
return gson.toJson(src, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Gson delegate() {
|
||||
return gson;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.rest.annotations;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
/**
|
||||
* Extracts the only element of a collection or null
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see SelectJson
|
||||
*/
|
||||
@Target( { ANNOTATION_TYPE, METHOD, FIELD, PARAMETER })
|
||||
@Retention(RUNTIME)
|
||||
@Qualifier
|
||||
public @interface OnlyElement {
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.rest.annotations;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Selects a name in a json structure as opposed to parsing from root.
|
||||
*
|
||||
* ex. for "foo" { "foo" :"bar" } becomes "bar"
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Target(METHOD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface SelectJson {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
|
@ -46,8 +46,14 @@ public @interface Unwrap {
|
|||
*
|
||||
* { "foo" : {"bar" : ["baz"]} } becomes ["baz"]
|
||||
*
|
||||
* @return nestingLevel
|
||||
* <h4>Deprecation</h4>
|
||||
* <p/>
|
||||
* Note that using @SelectJson("bar") is more effective than guessing the
|
||||
* depth
|
||||
*
|
||||
* @see SelectJson
|
||||
*/
|
||||
@Deprecated
|
||||
int depth() default 1;
|
||||
|
||||
/**
|
||||
|
@ -62,9 +68,15 @@ public @interface Unwrap {
|
|||
* { "foo" : {"bar" : ["baz"]} } becomes "baz"
|
||||
*
|
||||
* <h4>Note</h4> only Map and Set are valid
|
||||
* <p/>
|
||||
* <h4>Deprecation</h4>
|
||||
* <p/>
|
||||
* Note that using @SelectJson("bar") @OnlyElement will have the same effect
|
||||
*
|
||||
* @return
|
||||
* @see SelectJson
|
||||
* @see OnlyElement
|
||||
*/
|
||||
@Deprecated
|
||||
Class<?> edgeCollection() default Map.class;
|
||||
|
||||
}
|
||||
|
|
|
@ -46,9 +46,9 @@ import java.util.Collections;
|
|||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -70,12 +70,15 @@ import javax.ws.rs.core.UriBuilderException;
|
|||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.functions.IdentityFunction;
|
||||
import org.jclouds.functions.OnlyElementOrNull;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpRequestFilter;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.functions.ParseFirstJsonValueNamed;
|
||||
import org.jclouds.http.functions.ParseJson;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
|
||||
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
|
||||
import org.jclouds.http.functions.ReleasePayloadAndReturn;
|
||||
import org.jclouds.http.functions.ReturnInputStream;
|
||||
|
@ -85,7 +88,6 @@ import org.jclouds.http.functions.UnwrapOnlyJsonValue;
|
|||
import org.jclouds.http.functions.UnwrapOnlyJsonValueInSet;
|
||||
import org.jclouds.http.functions.UnwrapOnlyNestedJsonValue;
|
||||
import org.jclouds.http.functions.UnwrapOnlyNestedJsonValueInSet;
|
||||
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
|
||||
import org.jclouds.http.options.HttpRequestOptions;
|
||||
import org.jclouds.http.utils.ModifyRequest;
|
||||
import org.jclouds.internal.ClassMethodArgs;
|
||||
|
@ -96,6 +98,7 @@ import org.jclouds.io.Payloads;
|
|||
import org.jclouds.io.payloads.MultipartForm;
|
||||
import org.jclouds.io.payloads.Part;
|
||||
import org.jclouds.io.payloads.Part.PartOptions;
|
||||
import org.jclouds.json.internal.GsonWrapper;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.rest.Binder;
|
||||
import org.jclouds.rest.InputParamValidator;
|
||||
|
@ -108,6 +111,7 @@ import org.jclouds.rest.annotations.FormParams;
|
|||
import org.jclouds.rest.annotations.Headers;
|
||||
import org.jclouds.rest.annotations.MapBinder;
|
||||
import org.jclouds.rest.annotations.MatrixParams;
|
||||
import org.jclouds.rest.annotations.OnlyElement;
|
||||
import org.jclouds.rest.annotations.OverrideRequestFilters;
|
||||
import org.jclouds.rest.annotations.ParamParser;
|
||||
import org.jclouds.rest.annotations.PartParam;
|
||||
|
@ -116,6 +120,7 @@ import org.jclouds.rest.annotations.PayloadParams;
|
|||
import org.jclouds.rest.annotations.QueryParams;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.annotations.Unwrap;
|
||||
import org.jclouds.rest.annotations.VirtualHost;
|
||||
|
@ -129,18 +134,19 @@ import org.jclouds.util.Strings2;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSet.Builder;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.ImmutableSet.Builder;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
|
@ -252,7 +258,7 @@ public class RestAnnotationProcessor<T> {
|
|||
if (handler != null) {
|
||||
transformer = parserFactory.create(injector.getInstance(handler));
|
||||
} else {
|
||||
transformer = injector.getInstance(getParserOrThrowException(method));
|
||||
transformer = getTransformerForMethod(method, injector);
|
||||
}
|
||||
if (transformer instanceof InvocationContext<?>) {
|
||||
((InvocationContext<?>) transformer).setContext(request);
|
||||
|
@ -260,6 +266,23 @@ public class RestAnnotationProcessor<T> {
|
|||
return transformer;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public static Function<HttpResponse, ?> getTransformerForMethod(Method method, Injector injector) {
|
||||
Function<HttpResponse, ?> transformer;
|
||||
if (method.isAnnotationPresent(SelectJson.class)) {
|
||||
Type returnVal = getReturnTypeForMethod(method);
|
||||
if (method.isAnnotationPresent(OnlyElement.class))
|
||||
returnVal = Types.newParameterizedType(Set.class,returnVal);
|
||||
transformer = new ParseFirstJsonValueNamed(injector.getInstance(GsonWrapper.class), TypeLiteral.get(returnVal),
|
||||
method.getAnnotation(SelectJson.class).value());
|
||||
if (method.isAnnotationPresent(OnlyElement.class))
|
||||
transformer = Functions.compose(new OnlyElementOrNull(), transformer);
|
||||
} else {
|
||||
transformer = injector.getInstance(getParserOrThrowException(method));
|
||||
}
|
||||
return transformer;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Function<Exception, ?> createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(Method method) {
|
||||
return createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(injector, method);
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.http.functions;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.io.Payloads;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.json.internal.GsonWrapper;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class UnwrapFirstValueNamedTest {
|
||||
|
||||
GsonWrapper json = Guice.createInjector(new GsonModule()).getInstance(GsonWrapper.class);
|
||||
|
||||
static class Event {
|
||||
private String name;
|
||||
private String source;
|
||||
|
||||
private Event(String name, String source) {
|
||||
this.name = name;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("(name=%s, source=%s)", name, source);
|
||||
}
|
||||
}
|
||||
|
||||
public void testParseNestedElements() 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").apply(response);
|
||||
assertEquals(val.toString(), "[(name=GREETINGS, source=guest)]");
|
||||
}
|
||||
|
||||
public void testParseNestedElementsButNothing() throws IOException {
|
||||
String nested = "{ \"count\":1 ,\"event\" : [ ] }";
|
||||
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").apply(response);
|
||||
assertEquals(val.toString(), "[]");
|
||||
}
|
||||
|
||||
public void testParseNestedFurtherElements() throws IOException {
|
||||
String nestedFurther = "{ \"listaccountsresponse\" : { \"count\":1 ,\"event\" : [ {name:'GREETINGS',source:'guest'} ] } }";
|
||||
HttpResponse response = HttpResponse.builder().statusCode(200).message("goodie")
|
||||
.payload(Payloads.newPayload(nestedFurther)).build();
|
||||
|
||||
List<Event> val = new ParseFirstJsonValueNamed<List<Event>>(json, new TypeLiteral<List<Event>>() {
|
||||
}, "event").apply(response);
|
||||
assertEquals(val.toString(), "[(name=GREETINGS, source=guest)]");
|
||||
}
|
||||
|
||||
public void testParseNestedFurtherElementsButNothing() throws IOException {
|
||||
String nestedFurther = "{ \"listaccountsresponse\" : { \"count\":1 ,\"event\" : [ ] } }";
|
||||
HttpResponse response = HttpResponse.builder().statusCode(200).message("goodie")
|
||||
.payload(Payloads.newPayload(nestedFurther)).build();
|
||||
|
||||
List<Event> val = new ParseFirstJsonValueNamed<List<Event>>(json, new TypeLiteral<List<Event>>() {
|
||||
}, "event").apply(response);
|
||||
assertEquals(val.toString(), "[]");
|
||||
}
|
||||
|
||||
public void testParseNoPayloadEmptyList() throws IOException {
|
||||
HttpResponse response = HttpResponse.builder().statusCode(200).message("goodie").build();
|
||||
|
||||
List<Event> val = new ParseFirstJsonValueNamed<List<Event>>(json, new TypeLiteral<List<Event>>() {
|
||||
}, "event").apply(response);
|
||||
assertEquals(val, ImmutableList.<Event> of());
|
||||
}
|
||||
|
||||
public void testParseNoPayloadEmptyMap() throws IOException {
|
||||
HttpResponse response = HttpResponse.builder().statusCode(200).message("goodie").build();
|
||||
|
||||
Map<String, String> val = new ParseFirstJsonValueNamed<Map<String, String>>(json,
|
||||
new TypeLiteral<Map<String, String>>() {
|
||||
}, "event").apply(response);
|
||||
assertEquals(val, ImmutableMap.<String, String> of());
|
||||
}
|
||||
|
||||
public void testParseNoPayloadEmptySet() throws IOException {
|
||||
HttpResponse response = HttpResponse.builder().statusCode(200).message("goodie").build();
|
||||
|
||||
Set<Event> val = new ParseFirstJsonValueNamed<Set<Event>>(json, new TypeLiteral<Set<Event>>() {
|
||||
}, "event").apply(response);
|
||||
assertEquals(val, ImmutableSet.<Event> of());
|
||||
}
|
||||
}
|
|
@ -55,8 +55,8 @@ public abstract class BaseParserTest<T, G> {
|
|||
@SuppressWarnings("unchecked")
|
||||
protected Function<HttpResponse, T> parser(Injector i) {
|
||||
try {
|
||||
return (Function<HttpResponse, T>) i.getInstance(RestAnnotationProcessor.getJsonParserKeyForMethod(getClass()
|
||||
.getMethod("expected")));
|
||||
return (Function<HttpResponse, T>) RestAnnotationProcessor.getTransformerForMethod(getClass()
|
||||
.getMethod("expected"), i);
|
||||
} catch (Exception e) {
|
||||
Throwables.propagate(e);
|
||||
return null;
|
||||
|
|
|
@ -89,6 +89,7 @@ import org.jclouds.http.HttpResponse;
|
|||
import org.jclouds.http.IOExceptionRetryHandler;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
import org.jclouds.http.TransformingHttpCommandExecutorService;
|
||||
import org.jclouds.http.functions.ParseFirstJsonValueNamed;
|
||||
import org.jclouds.http.functions.ParseJson;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
|
||||
|
@ -122,6 +123,7 @@ import org.jclouds.rest.annotations.FormParams;
|
|||
import org.jclouds.rest.annotations.Headers;
|
||||
import org.jclouds.rest.annotations.MapBinder;
|
||||
import org.jclouds.rest.annotations.MatrixParams;
|
||||
import org.jclouds.rest.annotations.OnlyElement;
|
||||
import org.jclouds.rest.annotations.OverrideRequestFilters;
|
||||
import org.jclouds.rest.annotations.ParamParser;
|
||||
import org.jclouds.rest.annotations.PartParam;
|
||||
|
@ -130,6 +132,7 @@ import org.jclouds.rest.annotations.PayloadParams;
|
|||
import org.jclouds.rest.annotations.QueryParams;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.annotations.Unwrap;
|
||||
import org.jclouds.rest.annotations.VirtualHost;
|
||||
|
@ -801,6 +804,12 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
String testUnwrap();
|
||||
|
||||
@GET
|
||||
@Path("/")
|
||||
@SelectJson("foo")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
String testUnwrapValueNamed();
|
||||
|
||||
@POST
|
||||
@Path("/")
|
||||
String testWrapWith(@WrapWith("foo") String param);
|
||||
|
@ -835,12 +844,24 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
ListenableFuture<Long> testUnwrapDepth2Long();
|
||||
|
||||
@GET
|
||||
@Path("/")
|
||||
@SelectJson("jobid")
|
||||
ListenableFuture<Long> selectLong();
|
||||
|
||||
@GET
|
||||
@Path("/")
|
||||
@Unwrap(depth = 2, edgeCollection = Set.class)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
ListenableFuture<String> testUnwrapDepth2Set();
|
||||
|
||||
@GET
|
||||
@Path("/")
|
||||
@SelectJson("runit")
|
||||
@OnlyElement
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
ListenableFuture<String> selectOnlyElement();
|
||||
|
||||
@GET
|
||||
@Path("/")
|
||||
@Unwrap(depth = 3, edgeCollection = Set.class)
|
||||
|
@ -984,6 +1005,21 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testUnwrapValueNamed() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPut.class.getMethod("testUnwrapValueNamed");
|
||||
HttpRequest request = factory(TestPut.class).createRequest(method);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseFirstJsonValueNamed.class);
|
||||
// now test that it works!
|
||||
|
||||
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
|
||||
.createResponseParser(parserFactory, injector, method, request);
|
||||
|
||||
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))), "bar");
|
||||
|
||||
}
|
||||
public void testWrapWith() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPut.class.getMethod("testWrapWith", String.class);
|
||||
HttpRequest request = factory(TestPut.class).createRequest(method, "bar");
|
||||
|
@ -1069,6 +1105,20 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{\"runit\":[]}"))), null);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSelectOnlyElement() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPut.class.getMethod("selectOnlyElement");
|
||||
HttpRequest request = factory(TestPut.class).createRequest(method);
|
||||
|
||||
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
|
||||
.createResponseParser(parserFactory, injector, method, request);
|
||||
|
||||
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{\"runit\":[\"0.7.0\"]}"))), "0.7.0");
|
||||
|
||||
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{\"runit\":[]}"))), null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testUnwrapDepth2Long() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPut.class.getMethod("testUnwrapDepth2Long");
|
||||
|
@ -1084,6 +1134,21 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
|||
newStringPayload("{ \"destroyvirtualmachineresponse\" : {\"jobid\":4} }"))), new Long(4));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void selectLong() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPut.class.getMethod("selectLong");
|
||||
HttpRequest request = factory(TestPut.class).createRequest(method);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseFirstJsonValueNamed.class);
|
||||
// now test that it works!
|
||||
|
||||
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
|
||||
.createResponseParser(parserFactory, injector, method, request);
|
||||
|
||||
assertEquals(parser.apply(new HttpResponse(200, "ok",
|
||||
newStringPayload("{ \"destroyvirtualmachineresponse\" : {\"jobid\":4} }"))), new Long(4));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testUnwrapDepth3() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestPut.class.getMethod("testUnwrapDepth3");
|
||||
|
|
Loading…
Reference in New Issue