mirror of
https://github.com/apache/jclouds.git
synced 2025-02-16 06:56:45 +00:00
Merge pull request #1139 from nacx/jaxb-custom-class
Make JAXBResponseParser parameterizable
This commit is contained in:
commit
67b385f8e1
@ -24,6 +24,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.lang.model.type.NullType;
|
||||
|
||||
import org.jclouds.http.functions.ParseXMLWithJAXB;
|
||||
|
||||
/**
|
||||
* Shows the transformer type used to parse XML with the
|
||||
* {@link ParseXMLWithJAXB} parser in a HttpResponse.
|
||||
@ -34,4 +38,10 @@ import java.lang.annotation.Target;
|
||||
@Retention(RUNTIME)
|
||||
public @interface JAXBResponseParser {
|
||||
|
||||
/**
|
||||
* If present, this is the class that will be used to unmarshal the XML
|
||||
* document. If omitted, the return type of the annotated method will be
|
||||
* used.
|
||||
*/
|
||||
Class<?> value() default NullType.class;
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.lang.model.type.NullType;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.FormParam;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
@ -815,10 +816,16 @@ public abstract class RestAnnotationProcessor {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Key<? extends Function<HttpResponse, ?>> getJAXBParserKeyForMethod(Method method) {
|
||||
Type returnVal = getReturnTypeForMethod(method);
|
||||
Type parserType = Types.newParameterizedType(ParseXMLWithJAXB.class, returnVal);
|
||||
return (Key<? extends Function<HttpResponse, ?>>) Key.get(parserType);
|
||||
}
|
||||
Optional<Type> configuredReturnVal = Optional.absent();
|
||||
if (method.isAnnotationPresent(JAXBResponseParser.class)) {
|
||||
Type configuredClass = method.getAnnotation(JAXBResponseParser.class).value();
|
||||
configuredReturnVal = configuredClass.equals(NullType.class) ? Optional.<Type> absent() : Optional
|
||||
.<Type> of(configuredClass);
|
||||
}
|
||||
Type returnVal = configuredReturnVal.or(getReturnTypeForMethod(method));
|
||||
Type parserType = Types.newParameterizedType(ParseXMLWithJAXB.class, returnVal);
|
||||
return (Key<? extends Function<HttpResponse, ?>>) Key.get(parserType);
|
||||
}
|
||||
|
||||
public static Type getReturnTypeForMethod(Method method) {
|
||||
Type returnVal;
|
||||
|
@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you 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.annotationparsing;
|
||||
|
||||
import static org.jclouds.providers.AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.providers.ProviderMetadata;
|
||||
import org.jclouds.rest.annotations.JAXBResponseParser;
|
||||
import org.jclouds.rest.annotations.Transform;
|
||||
import org.jclouds.rest.internal.BaseRestClientExpectTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
* Tests the use of the {@link JAXBResponseParser} annotation.
|
||||
*
|
||||
* @author Ignasi Barrera
|
||||
*/
|
||||
@Test(groups = "unit", testName = "JAXBResponseParserAnnotationExpectTest")
|
||||
public class JAXBResponseParserAnnotationExpectTest extends
|
||||
BaseRestClientExpectTest<JAXBResponseParserAnnotationExpectTest.TestJAXBApi> {
|
||||
|
||||
@XmlRootElement(name = "test")
|
||||
public static class TestJAXBDomain {
|
||||
private String elem;
|
||||
|
||||
public String getElem() {
|
||||
return elem;
|
||||
}
|
||||
|
||||
public void setElem(String elem) {
|
||||
this.elem = elem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TestJAXBDomain [elem=" + elem + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface TestJAXBApi {
|
||||
public TestJAXBDomain jaxbGetWithAnnotation();
|
||||
|
||||
public Object jaxbGetWithAnnotationAndCustomClass();
|
||||
|
||||
public TestJAXBDomain jaxbGetWithAcceptHeader();
|
||||
|
||||
public String jaxbGetWithTransformer();
|
||||
}
|
||||
|
||||
public interface TestJAXBAsyncApi {
|
||||
@GET
|
||||
@Path("/jaxb/annotation")
|
||||
@JAXBResponseParser
|
||||
public ListenableFuture<TestJAXBDomain> jaxbGetWithAnnotation();
|
||||
|
||||
@GET
|
||||
@Path("/jaxb/custom")
|
||||
@JAXBResponseParser(TestJAXBDomain.class)
|
||||
public ListenableFuture<Object> jaxbGetWithAnnotationAndCustomClass();
|
||||
|
||||
@GET
|
||||
@Path("/jaxb/header")
|
||||
@Consumes(MediaType.APPLICATION_XML)
|
||||
public ListenableFuture<TestJAXBDomain> jaxbGetWithAcceptHeader();
|
||||
|
||||
@GET
|
||||
@Path("/jaxb/transformer")
|
||||
@JAXBResponseParser(TestJAXBDomain.class)
|
||||
@Transform(ToString.class)
|
||||
public ListenableFuture<String> jaxbGetWithTransformer();
|
||||
}
|
||||
|
||||
private static class ToString implements Function<Object, String> {
|
||||
@Override
|
||||
public String apply(Object input) {
|
||||
return Functions.toStringFunction().apply(input);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJAXBResponseParserAnnotationWithoutValue() throws SecurityException, NoSuchMethodException {
|
||||
TestJAXBApi api = requestSendsResponse( //
|
||||
HttpRequest.builder().method("GET").endpoint("http://mock/jaxb/annotation").build(), //
|
||||
HttpResponse.builder().statusCode(200).payload("<test><elem>Hello World</elem></test>").build());
|
||||
|
||||
TestJAXBDomain result = api.jaxbGetWithAnnotation();
|
||||
assertEquals(result.getElem(), "Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJAXBResponseParserAnnotationWithCustomValue() throws SecurityException, NoSuchMethodException {
|
||||
TestJAXBApi api = requestSendsResponse( //
|
||||
HttpRequest.builder().method("GET").endpoint("http://mock/jaxb/custom").build(), //
|
||||
HttpResponse.builder().statusCode(200).payload("<test><elem>Hello World</elem></test>").build());
|
||||
|
||||
Object result = api.jaxbGetWithAnnotationAndCustomClass();
|
||||
assertTrue(result instanceof TestJAXBDomain);
|
||||
assertEquals(TestJAXBDomain.class.cast(result).getElem(), "Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJAXBResponseParserAnnotationWithAcceptHeader() throws SecurityException, NoSuchMethodException {
|
||||
TestJAXBApi api = requestSendsResponse( //
|
||||
HttpRequest.builder().method("GET").endpoint("http://mock/jaxb/header")
|
||||
.addHeader("Accept", MediaType.APPLICATION_XML).build(), //
|
||||
HttpResponse.builder().statusCode(200).payload("<test><elem>Hello World</elem></test>").build());
|
||||
|
||||
TestJAXBDomain result = api.jaxbGetWithAcceptHeader();
|
||||
assertEquals(result.getElem(), "Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJAXBResponseParserAnnotationWithTransformer() throws SecurityException, NoSuchMethodException {
|
||||
TestJAXBApi api = requestSendsResponse( //
|
||||
HttpRequest.builder().method("GET").endpoint("http://mock/jaxb/transformer").build(), //
|
||||
HttpResponse.builder().statusCode(200).payload("<test><elem>Hello World</elem></test>").build());
|
||||
|
||||
String result = api.jaxbGetWithTransformer();
|
||||
assertEquals(result, "TestJAXBDomain [elem=Hello World]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderMetadata createProviderMetadata() {
|
||||
return forClientMappedToAsyncClientOnEndpoint(TestJAXBApi.class, TestJAXBAsyncApi.class, "http://mock");
|
||||
}
|
||||
|
||||
}
|
@ -20,8 +20,9 @@ package org.jclouds.rest.binders;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessorTest.TestJAXBDomain;
|
||||
import org.jclouds.xml.XMLParser;
|
||||
import org.jclouds.xml.internal.JAXBParser;
|
||||
import org.testng.annotations.Test;
|
||||
@ -48,7 +49,8 @@ public class BindToXMLPayloadTest {
|
||||
|
||||
HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://momma").build();
|
||||
request = binder.bindToRequest(request, obj);
|
||||
assertEquals(request.getPayload().getRawContent(), XMLParser.DEFAULT_XML_HEADER + "\n<test>\n <elem>Hello World</elem>\n</test>\n");
|
||||
assertEquals(request.getPayload().getRawContent(), XMLParser.DEFAULT_XML_HEADER
|
||||
+ "\n<test>\n <elem>Hello World</elem>\n</test>\n");
|
||||
assertEquals(request.getPayload().getContentMetadata().getContentType(), "application/xml");
|
||||
}
|
||||
|
||||
@ -63,11 +65,11 @@ public class BindToXMLPayloadTest {
|
||||
// Add the unknown content-type header to verify it is changed by the
|
||||
// binder
|
||||
Multimap<String, String> headers = ImmutableMultimap.<String, String> of("Content-type", "application/unknown");
|
||||
HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://momma").headers(headers)
|
||||
.build();
|
||||
HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://momma").headers(headers).build();
|
||||
|
||||
request = binder.bindToRequest(request, obj);
|
||||
assertEquals(request.getPayload().getRawContent(), XMLParser.DEFAULT_XML_HEADER + "\n<test>\n <elem>Hello World</elem>\n</test>\n");
|
||||
assertEquals(request.getPayload().getRawContent(), XMLParser.DEFAULT_XML_HEADER
|
||||
+ "\n<test>\n <elem>Hello World</elem>\n</test>\n");
|
||||
assertEquals(request.getPayload().getContentMetadata().getContentType(), "application/xml");
|
||||
}
|
||||
|
||||
@ -83,4 +85,18 @@ public class BindToXMLPayloadTest {
|
||||
HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://momma").build();
|
||||
request = binder.bindToRequest(request, new Object());
|
||||
}
|
||||
|
||||
@XmlRootElement(name = "test")
|
||||
public static class TestJAXBDomain {
|
||||
private String elem;
|
||||
|
||||
public String getElem() {
|
||||
return elem;
|
||||
}
|
||||
|
||||
public void setElem(String elem) {
|
||||
this.elem = elem;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2437,87 +2437,6 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest {
|
||||
assertEquals(form, "x-amz-copy-source=/eggs/robot");
|
||||
}
|
||||
|
||||
public interface TestJAXBResponseParser {
|
||||
@GET
|
||||
@Path("/jaxb/annotation")
|
||||
@JAXBResponseParser
|
||||
public ListenableFuture<TestJAXBDomain> jaxbGetWithAnnotation();
|
||||
|
||||
@GET
|
||||
@Path("/jaxb/header")
|
||||
@Consumes("application/xml")
|
||||
public ListenableFuture<TestJAXBDomain> jaxbGetWithAcceptHeader();
|
||||
}
|
||||
|
||||
@XmlRootElement(name = "test")
|
||||
public static class TestJAXBDomain {
|
||||
private String elem;
|
||||
|
||||
public String getElem() {
|
||||
return elem;
|
||||
}
|
||||
|
||||
public void setElem(String elem) {
|
||||
this.elem = elem;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateJAXBResponseParserWithAnnotation() throws SecurityException, NoSuchMethodException {
|
||||
RestAnnotationProcessor processor = factory(TestJAXBResponseParser.class);
|
||||
Method method = TestJAXBResponseParser.class.getMethod("jaxbGetWithAnnotation");
|
||||
GeneratedHttpRequest request = GeneratedHttpRequest.builder().method("GET").endpoint("http://localhost")
|
||||
.declaring(TestJAXBResponseParser.class).javaMethod(method).args(new Object[] {}).build();
|
||||
Function<HttpResponse, ?> transformer = processor.createResponseParser(method, request);
|
||||
assertEquals(transformer.getClass(), ParseXMLWithJAXB.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateJAXBResponseParserWithAcceptHeader() throws SecurityException, NoSuchMethodException {
|
||||
RestAnnotationProcessor processor = factory(TestJAXBResponseParser.class);
|
||||
Method method = TestJAXBResponseParser.class.getMethod("jaxbGetWithAcceptHeader");
|
||||
GeneratedHttpRequest request = GeneratedHttpRequest.builder().method("GET").endpoint("http://localhost")
|
||||
.declaring(TestJAXBResponseParser.class).javaMethod(method).args(new Object[] {}).build();
|
||||
Function<HttpResponse, ?> transformer = processor.createResponseParser(method, request);
|
||||
assertEquals(transformer.getClass(), ParseXMLWithJAXB.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testJAXBResponseParserWithAnnotation() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestJAXBResponseParser.class.getMethod("jaxbGetWithAnnotation");
|
||||
HttpRequest request = factory(TestJAXBResponseParser.class).createRequest(method);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
|
||||
// now test that it works!
|
||||
|
||||
Function<HttpResponse, TestJAXBDomain> parser = (Function<HttpResponse, TestJAXBDomain>) RestAnnotationProcessor
|
||||
.createResponseParser(parserFactory, injector, method, request);
|
||||
|
||||
StringBuilder payload = new StringBuilder(XMLParser.DEFAULT_XML_HEADER);
|
||||
payload.append("<test><elem>Hello World</elem></test>");
|
||||
TestJAXBDomain domain = parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload(payload.toString()).build());
|
||||
assertEquals(domain.getElem(), "Hello World");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testJAXBResponseParserWithAcceptHeader() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = TestJAXBResponseParser.class.getMethod("jaxbGetWithAcceptHeader");
|
||||
HttpRequest request = factory(TestJAXBResponseParser.class).createRequest(method);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
|
||||
// now test that it works!
|
||||
|
||||
Function<HttpResponse, TestJAXBDomain> parser = (Function<HttpResponse, TestJAXBDomain>) RestAnnotationProcessor
|
||||
.createResponseParser(parserFactory, injector, method, request);
|
||||
|
||||
StringBuilder payload = new StringBuilder(XMLParser.DEFAULT_XML_HEADER);
|
||||
payload.append("<test><elem>Hello World</elem></test>");
|
||||
TestJAXBDomain domain = parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload(payload.toString()).build());
|
||||
assertEquals(domain.getElem(), "Hello World");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testAddHostNullWithHost() throws Exception {
|
||||
assertNull(RestAnnotationProcessor.addHostIfMissing(null, null));
|
||||
|
Loading…
x
Reference in New Issue
Block a user