added endpoint parser that can collaborate with multiple parameters

This commit is contained in:
Adrian Cole 2010-08-09 01:26:59 -07:00
parent 10c2a0e36b
commit 1ec0c40c95
2 changed files with 282 additions and 209 deletions

View File

@ -613,13 +613,15 @@ public class RestAnnotationProcessor<T> {
} }
@VisibleForTesting @VisibleForTesting
public static URI getEndpointInParametersOrNull(Method method, Object[] args, Injector injector) { public static URI getEndpointInParametersOrNull(Method method, final Object[] args, Injector injector) {
Map<Integer, Set<Annotation>> map = RestAnnotationProcessor.indexWithOnlyOneAnnotation(method, "@EndpointParam", Map<Integer, Set<Annotation>> map = indexWithAtLeastOneAnnotation(method,
RestAnnotationProcessor.methodToIndexOfParamToEndpointParamAnnotations); methodToIndexOfParamToEndpointParamAnnotations);
if (map.size() == 1 && args.length > 0) { if (map.size() >= 1 && args.length > 0) {
EndpointParam annotation = (EndpointParam) map.values().iterator().next().iterator().next(); EndpointParam firstAnnotation = (EndpointParam) Iterables.get(Iterables.get(map.values(), 0), 0);
Function<Object, URI> parser = injector.getInstance(firstAnnotation.parser());
if (map.size() == 1) {
int index = map.keySet().iterator().next(); int index = map.keySet().iterator().next();
Function<Object, URI> parser = injector.getInstance(annotation.parser());
try { try {
URI returnVal = parser.apply(args[index]); URI returnVal = parser.apply(args[index]);
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", args[index], checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", args[index],
@ -628,6 +630,25 @@ public class RestAnnotationProcessor<T> {
} catch (NullPointerException e) { } catch (NullPointerException e) {
throw new IllegalArgumentException(String.format("argument at index %d on method %s", index, method), e); throw new IllegalArgumentException(String.format("argument at index %d on method %s", index, method), e);
} }
} else {
Iterable<Object> argsToParse = Iterables.transform(map.keySet(), new Function<Integer, Object>() {
@Override
public Object apply(Integer from) {
return args[from];
}
});
try {
URI returnVal = parser.apply(argsToParse);
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", argsToParse,
method));
return returnVal;
} catch (NullPointerException e) {
throw new IllegalArgumentException(String.format("argument at indexes %s on method %s", map.keySet(),
method), e);
}
}
} }
return null; return null;
} }
@ -831,18 +852,23 @@ public class RestAnnotationProcessor<T> {
public static Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method, String description, public static Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method, String description,
Map<Method, Map<Integer, Set<Annotation>>> toRefine) { Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = indexWithAtLeastOneAnnotation(method, toRefine);
if (indexToPayloadAnnotation.size() > 1) {
throw new IllegalStateException(String.format(
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
indexToPayloadAnnotation));
}
return indexToPayloadAnnotation;
}
private static Map<Integer, Set<Annotation>> indexWithAtLeastOneAnnotation(Method method,
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method), Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method),
new Predicate<Set<Annotation>>() { new Predicate<Set<Annotation>>() {
public boolean apply(Set<Annotation> input) { public boolean apply(Set<Annotation> input) {
return input.size() == 1; return input.size() == 1;
} }
}); });
if (indexToPayloadAnnotation.size() > 1) {
throw new IllegalStateException(String.format(
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
indexToPayloadAnnotation));
}
return indexToPayloadAnnotation; return indexToPayloadAnnotation;
} }

View File

@ -60,6 +60,7 @@ import javax.annotation.Nullable;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Qualifier; import javax.inject.Qualifier;
import javax.inject.Singleton;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam; import javax.ws.rs.FormParam;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@ -138,6 +139,7 @@ import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -1786,22 +1788,18 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
factory(TestVirtualHost.class).createRequest(method, "1", ""); factory(TestVirtualHost.class).createRequest(method, "1", "");
} }
public class TestHeaders { public interface TestHeaders {
@GET @GET
public void oneHeader(@HeaderParam("header") String header) { void oneHeader(@HeaderParam("header") String header);
}
@GET @GET
public void oneIntHeader(@HeaderParam("header") int header) { void oneIntHeader(@HeaderParam("header") int header);
}
@GET @GET
public void twoDifferentHeaders(@HeaderParam("header1") String header1, @HeaderParam("header2") String header2) { void twoDifferentHeaders(@HeaderParam("header1") String header1, @HeaderParam("header2") String header2);
}
@GET @GET
public void twoSameHeaders(@HeaderParam("header") String header1, @HeaderParam("header") String header2) { void twoSameHeaders(@HeaderParam("header") String header1, @HeaderParam("header") String header2);
}
} }
@Test @Test
@ -1843,6 +1841,56 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
assert values.contains("egg"); assert values.contains("egg");
} }
public interface TestEndpointParams {
@GET
void oneEndpointParam(@EndpointParam(parser = ConvertToURI.class) String EndpointParam);
@Singleton
public static class ConvertToURI implements Function<Object, URI> {
@Override
public URI apply(Object from) {
return URI.create(from.toString());
}
}
@GET
void twoEndpointParams(@EndpointParam(parser = ConvertTwoToURI.class) String EndpointParam1,
@EndpointParam(parser = ConvertTwoToURI.class) String EndpointParam2);
@Singleton
public static class ConvertTwoToURI implements Function<Object, URI> {
@SuppressWarnings("unchecked")
@Override
public URI apply(Object from) {
return URI.create(Joiner.on('/').join((Iterable<Object>) from));
}
}
}
@SuppressWarnings("static-access")
@Test
public void testOneEndpointParam() throws SecurityException, NoSuchMethodException {
Method method = TestEndpointParams.class.getMethod("oneEndpointParam", String.class);
URI uri = factory(TestEndpointParams.class).getEndpointInParametersOrNull(method, new Object[] { "robot" },
injector);
assertEquals(uri, URI.create("robot"));
}
@SuppressWarnings("static-access")
@Test
public void testTwoDifferentEndpointParams() throws SecurityException, NoSuchMethodException {
Method method = TestEndpointParams.class.getMethod("twoEndpointParams", String.class, String.class);
URI uri = factory(TestEndpointParams.class).getEndpointInParametersOrNull(method,
new Object[] { "robot", "egg" }, injector);
assertEquals(uri, URI.create("robot/egg"));
}
public interface TestPayload { public interface TestPayload {
@PUT @PUT
public void put(@BinderParam(BindToStringPayload.class) String content); public void put(@BinderParam(BindToStringPayload.class) String content);
@ -1975,8 +2023,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@Override @Override
protected void configure() { protected void configure() {
bind(URI.class).annotatedWith(Localhost2.class).toInstance( bind(URI.class).annotatedWith(Localhost2.class).toInstance(URI.create("http://localhost:1111"));
URI.create("http://localhost:1111"));
} }
})); }));