Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
Prev Previous commit
Next Next commit
Refactoring common code between ServiceActionProcessor and ExtraProce…
…ssor

Refactoring three parts : addCastMethod, addIntentBuilderPutExtraMethod and camelCaseToUpperSnakeCase
  • Loading branch information
DayS committed May 24, 2013
commit 9d1b3ca03bcd794f60758b17f324172545e8f655
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,25 @@
import static com.sun.codemodel.JMod.PUBLIC;
import static com.sun.codemodel.JMod.STATIC;
import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
import static org.androidannotations.helper.CanonicalNameConstants.PARCELABLE;
import static org.androidannotations.helper.CanonicalNameConstants.SERIALIZABLE;
import static org.androidannotations.helper.CanonicalNameConstants.STRING;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import org.androidannotations.processing.EBeanHolder;
import org.androidannotations.processing.EBeansHolder.Classes;
Expand All @@ -56,6 +63,7 @@
import com.sun.codemodel.JStatement;
import com.sun.codemodel.JTryBlock;
import com.sun.codemodel.JType;
import com.sun.codemodel.JTypeVar;
import com.sun.codemodel.JVar;

public class APTCodeModelHelper {
Expand Down Expand Up @@ -383,4 +391,47 @@ private void addIntentBuilder(JCodeModel codeModel, EBeanHolder holder, boolean
}
}
}

