Merge pull request #1 from myrle-krantz/develop
response body is now transported by exceptions including via custom exceptions
diff --git a/src/main/java/io/mifos/core/api/util/AnnotatedErrorDecoder.java b/src/main/java/io/mifos/core/api/util/AnnotatedErrorDecoder.java
index cb6f0d5..0a23b40 100644
--- a/src/main/java/io/mifos/core/api/util/AnnotatedErrorDecoder.java
+++ b/src/main/java/io/mifos/core/api/util/AnnotatedErrorDecoder.java
@@ -18,12 +18,14 @@
import feign.Feign;
import feign.FeignException;
import feign.Response;
+import feign.Util;
import feign.codec.ErrorDecoder;
import io.mifos.core.api.annotation.ThrowsException;
import io.mifos.core.api.annotation.ThrowsExceptions;
import org.slf4j.Logger;
import org.springframework.http.HttpStatus;
+import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -60,19 +62,30 @@
}
private RuntimeException getAlternative(final String methodKey, final Response response) {
+ final String bodyText = stringifyBody(response);
+
if (response.status() == HttpStatus.BAD_REQUEST.value()) {
- return new IllegalArgumentException(response.reason());
+ return new IllegalArgumentException(bodyText);
} else if (response.status() == HttpStatus.FORBIDDEN.value()) {
- return new InvalidTokenException(response.reason());
+ return new InvalidTokenException(bodyText);
} else if (response.status() == HttpStatus.NOT_FOUND.value()) {
- return new NotFoundException();
+ return new NotFoundException(bodyText);
} else if (response.status() == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
- return new InternalServerError(response.reason());
+ return new InternalServerError(bodyText);
} else {
return FeignException.errorStatus(methodKey, response);
}
}
+ private String stringifyBody(final Response response) {
+ try {
+ if (response.body() != null)
+ return Util.toString(response.body().asReader());
+ } catch (IOException ignored) {
+ }
+ return null;
+ }
+
private Optional<ThrowsException> getMatchingAnnotation(
final Response response,
final Method method) {
@@ -112,16 +125,23 @@
final ThrowsException throwsExceptionAnnotations) {
try {
try {
- final Constructor<? extends RuntimeException> oneArgumentConstructor =
+ final Constructor<? extends RuntimeException> oneResponseArgumentConstructor =
throwsExceptionAnnotations.exception().getConstructor(Response.class);
- return Optional.of(oneArgumentConstructor.newInstance(response));
+ return Optional.of(oneResponseArgumentConstructor.newInstance(response));
} catch (final NoSuchMethodException e) {
+ try {
+ final Constructor<? extends RuntimeException> noArgumentConstructor =
+ throwsExceptionAnnotations.exception().getConstructor();
- final Constructor<? extends RuntimeException> noArgumentConstructor =
- throwsExceptionAnnotations.exception().getConstructor();
+ return Optional.of(noArgumentConstructor.newInstance());
+ }
+ catch (final NoSuchMethodException e2) {
+ final Constructor<? extends RuntimeException> noStringArgumentConstructor =
+ throwsExceptionAnnotations.exception().getConstructor(String.class);
- return Optional.of(noArgumentConstructor.newInstance());
+ return Optional.of(noStringArgumentConstructor.newInstance(stringifyBody(response)));
+ }
}
} catch (final InvocationTargetException
| IllegalAccessException
diff --git a/src/main/java/io/mifos/core/api/util/NotFoundException.java b/src/main/java/io/mifos/core/api/util/NotFoundException.java
index 9649cd5..98650e8 100644
--- a/src/main/java/io/mifos/core/api/util/NotFoundException.java
+++ b/src/main/java/io/mifos/core/api/util/NotFoundException.java
@@ -21,4 +21,7 @@
@SuppressWarnings("WeakerAccess")
public class NotFoundException extends RuntimeException {
+ public NotFoundException(final String reason) {
+ super(reason);
+ }
}
diff --git a/src/test/java/io/mifos/core/api/util/AnnotatedErrorDecoderTest.java b/src/test/java/io/mifos/core/api/util/AnnotatedErrorDecoderTest.java
index 7dc1104..fc53e4c 100644
--- a/src/test/java/io/mifos/core/api/util/AnnotatedErrorDecoderTest.java
+++ b/src/test/java/io/mifos/core/api/util/AnnotatedErrorDecoderTest.java
@@ -26,6 +26,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -48,37 +49,48 @@
final Response emptyInternalServerErrorResponse = Response.builder()
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
- .reason("blah")
+ .body("blah", Charset.defaultCharset())
.headers(Collections.emptyMap())
.build();
final Response emptyBadRequestResponse = Response.builder()
.status(HttpStatus.BAD_REQUEST.value())
- .reason("blah")
+ .body("blah", Charset.defaultCharset())
+ .headers(Collections.emptyMap())
+ .build();
+
+ final Response emptyBadRequestResponseWithNoBody = Response.builder()
+ .status(HttpStatus.BAD_REQUEST.value())
+ .headers(Collections.emptyMap())
+ .build();
+
+ final Response emptyNotFoundRequestResponse = Response.builder()
+ .status(HttpStatus.NOT_FOUND.value())
+ .body("blah", Charset.defaultCharset())
.headers(Collections.emptyMap())
.build();
final Response emptyConflictResponse = Response.builder()
.status(HttpStatus.CONFLICT.value())
- .reason("blah")
+ .body("blah", Charset.defaultCharset())
.headers(Collections.emptyMap())
.build();
final Response emptyIAmATeapotResponse = Response.builder()
.status(HttpStatus.I_AM_A_TEAPOT.value())
- .reason("blah")
+ .body("blah", Charset.defaultCharset())
.headers(Collections.emptyMap())
.build();
final Response emptyUnauthorizedResponse = Response.builder()
.status(HttpStatus.UNAUTHORIZED.value())
- .reason("blah")
+ .body("blah", Charset.defaultCharset())
.headers(Collections.emptyMap())
.build();
final Response emptyForbiddenResponse = Response.builder()
.status(HttpStatus.FORBIDDEN.value())
- .reason("blah")
+ .body("blah", Charset.defaultCharset())
.headers(Collections.emptyMap())
.build();
@@ -91,7 +103,10 @@
Feign.configKey(OneMethodInterface.class, OneMethodInterface.class.getMethod("method"));
final String onceAnnotatedMethodKey =
- Feign.configKey(OneMethodOneAnnotationInterface.class, OneMethodOneAnnotationInterface.class.getMethod("method"));
+ Feign.configKey(OneMethodOneAnnotationInterface.class, OneMethodOneAnnotationInterface.class.getMethod("method"));
+
+ final String onceAnnotatedWithStringExceptionMethodKey =
+ Feign.configKey(OneMethodOneAnnotationStringParameteredExceptionInterface.class, OneMethodOneAnnotationStringParameteredExceptionInterface.class.getMethod("method"));
ret.add(new TestCase("Methodless interface")
.clazz(MethodlessInterface.class)
@@ -135,12 +150,31 @@
.response(emptyBadRequestResponse)
.expectedResult(new ParameterlessException()));
+ ret.add(new TestCase("Interface with one method that has one annotation containing an exception which accepts a string parameter.")
+ .clazz(OneMethodOneAnnotationStringParameteredExceptionInterface.class)
+ .methodKey(onceAnnotatedWithStringExceptionMethodKey)
+ .response(emptyBadRequestResponse)
+ .expectedResult(new StringParameteredException("blah")));
+
ret.add(new TestCase("Bad request on an interface in which bad request isn't mapped.")
.clazz(AnnotationlessInterface.class)
.methodKey(annotationlessMethodKey)
.response(emptyBadRequestResponse)
.expectedResult(new IllegalArgumentException("blah")));
+ ret.add(new TestCase("Bad request with no body on an interface in which bad request isn't mapped.")
+ .clazz(AnnotationlessInterface.class)
+ .methodKey(annotationlessMethodKey)
+ .response(emptyBadRequestResponseWithNoBody)
+ .expectedResult(new IllegalArgumentException((String)null)));
+
+
+ ret.add(new TestCase("Not found request on an interface in which not found request isn't mapped.")
+ .clazz(AnnotationlessInterface.class)
+ .methodKey(annotationlessMethodKey)
+ .response(emptyNotFoundRequestResponse)
+ .expectedResult(new NotFoundException("blah")));
+
ret.add(new TestCase("Request with invalid token.")
.clazz(OneMethodOneAnnotationInterface.class)
.methodKey(onceAnnotatedMethodKey)
@@ -199,6 +233,14 @@
void method();
}
+
+ private interface OneMethodOneAnnotationStringParameteredExceptionInterface {
+
+ @SuppressWarnings("unused")
+ @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = StringParameteredException.class)
+ void method();
+ }
+
private static class TestCase {
private final String name;
@@ -272,10 +314,18 @@
}
}
+ private static class StringParameteredException extends RuntimeException {
+
+ @SuppressWarnings("WeakerAccess")
+ public StringParameteredException(final String response) {
+ super(response);
+ }
+ }
+
private static class WrongParameteredException extends RuntimeException {
- public WrongParameteredException(final String message) {
- super(message);
+ public WrongParameteredException(final Integer message) {
+ super(message.toString());
}
}
}