From c0a4b249fce1204fd3c405e1a5d094a728240f20 Mon Sep 17 00:00:00 2001 From: WonderCsabo Date: Mon, 15 Jun 2015 19:42:15 +0200 Subject: [PATCH 1/4] Use ParameterizedTypeReference in REST method calls Generic response class is natively supported in Spring for Android 2.0. This commit utilize that support, if it is available in the reponse class is generic. It falls back to the old implementation otherwise. --- .../spring/helper/RestAnnotationHelper.java | 35 ++++++++++++++++--- .../rest/spring/helper/RestSpringClasses.java | 1 + 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java b/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java index 93b1e37601..cbb7bd5238 100644 --- a/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java +++ b/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java @@ -287,6 +287,12 @@ public JExpression getResponseClass(Element element, RestHolder holder) { JExpression responseClassExpr = nullCastedToNarrowedClass(holder); TypeMirror returnType = executableElement.getReturnType(); if (returnType.getKind() != TypeKind.VOID) { + if (getElementUtils().getTypeElement(RestSpringClasses.PARAMETERIZED_TYPE_REFERENCE) != null // + && returnType.getKind() == TypeKind.DECLARED && !((DeclaredType) returnType).getTypeArguments().isEmpty() // + && !returnType.toString().startsWith(RestSpringClasses.RESPONSE_ENTITY)) { + return createParameterizedTypeReferenceAnonymousSubclassInstance(returnType, holder); + } + JClass responseClass = retrieveResponseClass(returnType, holder); if (responseClass != null) { responseClassExpr = responseClass.dotclass(); @@ -295,6 +301,12 @@ public JExpression getResponseClass(Element element, RestHolder holder) { return responseClassExpr; } + public JExpression createParameterizedTypeReferenceAnonymousSubclassInstance(TypeMirror returnType, RestHolder holder) { + JClass narrowedTypeReference = holder.getEnvironment().getJClass(RestSpringClasses.PARAMETERIZED_TYPE_REFERENCE).narrow(codeModelHelper.typeMirrorToJClass(returnType)); + JDefinedClass anonymousClass = holder.getEnvironment().getCodeModel().anonymousClass(narrowedTypeReference); + return JExpr._new(anonymousClass); + } + public JClass retrieveResponseClass(TypeMirror returnType, RestHolder holder) { String returnTypeString = returnType.toString(); @@ -303,12 +315,12 @@ public JClass retrieveResponseClass(TypeMirror returnType, RestHolder holder) { if (returnTypeString.startsWith(RESPONSE_ENTITY)) { DeclaredType declaredReturnType = (DeclaredType) returnType; if (declaredReturnType.getTypeArguments().size() > 0) { - responseClass = resolveResponseClass(declaredReturnType.getTypeArguments().get(0), holder); + responseClass = resolveResponseClass(declaredReturnType.getTypeArguments().get(0), holder, false); } else { responseClass = getEnvironment().getJClass(RESPONSE_ENTITY); } } else { - responseClass = resolveResponseClass(returnType, holder); + responseClass = resolveResponseClass(returnType, holder, true); } return responseClass; @@ -336,7 +348,7 @@ public JClass retrieveResponseClass(TypeMirror returnType, RestHolder holder) { * * */ - private JClass resolveResponseClass(TypeMirror expectedType, RestHolder holder) { + private JClass resolveResponseClass(TypeMirror expectedType, RestHolder holder, boolean useTypeReference) { // is a class or an interface if (expectedType.getKind() == TypeKind.DECLARED) { DeclaredType declaredType = (DeclaredType) expectedType; @@ -351,6 +363,10 @@ private JClass resolveResponseClass(TypeMirror expectedType, RestHolder holder) // is a generics, must generate a new super class TypeElement declaredElement = (TypeElement) declaredType.asElement(); + if (useTypeReference && getElementUtils().getTypeElement(RestSpringClasses.PARAMETERIZED_TYPE_REFERENCE) != null) { + return codeModelHelper.typeMirrorToJClass(declaredType); + } + JClass baseClass = codeModelHelper.typeMirrorToJClass(declaredType).erasure(); JClass decoratedExpectedClass = retrieveDecoratedResponseClass(declaredType, declaredElement, holder); if (decoratedExpectedClass == null) { @@ -359,7 +375,18 @@ private JClass resolveResponseClass(TypeMirror expectedType, RestHolder holder) return decoratedExpectedClass; } else if (expectedType.getKind() == TypeKind.ARRAY) { ArrayType arrayType = (ArrayType) expectedType; - return resolveResponseClass(arrayType.getComponentType(), holder).array(); + + TypeMirror componentType = arrayType.getComponentType(); + + if (componentType.getKind() == TypeKind.DECLARED) { + DeclaredType declaredType = (DeclaredType) componentType; + + if (useTypeReference && getElementUtils().getTypeElement(RestSpringClasses.PARAMETERIZED_TYPE_REFERENCE) != null) { + return codeModelHelper.typeMirrorToJClass(expectedType); + } + } + + return resolveResponseClass(componentType, holder, false).array(); } // is not a class nor an interface, return directly diff --git a/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestSpringClasses.java b/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestSpringClasses.java index 6eff694ed9..c158630c7a 100644 --- a/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestSpringClasses.java +++ b/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestSpringClasses.java @@ -31,6 +31,7 @@ public final class RestSpringClasses { public static final String REST_CLIENT_EXCEPTION = "org.springframework.web.client.RestClientException"; public static final String NESTED_RUNTIME_EXCEPTION = "org.springframework.core.NestedRuntimeException"; public static final String RESPONSE_ERROR_HANDLER = "org.springframework.web.client.ResponseErrorHandler"; + public static final String PARAMETERIZED_TYPE_REFERENCE = "org.springframework.core.ParameterizedTypeReference"; private RestSpringClasses() { From 87be90981aabfb5d2ab5898e87f8f330c0359caf Mon Sep 17 00:00:00 2001 From: Kay-Uwe Janssen Date: Sun, 13 Sep 2015 10:49:03 +0200 Subject: [PATCH 2/4] fix generation of ParameterizedTypeReference subclasses for arrays of generic types --- .../spring/helper/RestAnnotationHelper.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java b/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java index cbb7bd5238..0236c7429b 100644 --- a/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java +++ b/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java @@ -287,10 +287,9 @@ public JExpression getResponseClass(Element element, RestHolder holder) { JExpression responseClassExpr = nullCastedToNarrowedClass(holder); TypeMirror returnType = executableElement.getReturnType(); if (returnType.getKind() != TypeKind.VOID) { - if (getElementUtils().getTypeElement(RestSpringClasses.PARAMETERIZED_TYPE_REFERENCE) != null // - && returnType.getKind() == TypeKind.DECLARED && !((DeclaredType) returnType).getTypeArguments().isEmpty() // - && !returnType.toString().startsWith(RestSpringClasses.RESPONSE_ENTITY)) { - return createParameterizedTypeReferenceAnonymousSubclassInstance(returnType, holder); + if (getElementUtils().getTypeElement(RestSpringClasses.PARAMETERIZED_TYPE_REFERENCE) != null && !returnType.toString().startsWith(RestSpringClasses.RESPONSE_ENTITY) + && checkIfParameterizedTypeReferenceShouldBeUsed(returnType)) { + return createParameterizedTypeReferenceAnonymousSubclassInstance(returnType); } JClass responseClass = retrieveResponseClass(returnType, holder); @@ -301,9 +300,22 @@ public JExpression getResponseClass(Element element, RestHolder holder) { return responseClassExpr; } - public JExpression createParameterizedTypeReferenceAnonymousSubclassInstance(TypeMirror returnType, RestHolder holder) { - JClass narrowedTypeReference = holder.getEnvironment().getJClass(RestSpringClasses.PARAMETERIZED_TYPE_REFERENCE).narrow(codeModelHelper.typeMirrorToJClass(returnType)); - JDefinedClass anonymousClass = holder.getEnvironment().getCodeModel().anonymousClass(narrowedTypeReference); + private boolean checkIfParameterizedTypeReferenceShouldBeUsed(TypeMirror returnType) { + switch (returnType.getKind()) { + case DECLARED: + return !((DeclaredType) returnType).getTypeArguments().isEmpty(); + + case ARRAY: + ArrayType arrayType = (ArrayType) returnType; + TypeMirror componentType = arrayType.getComponentType(); + return checkIfParameterizedTypeReferenceShouldBeUsed(componentType); + } + return false; + } + + public JExpression createParameterizedTypeReferenceAnonymousSubclassInstance(TypeMirror returnType) { + JClass narrowedTypeReference = getEnvironment().getJClass(RestSpringClasses.PARAMETERIZED_TYPE_REFERENCE).narrow(codeModelHelper.typeMirrorToJClass(returnType)); + JDefinedClass anonymousClass = getEnvironment().getCodeModel().anonymousClass(narrowedTypeReference); return JExpr._new(anonymousClass); } From 3b5ee5d123d1a871f460d777d354b72d5b8cfd95 Mon Sep 17 00:00:00 2001 From: Kay-Uwe Janssen Date: Sun, 13 Sep 2015 10:49:33 +0200 Subject: [PATCH 3/4] add additional test case for arrays of generic types --- .../org/androidannotations/rest/spring/test/MyService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AndroidAnnotations/androidannotations-rest-spring/rest-spring-test/src/main/java/org/androidannotations/rest/spring/test/MyService.java b/AndroidAnnotations/androidannotations-rest-spring/rest-spring-test/src/main/java/org/androidannotations/rest/spring/test/MyService.java index 14d49a8f17..aa22427ed9 100644 --- a/AndroidAnnotations/androidannotations-rest-spring/rest-spring-test/src/main/java/org/androidannotations/rest/spring/test/MyService.java +++ b/AndroidAnnotations/androidannotations-rest-spring/rest-spring-test/src/main/java/org/androidannotations/rest/spring/test/MyService.java @@ -86,6 +86,9 @@ public interface MyService { @Get("/events/{year}/{location}") List[] getEventsGenericsArrayList(String location, int year) throws RestClientException; + @Get("/events/{year}/{location}") + List[][] getEventsGenericsArrayList2(String location, int year) throws RestClientException; + @Get("/events/{year}/{location}") List> getEventsGenericsListListEvent(String location, int year) throws RestClientException; From c04444c36d7ff37d0c97d98b20caf21fb5fae550 Mon Sep 17 00:00:00 2001 From: Kay-Uwe Janssen Date: Sun, 13 Sep 2015 10:56:07 +0200 Subject: [PATCH 4/4] remove unnecessary code --- .../rest/spring/helper/RestAnnotationHelper.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java b/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java index 0236c7429b..d29c6c8ac2 100644 --- a/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java +++ b/AndroidAnnotations/androidannotations-rest-spring/rest-spring/src/main/java/org/androidannotations/rest/spring/helper/RestAnnotationHelper.java @@ -387,17 +387,7 @@ private JClass resolveResponseClass(TypeMirror expectedType, RestHolder holder, return decoratedExpectedClass; } else if (expectedType.getKind() == TypeKind.ARRAY) { ArrayType arrayType = (ArrayType) expectedType; - TypeMirror componentType = arrayType.getComponentType(); - - if (componentType.getKind() == TypeKind.DECLARED) { - DeclaredType declaredType = (DeclaredType) componentType; - - if (useTypeReference && getElementUtils().getTypeElement(RestSpringClasses.PARAMETERIZED_TYPE_REFERENCE) != null) { - return codeModelHelper.typeMirrorToJClass(expectedType); - } - } - return resolveResponseClass(componentType, holder, false).array(); }