Skip to content

Commit c38c649

Browse files
committed
@eApplication now stores the app instance as a static singleton, so that it can be retrieved from anywhere in the app. androidannotations#228
1 parent c2ad225 commit c38c649

7 files changed

Lines changed: 57 additions & 58 deletions

File tree

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/AndroidAnnotationProcessor.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ private ModelValidator buildModelValidator(IRClass rClass, AndroidSystemServices
477477
modelValidator.register(new PostValidator(processingEnv));
478478
modelValidator.register(new PutValidator(processingEnv));
479479
modelValidator.register(new AcceptValidator(processingEnv));
480-
modelValidator.register(new AppValidator(processingEnv, androidManifest));
480+
modelValidator.register(new AppValidator(processingEnv));
481481
modelValidator.register(new OptionsMenuValidator(processingEnv, rClass));
482482
modelValidator.register(new OptionsItemValidator(processingEnv, rClass));
483483
modelValidator.register(new NoTitleValidator(processingEnv));

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/AndroidManifestFinder.java‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,18 +195,16 @@ private Option<AndroidManifest> parse(File androidManifestFile, boolean libraryP
195195

196196
NodeList applicationNodes = documentElement.getElementsByTagName("application");
197197

198-
String applicationQualifiedName = null;
198+
String applicationClassQualifiedName = null;
199199
boolean applicationDebuggableMode = false;
200200

201201
if (applicationNodes.getLength() > 0) {
202202
Node applicationNode = applicationNodes.item(0);
203203
Node nameAttribute = applicationNode.getAttributes().getNamedItem("android:name");
204204

205-
String qualifiedName = manifestNameToValidQualifiedName(applicationPackage, nameAttribute);
205+
applicationClassQualifiedName = manifestNameToValidQualifiedName(applicationPackage, nameAttribute);
206206

207-
if (qualifiedName != null) {
208-
applicationQualifiedName = qualifiedName;
209-
} else {
207+
if (applicationClassQualifiedName == null) {
210208
Messager messager = processingEnv.getMessager();
211209
if (nameAttribute != null) {
212210
messager.printMessage(Kind.NOTE, String.format("The class application declared in the AndroidManifest.xml cannot be found in the compile path: [%s]", nameAttribute.getNodeValue()));
@@ -243,7 +241,7 @@ private Option<AndroidManifest> parse(File androidManifestFile, boolean libraryP
243241
List<String> permissionQualifiedNames = new ArrayList<String>();
244242
permissionQualifiedNames.addAll(usesPermissionQualifiedNames);
245243

246-
return Option.of(AndroidManifest.createManifest(applicationPackage, applicationQualifiedName, componentQualifiedNames, permissionQualifiedNames, applicationDebuggableMode));
244+
return Option.of(AndroidManifest.createManifest(applicationPackage, applicationClassQualifiedName, componentQualifiedNames, permissionQualifiedNames, applicationDebuggableMode));
247245
}
248246

249247
private List<String> extractComponentNames(String applicationPackage, NodeList componentNodes) {

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/ValidatorHelper.java‎

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -586,29 +586,6 @@ public void hasASqlLiteOpenHelperParameterizedType(Element element, IsValid vali
586586
}
587587
}
588588

589-
public void upperclassOfRegisteredApplication(Element element, AndroidManifest manifest, IsValid valid) {
590-
591-
if (manifest.isLibraryProject()) {
592-
return;
593-
}
594-
595-
String applicationClassName = manifest.getApplicationClassName();
596-
if (applicationClassName != null) {
597-
if (applicationClassName.endsWith(GENERATION_SUFFIX)) {
598-
applicationClassName = applicationClassName.substring(0, applicationClassName.length() - GENERATION_SUFFIX.length());
599-
}
600-
TypeMirror elementType = element.asType();
601-
TypeMirror manifestType = annotationHelper.typeElementFromQualifiedName(applicationClassName).asType();
602-
if (!annotationHelper.isSubtype(manifestType, elementType)) {
603-
valid.invalidate();
604-
annotationHelper.printAnnotationError(element, "%s can only be used on an element that is an instance of the following class (or one of it's superclass): " + applicationClassName);
605-
}
606-
} else {
607-
valid.invalidate();
608-
annotationHelper.printAnnotationError(element, "No application class is registered in the AndroidManifest.xml");
609-
}
610-
}
611-
612589
public void applicationRegistered(Element element, AndroidManifest manifest, IsValid valid) {
613590

614591
if (manifest.isLibraryProject()) {
@@ -645,7 +622,7 @@ public void isSharedPreference(Element element, AnnotationElements validatedElem
645622
/*
646623
* The type is not available yet because it has just been generated
647624
*/
648-
if (type instanceof ErrorType || type.getKind() == TypeKind.ERROR) {
625+
if (type instanceof ErrorType || type.getKind() == TypeKind.ERROR) {
649626
String elementTypeName = type.toString();
650627

651628
boolean sharedPrefValidatedInRound = false;
@@ -1181,7 +1158,7 @@ public void validateInterceptors(Element element, IsValid valid) {
11811158
TypeMirror clientHttpRequestInterceptorType = annotationHelper.typeElementFromQualifiedName(CLIENT_HTTP_REQUEST_INTERCEPTOR).asType();
11821159
TypeMirror clientHttpRequestInterceptorTypeErased = annotationHelper.getTypeUtils().erasure(clientHttpRequestInterceptorType);
11831160
List<DeclaredType> interceptors = annotationHelper.extractAnnotationClassArrayParameter(element, annotationHelper.getTarget(), "interceptors");
1184-
if(interceptors == null) {
1161+
if (interceptors == null) {
11851162
return;
11861163
}
11871164
for (DeclaredType interceptorType : interceptors) {

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/AppProcessor.java‎

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,17 @@
1515
*/
1616
package org.androidannotations.processing;
1717

18-
import static org.androidannotations.helper.CanonicalNameConstants.APPLICATION;
19-
import static com.sun.codemodel.JExpr.cast;
2018
import static com.sun.codemodel.JExpr.ref;
2119

2220
import java.lang.annotation.Annotation;
2321

2422
import javax.lang.model.element.Element;
25-
import javax.lang.model.type.TypeMirror;
2623

2724
import org.androidannotations.annotations.App;
25+
import org.androidannotations.helper.ModelConstants;
26+
27+
import com.sun.codemodel.JClass;
2828
import com.sun.codemodel.JCodeModel;
29-
import com.sun.codemodel.JInvocation;
3029

3130
public class AppProcessor implements DecoratingElementProcessor {
3231

@@ -38,18 +37,12 @@ public Class<? extends Annotation> getTarget() {
3837
@Override
3938
public void process(Element element, JCodeModel codeModel, EBeanHolder holder) {
4039

41-
String fieldName = element.getSimpleName().toString();
42-
43-
TypeMirror elementType = element.asType();
40+
String applicationQualifiedName = element.asType().toString();
41+
JClass applicationClass = holder.refClass(applicationQualifiedName + ModelConstants.GENERATION_SUFFIX);
4442

45-
JInvocation getApplication = holder.initActivityRef.invoke("getApplication");
43+
String fieldName = element.getSimpleName().toString();
4644

47-
String applicationTypeQualifiedName = elementType.toString();
48-
if (APPLICATION.equals(applicationTypeQualifiedName)) {
49-
holder.initIfActivityBody.assign(ref(fieldName), getApplication);
50-
} else {
51-
holder.initIfActivityBody.assign(ref(fieldName), cast(holder.refClass(applicationTypeQualifiedName), getApplication));
52-
}
45+
holder.init.body().assign(ref(fieldName), applicationClass.staticInvoke(EApplicationProcessor.GET_APPLICATION_INSTANCE));
5346

5447
}
5548

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EApplicationProcessor.java‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static com.sun.codemodel.JMod.FINAL;
2020
import static com.sun.codemodel.JMod.PRIVATE;
2121
import static com.sun.codemodel.JMod.PUBLIC;
22+
import static com.sun.codemodel.JMod.STATIC;
2223

2324
import java.lang.annotation.Annotation;
2425

@@ -27,16 +28,22 @@
2728

2829
import org.androidannotations.annotations.EApplication;
2930
import org.androidannotations.helper.ModelConstants;
31+
3032
import com.sun.codemodel.ClassType;
3133
import com.sun.codemodel.JBlock;
3234
import com.sun.codemodel.JClass;
3335
import com.sun.codemodel.JCodeModel;
3436
import com.sun.codemodel.JDefinedClass;
3537
import com.sun.codemodel.JExpr;
38+
import com.sun.codemodel.JFieldVar;
3639
import com.sun.codemodel.JMethod;
40+
import com.sun.codemodel.JMod;
41+
import com.sun.codemodel.JVar;
3742

3843
public class EApplicationProcessor implements GeneratingElementProcessor {
3944

45+
public static final String GET_APPLICATION_INSTANCE = "getInstance";
46+
4047
@Override
4148
public Class<? extends Annotation> getTarget() {
4249
return EApplication.class;
@@ -60,21 +67,34 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo
6067

6168
holder.contextRef = _this();
6269

70+
JFieldVar staticInstanceField = holder.generatedClass.field(PRIVATE | STATIC, annotatedComponent, "INSTANCE_");
71+
{
72+
// Static singleton getter and setter
73+
JMethod getInstance = holder.generatedClass.method(PUBLIC | JMod.STATIC, annotatedComponent, GET_APPLICATION_INSTANCE);
74+
getInstance.body()._return(staticInstanceField);
75+
76+
JMethod setInstance = holder.generatedClass.method(PUBLIC | JMod.STATIC, codeModel.VOID, "setForTesting");
77+
setInstance.javadoc().append("Visible for testing purposes");
78+
JVar applicationParam = setInstance.param(annotatedComponent, "application");
79+
setInstance.body().assign(staticInstanceField, applicationParam);
80+
}
81+
6382
holder.init = holder.generatedClass.method(PRIVATE, codeModel.VOID, "init_");
6483
{
6584
// onCreate
6685
JMethod onCreate = holder.generatedClass.method(PUBLIC, codeModel.VOID, "onCreate");
6786
onCreate.annotate(Override.class);
6887
JBlock onCreateBody = onCreate.body();
88+
onCreateBody.assign(staticInstanceField, _this());
6989
onCreateBody.invoke(holder.init);
7090
onCreateBody.invoke(JExpr._super(), onCreate);
7191
}
7292

7393
{
7494
/*
75-
* Setting to null shouldn't be a problem as long as we don't allow
95+
* Setting to null shouldn't be a problem as long as we do not allow
7696
*
77-
* @App and @Extra on this component
97+
* @Extra on this component
7898
*/
7999
holder.initIfActivityBody = null;
80100
holder.initActivityRef = null;

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/validation/AppValidator.java‎

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,16 @@
2121
import javax.lang.model.element.Element;
2222

2323
import org.androidannotations.annotations.App;
24-
import org.androidannotations.helper.AndroidManifest;
24+
import org.androidannotations.annotations.EApplication;
2525
import org.androidannotations.helper.TargetAnnotationHelper;
2626
import org.androidannotations.helper.ValidatorHelper;
2727
import org.androidannotations.model.AnnotationElements;
2828

2929
public class AppValidator implements ElementValidator {
3030

3131
private ValidatorHelper validatorHelper;
32-
private final AndroidManifest manifest;
3332

34-
public AppValidator(ProcessingEnvironment processingEnv, AndroidManifest manifest) {
35-
this.manifest = manifest;
33+
public AppValidator(ProcessingEnvironment processingEnv) {
3634
TargetAnnotationHelper annotationHelper = new TargetAnnotationHelper(processingEnv, getTarget());
3735
validatorHelper = new ValidatorHelper(annotationHelper);
3836
}
@@ -44,14 +42,11 @@ public Class<? extends Annotation> getTarget() {
4442

4543
@Override
4644
public boolean validate(Element element, AnnotationElements validatedElements) {
47-
4845
IsValid valid = new IsValid();
4946

50-
validatorHelper.enclosingElementHasEnhancedViewSupportAnnotation(element, validatedElements, valid);
51-
52-
validatorHelper.extendsApplication(element, valid);
47+
validatorHelper.enclosingElementHasEnhancedComponentAnnotation(element, validatedElements, valid);
5348

54-
validatorHelper.upperclassOfRegisteredApplication(element, manifest, valid);
49+
validatorHelper.typeHasAnnotation(EApplication.class, element, valid);
5550

5651
validatorHelper.isNotPrivate(element, valid);
5752

‎AndroidAnnotations/functional-test-1-5-tests/src/test/java/org/androidannotations/test15/ApplicationInjectedActivityTest.java‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,35 @@
1717

1818
import static org.fest.assertions.Assertions.assertThat;
1919

20+
import org.androidannotations.test15.roboguice.SampleRoboApplication;
21+
import org.androidannotations.test15.roboguice.SampleRoboApplication_;
2022
import org.junit.Test;
2123
import org.junit.runner.RunWith;
2224

2325
@RunWith(AndroidAnnotationsTestRunner.class)
2426
public class ApplicationInjectedActivityTest {
2527

2628
@Test
27-
public void shouldHaveLayoutAfterCreate() {
29+
public void should_have_application_after_create() {
2830
ApplicationInjectedActivity_ activity = new ApplicationInjectedActivity_();
2931

3032
activity.onCreate(null);
3133

3234
assertThat(activity.customApplication).isNotNull();
3335
}
36+
37+
@Test
38+
public void application_can_be_replaced_for_tests() {
39+
SampleRoboApplication testApp = new SampleRoboApplication();
40+
41+
SampleRoboApplication_.setForTesting(testApp);
42+
43+
ApplicationInjectedActivity_ activity = new ApplicationInjectedActivity_();
44+
45+
activity.onCreate(null);
46+
47+
assertThat(activity.customApplication).isSameAs(testApp);
48+
}
49+
3450

3551
}

0 commit comments

Comments
 (0)