Skip to content

Commit 574fd51

Browse files
committed
Fixed classpath issues with RoboGuice
Some classes of RoboGuice are referencing the android.support package. This is problematic, since it is not always in the classpath. In that case, generated code cannot be compiled if support classes are indirectly referenced, also validation can go wrong. This commit fixes that issue by removing all indirect reference to the support package.
1 parent 2d3ca56 commit 574fd51

8 files changed

Lines changed: 99 additions & 28 deletions

File tree

‎AndroidAnnotations/androidannotations-api/META-INF/MANIFEST.MF‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Export-Package: org.androidannotations.annotations,
1010
org.androidannotations.api,
1111
org.androidannotations.api.builder,
1212
org.androidannotations.api.rest,
13+
org.androidannotations.api.roboguice,
1314
org.androidannotations.api.sharedpreferences,
1415
org.androidannotations.api.view
1516
Bundle-Vendor: androidannotations
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.androidannotations.api.roboguice;
2+
3+
import java.lang.reflect.InvocationTargetException;
4+
import java.lang.reflect.Method;
5+
6+
/**
7+
* Reflection utils to call methods which are accessible in RoboGuice package
8+
* but not from outside.
9+
*/
10+
public class RoboGuiceHelper {
11+
12+
public static void callInjectViews(Object activity) {
13+
try {
14+
Class<?> viewMembersInjectorClass = Class.forName("roboguice.inject.ViewListener$ViewMembersInjector");
15+
Method injectViewsMethod = viewMembersInjectorClass.getDeclaredMethod("injectViews", Object.class);
16+
injectViewsMethod.setAccessible(true);
17+
injectViewsMethod.invoke(null, activity);
18+
} catch (ClassNotFoundException e) {
19+
propagateRuntimeException(e);
20+
} catch (NoSuchMethodException e) {
21+
propagateRuntimeException(e);
22+
} catch (SecurityException e) {
23+
propagateRuntimeException(e);
24+
} catch (IllegalAccessException e) {
25+
propagateRuntimeException(e);
26+
} catch (IllegalArgumentException e) {
27+
propagateRuntimeException(e);
28+
} catch (InvocationTargetException e) {
29+
propagateRuntimeException(e);
30+
}
31+
}
32+
33+
private static void propagateRuntimeException(Throwable t) {
34+
throw new RuntimeException("Could not invoke RoboGuice method!", t);
35+
}
36+
}

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/handler/RoboGuiceHandler.java‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,13 @@ public void process(Element element, EActivityHolder holder) {
6969

7070
holder.getGeneratedClass()._implements(classes().ROBO_CONTEXT);
7171

72+
JFieldVar scope = roboGuiceHolder.getScopeField();
7273
JFieldVar scopedObjects = roboGuiceHolder.getScopedObjectsField();
7374
JFieldVar eventManager = roboGuiceHolder.getEventManagerField();
7475
roboGuiceHolder.getContentViewListenerField();
7576
listenerFields(element, holder);
7677

77-
beforeCreateMethod(holder, scopedObjects, eventManager);
78+
beforeCreateMethod(holder, scope, scopedObjects, eventManager);
7879
onRestartMethod(roboGuiceHolder, eventManager);
7980
onStartMethod(roboGuiceHolder, eventManager);
8081
onResumeMethod(roboGuiceHolder, eventManager);
@@ -83,7 +84,7 @@ public void process(Element element, EActivityHolder holder) {
8384
onStopMethod(roboGuiceHolder, eventManager);
8485
onDestroyMethod(roboGuiceHolder, eventManager);
8586
onConfigurationChangedMethod(roboGuiceHolder, eventManager);
86-
onContentChangedMethod(roboGuiceHolder, eventManager);
87+
onContentChangedMethod(roboGuiceHolder, holder, scope, eventManager);
8788
onActivityResultMethod(roboGuiceHolder, eventManager);
8889
getScopedObjectMap(holder, scopedObjects);
8990
}
@@ -131,13 +132,14 @@ private List<String> extractListenerClasses(Element activityElement) {
131132
return new ArrayList<String>(0);
132133
}
133134

134-
private void beforeCreateMethod(EActivityHolder holder, JFieldVar scopedObjects, JFieldVar eventManager) {
135+
private void beforeCreateMethod(EActivityHolder holder, JFieldVar scope, JFieldVar scopedObjects, JFieldVar eventManager) {
135136
JBlock body = holder.getInitBody();
136137
JClass keyWildCard = classes().KEY.narrow(codeModel().wildcard());
137138
JClass scopedHashMap = classes().HASH_MAP.narrow(keyWildCard, classes().OBJECT);
138139
body.assign(scopedObjects, JExpr._new(scopedHashMap));
139140

140141
JVar injector = body.decl(classes().ROBO_INJECTOR, "injector_", classes().ROBO_GUICE.staticInvoke("getInjector").arg(_this()));
142+
body.assign(scope, invoke(injector, "getInstance").arg(classes().CONTEXT_SCOPE.dotclass()));
141143
body.assign(eventManager, invoke(injector, "getInstance").arg(classes().EVENT_MANAGER.dotclass()));
142144
body.add(injector.invoke("injectMembersWithoutViews").arg(_this()));
143145
fireEvent(eventManager, body, classes().ON_CREATE_EVENT, holder.getInitSavedInstanceParam());
@@ -203,9 +205,19 @@ private void onConfigurationChangedMethod(RoboGuiceHolder holder, JFieldVar even
203205
fireEvent(eventManager, onConfigurationChangedAfterSuperBlock, classes().ON_CONFIGURATION_CHANGED_EVENT, currentConfig, newConfig);
204206
}
205207

206-
private void onContentChangedMethod(RoboGuiceHolder holder, JFieldVar eventManager) {
208+
private void onContentChangedMethod(RoboGuiceHolder holder, EActivityHolder eActivityHolder, JFieldVar scope, JFieldVar eventManager) {
207209
JBlock onContentChangedAfterSuperBlock = holder.getOnContentChangedAfterSuperBlock();
208-
onContentChangedAfterSuperBlock.add(classes().ROBO_GUICE.staticInvoke("getInjector").arg(_this()).invoke("injectViewMembers").arg(_this()));
210+
211+
// no synchronized in CodeModel
212+
// https://java.net/jira/browse/CODEMODEL-6
213+
onContentChangedAfterSuperBlock.directStatement("synchronized(" + classes().CONTEXT_SCOPE.name() + ".class" + ")");
214+
JBlock synchronizedBlock = new JBlock(true, true);
215+
synchronizedBlock.invoke(scope, "enter").arg(_this());
216+
JTryBlock tryBlock = synchronizedBlock._try();
217+
tryBlock.body().staticInvoke(eActivityHolder.refClass(org.androidannotations.api.roboguice.RoboGuiceHelper.class), "callInjectViews").arg(_this());
218+
tryBlock._finally().invoke(scope, "exit").arg(_this());
219+
onContentChangedAfterSuperBlock.add(synchronizedBlock);
220+
209221
fireEvent(eventManager, onContentChangedAfterSuperBlock, classes().ON_CONTENT_CHANGED_EVENT);
210222
}
211223

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ public final class CanonicalNameConstants {
141141
/*
142142
* RoboGuice
143143
*/
144+
public static final String ROBO_APPLICATION = "roboguice.application.RoboApplication";
144145
public static final String ROBO_CONTEXT = "roboguice.util.RoboContext";
145146
public static final String ROBO_INJECTOR = "roboguice.inject.RoboInjector";
146147
public static final String KEY = "com.google.inject.Key";
@@ -152,6 +153,7 @@ public final class CanonicalNameConstants {
152153
public static final String ON_NEW_INTENT_EVENT = "roboguice.activity.event.OnNewIntentEvent";
153154
public static final String EVENT_MANAGER = "roboguice.event.EventManager";
154155
public static final String CONTEXT_SCOPE = "roboguice.inject.ContextScope";
156+
public static final String VIEW_MEMBERS_INJECTOR = "roboguice.inject.ViewListener.ViewMembersInjector";
155157
public static final String ROBO_GUICE = "roboguice.RoboGuice";
156158
public static final String INJECT = "com.google.inject.Inject";
157159
public static final String ON_STOP_EVENT = "roboguice.activity.event.OnStopEvent";

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -678,14 +678,9 @@ public void hasRoboGuiceJars(Element element, IsValid valid) {
678678
annotationHelper.printAnnotationError(element, "Could not find the RoboGuice framework in the classpath, the following class is missing: " + CanonicalNameConstants.ROBO_CONTEXT);
679679
}
680680

681-
try {
682-
if (elementUtils.getTypeElement(CanonicalNameConstants.ROBO_INJECTOR) == null) {
683-
valid.invalidate();
684-
annotationHelper.printAnnotationError(element, "Could not find the Guice framework in the classpath, the following class is missing: " + CanonicalNameConstants.ROBO_INJECTOR);
685-
}
686-
} catch (RuntimeException e) {
681+
if (elementUtils.getTypeElement(CanonicalNameConstants.ROBO_APPLICATION) != null) {
687682
valid.invalidate();
688-
annotationHelper.printAnnotationError(element, "Could not find the Guice framework in the classpath, the following class is missing: " + CanonicalNameConstants.ROBO_INJECTOR);
683+
annotationHelper.printAnnotationError(element, "It seems you are using an old version of RoboGuice. Be sure to use version 2.0!");
689684
}
690685
}
691686

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/holder/EActivityHolder.java‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161

6262
public class EActivityHolder extends EComponentWithViewSupportHolder implements HasIntentBuilder, HasExtras, HasInstanceState, HasOptionsMenu, HasOnActivityResult, HasReceiverRegistration {
6363

64+
private static final String ON_CONTENT_CHANGED_JAVADOC = "We cannot simply copy the " + "code from RoboActivity, because that can cause classpath issues. " + "For further details see issue #1116.";
65+
6466
private ActivityIntentBuilder intentBuilder;
6567
private JMethod onCreate;
6668
private JMethod setIntent;
@@ -230,6 +232,7 @@ protected void setOnConfigurationChanged() {
230232
protected void setOnContentChanged() {
231233
JMethod method = generatedClass.method(JMod.PUBLIC, codeModel().VOID, "onContentChanged");
232234
method.annotate(Override.class);
235+
method.javadoc().append(ON_CONTENT_CHANGED_JAVADOC);
233236
JBlock body = method.body();
234237
body.invoke(_super(), method);
235238
getRoboGuiceHolder().onContentChangedAfterSuperBlock = body.block();
@@ -368,15 +371,15 @@ private void handleBackPressed() {
368371

369372
onKeyDownBody._if( //
370373
sdkInt.lt(JExpr.lit(5)) //
371-
.cand(keyCodeParam.eq(keyEventClass.staticRef("KEYCODE_BACK"))) //
372-
.cand(eventParam.invoke("getRepeatCount").eq(JExpr.lit(0)))) //
374+
.cand(keyCodeParam.eq(keyEventClass.staticRef("KEYCODE_BACK"))) //
375+
.cand(eventParam.invoke("getRepeatCount").eq(JExpr.lit(0)))) //
373376
._then() //
374377
.invoke("onBackPressed");
375378

376379
onKeyDownBody._return( //
377380
JExpr._super().invoke(onKeyDownMethod) //
378-
.arg(keyCodeParam) //
379-
.arg(eventParam));
381+
.arg(keyCodeParam) //
382+
.arg(eventParam));
380383

381384
}
382385
}
@@ -406,7 +409,7 @@ private boolean isCustomOnBackPressedMethod(ExecutableElement method) {
406409
&& method.getModifiers().contains(Modifier.PUBLIC) //
407410
&& method.getReturnType().getKind().equals(TypeKind.VOID) //
408411
&& method.getParameters().size() == 0 //
409-
;
412+
;
410413
}
411414

412415
@Override
@@ -448,6 +451,11 @@ protected void setContentViewListenerField() {
448451
getRoboGuiceHolder().contentViewListenerField.annotate(classes().INJECT);
449452
}
450453

454+
protected void setScopeField() {
455+
getRoboGuiceHolder().scope = getGeneratedClass().field(JMod.PRIVATE, classes().CONTEXT_SCOPE, "scope_");
456+
457+
}
458+
451459
@Override
452460
public JMethod getInjectExtrasMethod() {
453461
if (injectExtrasMethod == null) {

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/holder/RoboGuiceHolder.java‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class RoboGuiceHolder {
2424

2525
private EActivityHolder holder;
2626
protected JFieldVar scopedObjects;
27+
protected JFieldVar scope;
2728
protected JFieldVar eventManager;
2829
public JFieldVar contentViewListenerField;
2930
protected JBlock onRestartBeforeSuperBlock;
@@ -57,6 +58,13 @@ public JFieldVar getScopedObjectsField() {
5758
return scopedObjects;
5859
}
5960

61+
public JFieldVar getScopeField() {
62+
if (scope == null) {
63+
holder.setScopeField();
64+
}
65+
return scope;
66+
}
67+
6068
public JFieldVar getContentViewListenerField() {
6169
if (contentViewListenerField == null) {
6270
holder.setContentViewListenerField();

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/process/ProcessHolder.java‎

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,27 @@
1515
*/
1616
package org.androidannotations.process;
1717

18-
import com.sun.codemodel.JClass;
19-
import com.sun.codemodel.JClassAlreadyExistsException;
20-
import com.sun.codemodel.JCodeModel;
21-
import com.sun.codemodel.JDefinedClass;
22-
import org.androidannotations.helper.CanonicalNameConstants;
23-
import org.androidannotations.holder.GeneratedClassHolder;
24-
25-
import javax.annotation.processing.ProcessingEnvironment;
26-
import javax.lang.model.element.Element;
2718
import java.io.FileInputStream;
2819
import java.io.InputStream;
2920
import java.io.Serializable;
3021
import java.sql.SQLException;
31-
import java.util.*;
22+
import java.util.Collections;
23+
import java.util.HashMap;
24+
import java.util.HashSet;
25+
import java.util.List;
26+
import java.util.Map;
27+
import java.util.Set;
28+
29+
import javax.annotation.processing.ProcessingEnvironment;
30+
import javax.lang.model.element.Element;
31+
32+
import org.androidannotations.helper.CanonicalNameConstants;
33+
import org.androidannotations.holder.GeneratedClassHolder;
34+
35+
import com.sun.codemodel.JClass;
36+
import com.sun.codemodel.JClassAlreadyExistsException;
37+
import com.sun.codemodel.JCodeModel;
38+
import com.sun.codemodel.JDefinedClass;
3239

3340
public class ProcessHolder {
3441

@@ -129,6 +136,8 @@ public class Classes {
129136
public final JClass ON_PAUSE_EVENT = refClass(CanonicalNameConstants.ON_PAUSE_EVENT);
130137
public final JClass ON_NEW_INTENT_EVENT = refClass(CanonicalNameConstants.ON_NEW_INTENT_EVENT);
131138
public final JClass EVENT_MANAGER = refClass(CanonicalNameConstants.EVENT_MANAGER);
139+
public final JClass CONTEXT_SCOPE = refClass(CanonicalNameConstants.CONTEXT_SCOPE);
140+
public final JClass VIEW_MEMBERS_INJECTOR = refClass(CanonicalNameConstants.VIEW_MEMBERS_INJECTOR);
132141
public final JClass ROBO_GUICE = refClass(CanonicalNameConstants.ROBO_GUICE);
133142
public final JClass INJECT = refClass(CanonicalNameConstants.INJECT);
134143
public final JClass ON_STOP_EVENT = refClass(CanonicalNameConstants.ON_STOP_EVENT);
@@ -212,7 +221,7 @@ public void put(Element element, GeneratedClassHolder generatedClassHolder) {
212221

213222
public GeneratedClassHolder getGeneratedClassHolder(Element element) {
214223
for (Element key : generatedClassHolders.keySet()) {
215-
if(key.asType().toString().equals(element.asType().toString())) {
224+
if (key.asType().toString().equals(element.asType().toString())) {
216225
return generatedClassHolders.get(key);
217226
}
218227
}

0 commit comments

Comments
 (0)