Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend ResourceVisitor to hold parameters type information #11

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
18 changes: 15 additions & 3 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
<version>HEAD-SNAPSHOT</version>
</parent>
<artifactId>autorest-core</artifactId>
<packaging>jar</packaging>
<packaging>gwt-lib</packaging>
<name>AutoREST :: core</name>

<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
Expand Down Expand Up @@ -40,6 +40,18 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>net.ltgt.gwt.maven</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<configuration>
<moduleName>com.intendia.gwt.autorest</moduleName>
<moduleShortName>autorest</moduleShortName>
</configuration>
</plugin>
</plugins>
</build>
</project>


Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.annotation.Nullable;
import javax.ws.rs.HttpMethod;

Expand All @@ -16,29 +17,31 @@ public abstract class CollectorResourceVisitor implements ResourceVisitor {
private static final String ABSOLUTE_PATH = "[a-z][a-z0-9+.-]*:.*|//.*";
private static final List<Integer> DEFAULT_EXPECTED_STATUS = asList(200, 201, 204, 1223/*MSIE*/);

public static class Param {
public static class Param<T> {
public final String k;
public final Object v;
public Param(String k, Object v) { this.k = k; this.v = v; }
public static List<Param> expand(List<Param> in) {
List<Param> out = new ArrayList<>();
for (Param p : in) {
public final T v;
public final TypeToken<T> t;
public Param(String k, T v, TypeToken<T> t) { this.k = k; this.v = v; this.t = t; }

public static List<Param<?>> expand(List<Param<?>> in) {
List<Param<?>> out = new ArrayList<>();
for (Param<?> p : in) {
if (!(p.v instanceof Iterable<?>)) out.add(p);
else for (Object v : ((Iterable<?>) p.v)) out.add(new Param(p.k, v));
else for (Object v : ((Iterable<?>) p.v)) out.add(new Param<Object>(p.k, v, null));
}
return out;
}
@Override public String toString() { return "Param{k='" + k + "', v=" + v + '}'; }
@Override public String toString() { return "Param{k='" + k + "', v=" + v + ", t='" + t + '}'; }
}

protected List<String> paths = new ArrayList<>();
protected List<Param> queryParams = new ArrayList<>();
protected List<Param> headerParams = new ArrayList<>();
protected List<Param> formParams = new ArrayList<>();
protected List<Object> paths = new ArrayList<>();
protected List<Param<?>> queryParams = new ArrayList<>();
protected List<Param<?>> headerParams = new ArrayList<>();
protected List<Param<?>> formParams = new ArrayList<>();
protected String method = HttpMethod.GET;
protected String produces[] = { "application/json" };
protected String consumes[] = { "application/json" };
protected Object data = null;
protected Param<?> data = null;
private List<Integer> expectedStatuses = DEFAULT_EXPECTED_STATUS;

@Override public ResourceVisitor method(String method) {
Expand All @@ -59,6 +62,11 @@ public ResourceVisitor path(String path) {
return this;
}

@Override public <T> ResourceVisitor path(@Nullable T value, TypeToken<T> typeToken) {
if (value != null) paths.add(new Param<>(null, value, typeToken));
return this;
}

@Override public ResourceVisitor produces(String... produces) {
if (produces.length > 0 /*0 means undefined, so do not override default*/) this.produces = produces;
return this;
Expand All @@ -69,34 +77,41 @@ public ResourceVisitor path(String path) {
return this;
}

@Override public ResourceVisitor param(String key, @Nullable Object value) {
@Override public <T> ResourceVisitor param(String key, @Nullable T value, TypeToken<T> typeToken) {
Objects.requireNonNull(key, "query param key required");
if (value != null) queryParams.add(new Param(key, value));
if (value != null) queryParams.add(new Param<>(key, value, typeToken));
return this;
}

@Override public ResourceVisitor header(String key, @Nullable Object value) {
@Override public <T> ResourceVisitor header(String key, @Nullable T value, TypeToken<T> typeToken) {
Objects.requireNonNull(key, "header param key required");
if (value != null) headerParams.add(new Param(key, value));
if (value != null) headerParams.add(new Param<>(key, value, typeToken));
return this;
}

@Override public ResourceVisitor form(String key, @Nullable Object value) {
@Override public <T> ResourceVisitor form(String key, @Nullable T value, TypeToken<T> typeToken) {
Objects.requireNonNull(key, "form param key required");
if (value != null) formParams.add(new Param(key, value));
if (value != null) formParams.add(new Param<>(key, value, typeToken));
return this;
}

@Override public ResourceVisitor data(Object data) {
this.data = data;
@Override public <T> ResourceVisitor data(T data, TypeToken<T> typeToken) {
this.data = new Param<>(null, data, typeToken);
return this;
}

public String method() { return method; }

public String uri() {
String path = "";
for (String p : paths) path += p;
for (Object p : paths) {
if (p instanceof Param<?>) {
Param<?> param = (Param<?>)p;
path += encodeComponent(Objects.toString(param.v));
} else
path += p;
}

return path + query();
}

Expand All @@ -105,9 +120,9 @@ public String query() {
return q.isEmpty() ? "" : "?" + q;
}

protected String encodeParams(List<Param> params) {
protected String encodeParams(List<Param<?>> params) {
String q = "";
for (Param p : expand(params)) {
for (Param<?> p : expand(params)) {
q += (q.isEmpty() ? "" : "&") + encodeComponent(p.k) + "=" + encodeComponent(Objects.toString(p.v));
}
return q;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.intendia.gwt.autorest.client;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* GWT & J2CL will skip any classes or methods marked with this annotation (or any other as long as it is named "@GwtIncompatible")
*/
@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GwtIncompatible {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.intendia.gwt.autorest.client;

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;

/**
* A set of private utility methods used by {@link TypeToken} in JavaSE/Android environments.
*/
@GwtIncompatible
class ReflectionTypeUtils {
private ReflectionTypeUtils() {}

public static Type[] getActualTypeArguments(Type type) {
if (type instanceof ParameterizedType)
return ((ParameterizedType) type).getActualTypeArguments();
else
return new Type[0];
}

public static Class<?> getRawType(Type type) {
// For wildcard or type variable, the first bound determines the runtime type.
return getRawTypes(type).iterator().next();
}

private static Collection<Class<?>> getRawTypes(Type type) {
if (type instanceof Class<?>) {
return Collections.<Class<?>>singleton((Class<?>) type);
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// JDK implementation declares getRawType() to return Class<?>: http://goo.gl/YzaEd
return Collections.<Class<?>>singleton((Class<?>) parameterizedType.getRawType());
} else if (type instanceof GenericArrayType) {
GenericArrayType genericArrayType = (GenericArrayType) type;
return Collections.<Class<?>>singleton(getArrayClass(getRawType(genericArrayType.getGenericComponentType())));
} else if (type instanceof TypeVariable) {
return getRawTypes(((TypeVariable<?>) type).getBounds());
} else if (type instanceof WildcardType) {
return getRawTypes(((WildcardType) type).getUpperBounds());
} else {
throw new AssertionError(type + " unsupported");
}
}

/** Returns the {@code Class} object of arrays with {@code componentType}. */
private static Class<?> getArrayClass(Class<?> componentType) {
return Array.newInstance(componentType, 0).getClass();
}

private static Collection<Class<?>> getRawTypes(Type[] types) {
return Arrays.stream(types)
.flatMap(type -> getRawTypes(type).stream())
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,29 @@ public interface ResourceVisitor {
/** Append paths, or set if the path is absolute. */
ResourceVisitor path(Object... paths);

/** Sets a path param with its type */
<T> ResourceVisitor path(@Nullable T value, TypeToken<T> typeToken);

/** Sets the produced media-type. */
ResourceVisitor produces(String... produces);

/** Sets the consumed media-type. */
ResourceVisitor consumes(String... consumes);

/** Sets a query param. */
ResourceVisitor param(String key, @Nullable Object value);
/** Sets a query param with its type */
<T> ResourceVisitor param(String key, @Nullable T value, TypeToken<T> typeToken);

/** Sets a header param. */
ResourceVisitor header(String key, @Nullable Object value);
/** Sets a header param with its type. */
<T> ResourceVisitor header(String key, @Nullable T value, TypeToken<T> typeToken);

/** Sets a from param. */
ResourceVisitor form(String key, @Nullable Object value);
/** Sets a form param with its type. */
<T> ResourceVisitor form(String key, @Nullable T value, TypeToken<T> typeToken);

/** Sets the content data with its type. */
<T> ResourceVisitor data(T data, TypeToken<T> typeToken);

/** Sets the content data. */
ResourceVisitor data(Object data);

/** Wrap the current resource state into a {@code container}. */
<T> T as(Class<? super T> container, Class<?> type);
/** Wrap the current resource state into a {@code type}. */
<T> T as(TypeToken<T> typeToken);

interface Supplier {
ResourceVisitor get();
Expand Down
Loading