public JInvocation addIntentBuilderPutExtraMethod(JCodeModel codeModel, EBeanHolder holder, APTCodeModelHelper helper, ProcessingEnvironment processingEnv, JMethod method, TypeMirror elementType, String paramName, String extraName) {
boolean castToSerializable = false;
boolean castToParcelable = false;
if (elementType.getKind() == TypeKind.DECLARED) {
Elements elementUtils = processingEnv.getElementUtils();
Types typeUtils = processingEnv.getTypeUtils();
TypeMirror parcelableType = elementUtils.getTypeElement(PARCELABLE).asType();
if (!typeUtils.isSubtype(elementType, parcelableType)) {
TypeMirror stringType = elementUtils.getTypeElement(STRING).asType();
if (!typeUtils.isSubtype(elementType, stringType)) {
castToSerializable = true;
}
} else {
TypeMirror serializableType = elementUtils.getTypeElement(SERIALIZABLE).asType();
if (typeUtils.isSubtype(elementType, serializableType)) {
castToParcelable = true;
}
}
}

JClass paramClass = helper.typeMirrorToJClass(elementType, holder);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameterizedClass or parameterClass ?
Can you choose a more excplicit variable name ?

JVar extraParam = method.param(paramClass, paramName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

JBlock body = method.body();
JInvocation invocation = body.invoke(holder.intentField, "putExtra").arg(extraName);
if (castToSerializable) {
return invocation.arg(cast(holder.classes().SERIALIZABLE, extraParam));
} else if (castToParcelable) {
return invocation.arg(cast(holder.classes().PARCELABLE, extraParam));
}
return invocation.arg(extraParam);
}

public void addCastMethod(JCodeModel codeModel, EBeanHolder holder) {
JType objectType = codeModel._ref(Object.class);
JMethod method = holder.generatedClass.method(JMod.PRIVATE, objectType, "cast_");
JTypeVar genericType = method.generify("T");
method.type(genericType);
JVar objectParam = method.param(objectType, "object");
method.annotate(SuppressWarnings.class).param("value", "unchecked");
method.body()._return(JExpr.cast(genericType, objectParam));
holder.cast = method;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,14 @@ public static String camelCaseToUpperSnakeCase(String camelCase) {
return camelCaseToSnakeCase(camelCase).toUpperCase();
}

public static String camelCaseToUpperSnakeCase(String prefix, String camelCase, String suffix) {
if (prefix != null && !camelCase.startsWith(prefix)) {
camelCase = prefix + "_" + camelCase;
}
if (suffix != null && !camelCase.toLowerCase().endsWith(suffix.toLowerCase())) {
camelCase = camelCase + "_" + suffix;
}
return camelCaseToUpperSnakeCase(camelCase);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,16 @@
import static com.sun.codemodel.JExpr._null;
import static com.sun.codemodel.JExpr._super;
import static com.sun.codemodel.JExpr._this;
import static com.sun.codemodel.JExpr.cast;
import static com.sun.codemodel.JExpr.invoke;
import static com.sun.codemodel.JExpr.lit;
import static com.sun.codemodel.JMod.FINAL;
import static com.sun.codemodel.JMod.PRIVATE;
import static com.sun.codemodel.JMod.PUBLIC;
import static com.sun.codemodel.JMod.STATIC;
import static org.androidannotations.helper.CanonicalNameConstants.PARCELABLE;
import static org.androidannotations.helper.CanonicalNameConstants.SERIALIZABLE;
import static org.androidannotations.helper.CanonicalNameConstants.STRING;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import org.androidannotations.annotations.Extra;
import org.androidannotations.helper.APTCodeModelHelper;
Expand All @@ -50,11 +43,9 @@
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JPrimitiveType;
import com.sun.codemodel.JTryBlock;
import com.sun.codemodel.JType;
import com.sun.codemodel.JTypeVar;
import com.sun.codemodel.JVar;

public class ExtraProcessor implements DecoratingElementProcessor {
Expand Down Expand Up @@ -87,19 +78,14 @@ public void process(Element element, JCodeModel codeModel, EBeanHolder holder) {
Classes classes = holder.classes();

if (!isPrimitive && holder.cast == null) {
generateCastMethod(codeModel, holder);
helper.addCastMethod(codeModel, holder);
}

if (holder.extras == null) {
injectExtras(holder, codeModel);
}

String staticFieldName;
if (fieldName.endsWith("Extra")) {
staticFieldName = CaseHelper.camelCaseToUpperSnakeCase(fieldName);
} else {
staticFieldName = CaseHelper.camelCaseToUpperSnakeCase(fieldName + "Extra");
}
String staticFieldName = CaseHelper.camelCaseToUpperSnakeCase(null, fieldName, "Extra");

JFieldVar extraKeyField = holder.generatedClass.field(PUBLIC | STATIC | FINAL, classes.STRING, staticFieldName, lit(extraKey));

Expand Down Expand Up @@ -137,53 +123,15 @@ public void process(Element element, JCodeModel codeModel, EBeanHolder holder) {
// flags()
JMethod method = holder.intentBuilderClass.method(PUBLIC, holder.intentBuilderClass, fieldName);

boolean castToSerializable = false;
boolean castToParcelable = false;
TypeMirror extraType = elementType;
if (extraType.getKind() == TypeKind.DECLARED) {
Elements elementUtils = processingEnv.getElementUtils();
Types typeUtils = processingEnv.getTypeUtils();
TypeMirror parcelableType = elementUtils.getTypeElement(PARCELABLE).asType();
if (!typeUtils.isSubtype(extraType, parcelableType)) {
TypeMirror stringType = elementUtils.getTypeElement(STRING).asType();
if (!typeUtils.isSubtype(extraType, stringType)) {
castToSerializable = true;
}
} else {
TypeMirror serializableType = elementUtils.getTypeElement(SERIALIZABLE).asType();
if (typeUtils.isSubtype(extraType, serializableType)) {
castToParcelable = true;
}
}
}
JClass paramClass = helper.typeMirrorToJClass(extraType, holder);
JVar extraParam = method.param(paramClass, fieldName);
helper.addIntentBuilderPutExtraMethod(codeModel, holder, helper, processingEnv, method, elementType, fieldName, staticFieldName);

JBlock body = method.body();
JInvocation invocation = body.invoke(holder.intentField, "putExtra").arg(extraKeyField);
if (castToSerializable) {
invocation.arg(cast(classes.SERIALIZABLE, extraParam));
} else if (castToParcelable) {
invocation.arg(cast(classes.PARCELABLE, extraParam));
} else {
invocation.arg(extraParam);
}
body._return(_this());
}
}

}

private void generateCastMethod(JCodeModel codeModel, EBeanHolder holder) {
JType objectType = codeModel._ref(Object.class);
JMethod method = holder.generatedClass.method(JMod.PRIVATE, objectType, "cast_");
JTypeVar genericType = method.generify("T");
method.type(genericType);
JVar objectParam = method.param(objectType, "object");
method.annotate(SuppressWarnings.class).param("value", "unchecked");
method.body()._return(JExpr.cast(genericType, objectParam));
holder.cast = method;
}

/**
* Adds call to injectExtras_() in onCreate and setIntent() methods.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,10 @@
package org.androidannotations.processing;

import static com.sun.codemodel.JExpr._null;
import static com.sun.codemodel.JExpr.cast;
import static com.sun.codemodel.JExpr.lit;
import static com.sun.codemodel.JMod.FINAL;
import static com.sun.codemodel.JMod.PUBLIC;
import static com.sun.codemodel.JMod.STATIC;
import static org.androidannotations.helper.CanonicalNameConstants.PARCELABLE;
import static org.androidannotations.helper.CanonicalNameConstants.SERIALIZABLE;
import static org.androidannotations.helper.CanonicalNameConstants.STRING;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -32,10 +28,6 @@
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import org.androidannotations.annotations.ServiceAction;
import org.androidannotations.helper.APTCodeModelHelper;
Expand All @@ -50,10 +42,8 @@
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JPrimitiveType;
import com.sun.codemodel.JType;
import com.sun.codemodel.JTypeVar;
import com.sun.codemodel.JVar;

public class ServiceActionProcessor implements DecoratingElementProcessor {
Expand Down Expand Up @@ -84,12 +74,8 @@ public void process(Element element, JCodeModel codeModel, EBeanHolder holder) {
extraKey = methodName;
}

String staticFieldName;
if (methodName.startsWith("action")) {
staticFieldName = CaseHelper.camelCaseToUpperSnakeCase(methodName);
} else {
staticFieldName = CaseHelper.camelCaseToUpperSnakeCase("action_" + methodName);
}
String staticFieldName = CaseHelper.camelCaseToUpperSnakeCase("action", methodName, null);

JFieldVar actionKeyField = holder.generatedClass.field(PUBLIC | STATIC | FINAL, classes.STRING, staticFieldName, lit(extraKey));

if (holder.onHandleIntentBody != null) {
Expand All @@ -108,7 +94,7 @@ public void process(Element element, JCodeModel codeModel, EBeanHolder holder) {
List<? extends VariableElement> methodParameters = executableElement.getParameters();
if (methodParameters.size() > 0) {
if (holder.cast == null) {
generateCastMethod(codeModel, holder);
helper.addCastMethod(codeModel, holder);
}

// Extras
Expand Down Expand Up @@ -169,53 +155,13 @@ public void process(Element element, JCodeModel codeModel, EBeanHolder holder) {
// Extras params
for (VariableElement param : methodParameters) {
String paramName = param.getSimpleName().toString();
String extraParamName = paramName + "Extra";

boolean castToSerializable = false;
boolean castToParcelable = false;
TypeMirror extraType = param.asType();
if (extraType.getKind() == TypeKind.DECLARED) {
Elements elementUtils = processingEnv.getElementUtils();
Types typeUtils = processingEnv.getTypeUtils();
TypeMirror parcelableType = elementUtils.getTypeElement(PARCELABLE).asType();
if (!typeUtils.isSubtype(extraType, parcelableType)) {
TypeMirror stringType = elementUtils.getTypeElement(STRING).asType();
if (!typeUtils.isSubtype(extraType, stringType)) {
castToSerializable = true;
}
} else {
TypeMirror serializableType = elementUtils.getTypeElement(SERIALIZABLE).asType();
if (typeUtils.isSubtype(extraType, serializableType)) {
castToParcelable = true;
}
}
}
JClass paramClass = helper.typeMirrorToJClass(extraType, holder);
JVar extraParam = method.param(paramClass, extraParamName);
JInvocation invocation = body.invoke(holder.intentField, "putExtra").arg(paramName);
if (castToSerializable) {
invocation.arg(cast(classes.SERIALIZABLE, extraParam));
} else if (castToParcelable) {
invocation.arg(cast(classes.PARCELABLE, extraParam));
} else {
invocation.arg(extraParam);
}
helper.addIntentBuilderPutExtraMethod(codeModel, holder, helper, processingEnv, method, param.asType(), paramName, paramName);
}

}
body._return(JExpr._this());
}

}

private void generateCastMethod(JCodeModel codeModel, EBeanHolder holder) {
JType objectType = codeModel._ref(Object.class);
JMethod method = holder.generatedClass.method(JMod.PRIVATE, objectType, "cast_");
JTypeVar genericType = method.generify("T");
method.type(genericType);
JVar objectParam = method.param(objectType, "object");
method.annotate(SuppressWarnings.class).param("value", "unchecked");
method.body()._return(JExpr.cast(genericType, objectParam));
holder.cast = method;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.androidannotations.helper;

import junit.framework.Assert;

import org.junit.Test;

public class CaseHelperTest {

@Test
public void testCamelCaseToUpperSnakeCaseString() throws Exception {
Assert.assertEquals("CAMEL_CASE", CaseHelper.camelCaseToUpperSnakeCase("camelCase"));
Assert.assertEquals("CAMEL_CASE", CaseHelper.camelCaseToUpperSnakeCase("camel_case"));
Assert.assertEquals("CAMEL_CASE", CaseHelper.camelCaseToUpperSnakeCase("Camel_Case"));
}

@Test
public void testCamelCaseToUpperSnakeCaseStringStringString() throws Exception {
Assert.assertEquals("CAMEL_CASE", CaseHelper.camelCaseToUpperSnakeCase(null, "camelCase", null));
Assert.assertEquals("PREFIX_CAMEL_CASE", CaseHelper.camelCaseToUpperSnakeCase("prefix", "camelCase", null));
Assert.assertEquals("PREFIX_CAMEL_CASE", CaseHelper.camelCaseToUpperSnakeCase("prefix", "prefixCamelCase", null));
Assert.assertEquals("CAMEL_CASE_SUFFIX", CaseHelper.camelCaseToUpperSnakeCase(null, "camelCase", "suffix"));
Assert.assertEquals("CAMEL_CASE_SUFFIX", CaseHelper.camelCaseToUpperSnakeCase(null, "camelCaseSuffix", "suffix"));
Assert.assertEquals("PREFIX_CAMEL_CASE_SUFFIX", CaseHelper.camelCaseToUpperSnakeCase("prefix", "camelCase", "suffix"));
}

}