Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Inject post parameters into the request entity
  • Loading branch information
WonderCsabo committed Sep 21, 2015
commit c8bf18e31a0648a2053e1193b154265273e910f9
Original file line number Diff line number Diff line change
Expand Up @@ -215,16 +215,32 @@ public void enclosingElementHasOneOfAnnotations(Element element, List<Class<? ex
}

private void hasOneOfAnnotations(Element reportElement, Element element, List<Class<? extends Annotation>> validAnnotations, ElementValidation validation) {
checkAnnotations(reportElement, element, validAnnotations, true, validation);
}

public void doesNotHaveOneOfAnnotations(Element element, List<Class<? extends Annotation>> validAnnotations, ElementValidation validation) {
checkAnnotations(element, element, validAnnotations, false, validation);
}

public void doesNotHaveAnnotation(Element element, Class<? extends Annotation> annotation, ElementValidation validation) {
doesNotHaveOneOfAnnotations(element, Collections.<Class<? extends Annotation>> singletonList(annotation), validation);
}

private void checkAnnotations(Element reportElement, Element element, List<Class<? extends Annotation>> validAnnotations, boolean shouldFind, ElementValidation validation) {

boolean foundAnnotation = false;
for (Class<? extends Annotation> validAnnotation : validAnnotations) {
if (element.getAnnotation(validAnnotation) != null) {
foundAnnotation = true;
break;
}
}
if (!foundAnnotation) {
validation.addError(reportElement,
"%s can only be used in a " + element.getKind().toString().toLowerCase() + " annotated with " + getFormattedValidEnhancedBeanAnnotationTypes(validAnnotations) + ".");

if (shouldFind != foundAnnotation) {
String not = shouldFind ? "" : " not";

validation.addError(reportElement, "%s can only be used in a " + element.getKind().toString().toLowerCase() + not + " annotated with "
+ getFormattedValidEnhancedBeanAnnotationTypes(validAnnotations) + ".");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public PathHandler(AndroidAnnotationsEnvironment environment) {

@Override
protected void validate(Element element, ElementValidation validation) {
restValidatorHelper.doesNotHaveFieldAnnotation(element, validation);

restValidatorHelper.enclosingElementHasOneOfRestMethodAnnotations(element, validation);

if (validation.isValid()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package org.androidannotations.rest.spring.handler;

import java.util.Collections;
import java.util.Map;
import java.util.SortedMap;

import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
Expand All @@ -28,8 +30,15 @@
import org.androidannotations.holder.GeneratedClassHolder;
import org.androidannotations.rest.spring.annotations.Field;
import org.androidannotations.rest.spring.annotations.Post;
import org.androidannotations.rest.spring.helper.RestSpringClasses;
import org.androidannotations.rest.spring.holder.RestHolder;

import com.sun.codemodel.JBlock;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JVar;

public class PostHandler extends RestMethodHandler implements HasParameterHandlers<RestHolder> {

private FieldHandler fieldHandler;
Expand All @@ -50,7 +59,7 @@ public void validate(Element element, ElementValidation validation) {

validatorHelper.doesNotReturnPrimitive((ExecutableElement) element, validation);

restSpringValidatorHelper.urlVariableNamesExistInParametersAndHasOnlyOneMoreParameter((ExecutableElement) element, validation);
restSpringValidatorHelper.urlVariableNamesExistInParametersAndHasOnlyOneEntityParameterOrOneOrMorePostParameter((ExecutableElement) element, validation);
}

@Override
Expand All @@ -59,6 +68,27 @@ protected String getUrlSuffix(Element element) {
return annotation.value();
}

@Override
protected JExpression getRequestEntity(ExecutableElement element, RestHolder holder, JBlock methodBody, SortedMap<String, JVar> params) {
JVar httpHeaders = restAnnotationHelper.declareHttpHeaders(element, holder, methodBody);
JVar entitySentToServer = restAnnotationHelper.getEntitySentToServer(element, params);

if (entitySentToServer == null) {
Map<String, String> postParameters = restAnnotationHelper.extractPostParameters(element);

if (postParameters != null) {
JClass hashMapClass = getJClass(RestSpringClasses.LINKED_MULTI_VALUE_MAP).narrow(String.class, Object.class);
entitySentToServer = methodBody.decl(hashMapClass, "postParameters", JExpr._new(hashMapClass));

for (Map.Entry<String, String> postParameter : postParameters.entrySet()) {
methodBody.add(entitySentToServer.invoke("add").arg(JExpr.lit(postParameter.getKey())).arg(params.get(postParameter.getValue())));
}
}
}

return restAnnotationHelper.declareHttpEntity(methodBody, entitySentToServer, httpHeaders);
}

public class FieldHandler extends BaseAnnotationHandler<GeneratedClassHolder> {

public FieldHandler(AndroidAnnotationsEnvironment environment) {
Expand All @@ -68,6 +98,10 @@ public FieldHandler(AndroidAnnotationsEnvironment environment) {
@Override
protected void validate(Element element, ElementValidation validation) {
validatorHelper.enclosingElementHasAnnotation(Post.class, element, validation);

restSpringValidatorHelper.doesNotHavePathAnnotation(element, validation);

restSpringValidatorHelper.restInterfaceHasFormConverter(element, validation);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.androidannotations.helper.CanonicalNameConstants;
import org.androidannotations.helper.TargetAnnotationHelper;
import org.androidannotations.rest.spring.annotations.Accept;
import org.androidannotations.rest.spring.annotations.Field;
import org.androidannotations.rest.spring.annotations.Path;
import org.androidannotations.rest.spring.annotations.RequiresAuthentication;
import org.androidannotations.rest.spring.annotations.RequiresCookie;
Expand Down Expand Up @@ -100,9 +101,11 @@ public Set<String> extractUrlVariableNames(String uriTemplate) {
}

public JVar declareUrlVariables(ExecutableElement element, RestHolder holder, JBlock methodBody, SortedMap<String, JVar> methodParams) {
Map<String, String> urlNameToElementName = new HashMap<>();
Map<String, String> urlNameToElementName = new HashMap<String, String>();
for (VariableElement variableElement : element.getParameters()) {
urlNameToElementName.put(getUrlVariableCorrespondingTo(variableElement), variableElement.getSimpleName().toString());
if (variableElement.getAnnotation(Field.class) == null) {
urlNameToElementName.put(getUrlVariableCorrespondingTo(variableElement), variableElement.getSimpleName().toString());
}
}

Set<String> urlVariables = extractUrlVariableNames(element);
Expand All @@ -120,13 +123,8 @@ public JVar declareUrlVariables(ExecutableElement element, RestHolder holder, JB
JVar hashMapVar = methodBody.decl(hashMapClass, "urlVariables", JExpr._new(hashMapClass));
for (String urlVariable : urlVariables) {
String elementName = urlNameToElementName.get(urlVariable);
JVar methodParam = null;

if (elementName != null) {
methodParam = methodParams.get(elementName);
}

if (methodParam != null) {
JVar methodParam = methodParams.get(elementName);
methodBody.invoke(hashMapVar, "put").arg(urlVariable).arg(methodParam);
methodParams.remove(elementName);
} else {
Expand Down Expand Up @@ -268,10 +266,12 @@ public JVar declareHttpHeaders(ExecutableElement executableElement, RestHolder h
public JVar getEntitySentToServer(ExecutableElement element, SortedMap<String, JVar> params) {
Set<String> urlVariables = extractUrlVariableNames(element);
for (VariableElement parameter : element.getParameters()) {
String parametername = getUrlVariableCorrespondingTo(parameter);
if (parameter.getAnnotation(Field.class) == null) {
String parameterName = getUrlVariableCorrespondingTo(parameter);

if (!urlVariables.contains(parametername)) {
return params.get(parametername);
if (!urlVariables.contains(parameterName)) {
return params.get(parameterName);
}
}
}
return null;
Expand Down Expand Up @@ -511,4 +511,25 @@ protected String plainName(JClass jClass) {
public JExpression nullCastedToNarrowedClass(RestHolder holder) {
return JExpr.cast(getEnvironment().getJClass(Class.class).narrow(getEnvironment().getJClass(Void.class)), JExpr._null());
}

/**
* Returns the post parameter name to method parameter name mapping, or null
* if duplicate names found.
*/
public Map<String, String> extractPostParameters(ExecutableElement element) {
Map<String, String> formNameToElementName = new HashMap<>();

for (VariableElement parameter : element.getParameters()) {
Field annotation = parameter.getAnnotation(Field.class);
if (annotation != null) {
String elementName = !annotation.value().equals("") ? annotation.value() : parameter.getSimpleName().toString();
if (formNameToElementName.containsKey(elementName)) {
return null;
}

formNameToElementName.put(elementName, parameter.getSimpleName().toString());
}
}
return formNameToElementName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ 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 LINKED_MULTI_VALUE_MAP = "org.springframework.util.LinkedMultiValueMap";
public static final String FORM_HTTP_MESSAGE_CONVERTER = "org.springframework.http.converter.FormHttpMessageConverter";
public static final String PARAMETERIZED_TYPE_REFERENCE = "org.springframework.core.ParameterizedTypeReference";

private RestSpringClasses() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static java.util.Arrays.asList;
import static org.androidannotations.rest.spring.helper.RestSpringClasses.CLIENT_HTTP_REQUEST_FACTORY;
import static org.androidannotations.rest.spring.helper.RestSpringClasses.CLIENT_HTTP_REQUEST_INTERCEPTOR;
import static org.androidannotations.rest.spring.helper.RestSpringClasses.FORM_HTTP_MESSAGE_CONVERTER;
import static org.androidannotations.rest.spring.helper.RestSpringClasses.HTTP_MESSAGE_CONVERTER;
import static org.androidannotations.rest.spring.helper.RestSpringClasses.REST_CLIENT_EXCEPTION;
import static org.androidannotations.rest.spring.helper.RestSpringClasses.REST_TEMPLATE;
Expand All @@ -27,6 +28,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.lang.model.element.AnnotationMirror;
Expand All @@ -48,9 +50,11 @@
import org.androidannotations.helper.TargetAnnotationHelper;
import org.androidannotations.helper.ValidatorHelper;
import org.androidannotations.rest.spring.annotations.Delete;
import org.androidannotations.rest.spring.annotations.Field;
import org.androidannotations.rest.spring.annotations.Get;
import org.androidannotations.rest.spring.annotations.Head;
import org.androidannotations.rest.spring.annotations.Options;
import org.androidannotations.rest.spring.annotations.Path;
import org.androidannotations.rest.spring.annotations.Post;
import org.androidannotations.rest.spring.annotations.Put;
import org.androidannotations.rest.spring.annotations.Rest;
Expand Down Expand Up @@ -360,6 +364,10 @@ public void urlVariableNamesExistInParameters(ExecutableElement element, Set<Str

Set<String> parametersName = new HashSet<>();
for (VariableElement parameter : parameters) {
if (parameter.getAnnotation(Field.class) != null) {
continue;
}

String nameToAdd = restAnnotationHelper.getUrlVariableCorrespondingTo(parameter);

if (parametersName.contains(nameToAdd)) {
Expand Down Expand Up @@ -410,6 +418,32 @@ public void urlVariableNamesExistInParametersAndHasOnlyOneMoreParameter(Executab
}
}

public void urlVariableNamesExistInParametersAndHasOnlyOneEntityParameterOrOneOrMorePostParameter(ExecutableElement element, ElementValidation validation) {
if (validation.isValid()) {
Set<String> variableNames = restAnnotationHelper.extractUrlVariableNames(element);
urlVariableNamesExistInParameters(element, variableNames, validation);
if (validation.isValid()) {
List<? extends VariableElement> parameters = element.getParameters();

Map<String, String> postParameters = restAnnotationHelper.extractPostParameters(element);

if (postParameters == null) {
validation.addError(element, "%s annotated method has multiple form parameters with the same name");
return;
}

if (!postParameters.isEmpty() && postParameters.size() + variableNames.size() < parameters.size()) {
validation.addError(element, "%s method cannot have both entity parameter and @Field annotated parameters");
return;
}

if (postParameters.isEmpty() && parameters.size() > variableNames.size() + 1) {
validation.addError(element, "%s annotated method has more than one entity parameter");
}
}
}
}

public void urlVariableNameExistsInEnclosingAnnotation(Element element, ElementValidation validation) {
Set<String> validRestMethodAnnotationNames = new HashSet<>();

Expand Down Expand Up @@ -468,4 +502,38 @@ public void hasSetOfHttpMethodReturnType(ExecutableElement element, ElementValid
}
}
}

public void doesNotHavePathAnnotation(Element element, ElementValidation validation) {
doesNotHaveAnnotation(element, Path.class, validation);
}

public void doesNotHaveFieldAnnotation(Element element, ElementValidation validation) {
doesNotHaveAnnotation(element, Field.class, validation);
}

public void restInterfaceHasFormConverter(Element element, ElementValidation validation) {
Element restInterface = element.getEnclosingElement().getEnclosingElement();

if (restInterface.getAnnotation(Rest.class) == null) {
return;
}

List<DeclaredType> converters = annotationHelper.extractAnnotationClassArrayParameter(restInterface, Rest.class.getCanonicalName(), "converters");

boolean formConverterFound = false;

TypeElement formConverter = annotationHelper.getElementUtils().getTypeElement(FORM_HTTP_MESSAGE_CONVERTER);

for (DeclaredType converter : converters) {
if (formConverter != null && annotationHelper.isSubtype(formConverter.asType(), converter)) {
formConverterFound = true;
break;
}
}

if (!formConverterFound) {
validation.addError(element, "%s annotated method parameter must be in a @Rest annotated interface which uses at least one " //
+ FORM_HTTP_MESSAGE_CONVERTER + " (or subtype)");
}
}
}