├── .gitignore
├── .gitmodules
├── .project
├── .settings
└── org.eclipse.m2e.core.prefs
├── README.md
├── assets
├── android_smell.png
└── android_smell.psd
├── cleanandroidcode-it
├── .classpath
├── .project
├── .settings
│ ├── org.eclipse.core.resources.prefs
│ ├── org.eclipse.jdt.core.prefs
│ └── org.eclipse.m2e.core.prefs
├── AndroidManifest.xml
├── pom.xml
├── project.properties
└── src
│ └── main
│ └── java
│ └── info
│ └── piwai
│ └── cleanandroidcode
│ └── HelloAndroidActivityTest.java
├── cleanandroidcode-processor
├── .classpath
├── .project
├── .settings
│ ├── org.eclipse.core.resources.prefs
│ ├── org.eclipse.jdt.core.prefs
│ └── org.eclipse.m2e.core.prefs
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── piwai
│ │ └── cleanandroidcode
│ │ └── DaggerAAIntegrationProcessor.java
│ └── resources
│ └── META-INF
│ └── services
│ └── javax.annotation.processing.Processor
├── cleanandroidcode
├── .classpath
├── .factorypath
├── .project
├── .settings
│ ├── org.eclipse.core.resources.prefs
│ ├── org.eclipse.jdt.apt.core.prefs
│ ├── org.eclipse.jdt.core.prefs
│ └── org.eclipse.m2e.core.prefs
├── AndroidManifest.xml
├── pom.xml
├── project.properties
├── res
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ │ └── ic_launcher.png
│ ├── layout
│ │ ├── hello_activity.xml
│ │ └── hello_fragment.xml
│ └── values
│ │ └── strings.xml
└── src
│ └── main
│ └── java
│ └── info
│ └── piwai
│ └── cleanandroidcode
│ ├── HelloAndroidActivity.java
│ ├── HelloApplication.java
│ ├── HelloFragment.java
│ ├── UpdateTitleEvent.java
│ └── base
│ ├── BaseActivity.java
│ ├── BaseFragment.java
│ ├── BaseModule.java
│ └── GraphRetriever.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | bin
3 | gen
4 | .apt_generated
5 | .DS_Store
6 | *.idea
7 | *.iml
8 | *.ipr
9 | *.iws
10 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "otto"]
2 | path = otto
3 | url = git@github.com:pyricau/otto.git
4 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | cleanandroidcode-parent
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.m2e.core.maven2Builder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.m2e.core.maven2Nature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | activeProfiles=
2 | eclipse.preferences.version=1
3 | resolveWorkspaceProjects=true
4 | version=1
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ALL YOUR LIB ARE BELONG TO US
2 |
3 | 
4 |
5 | ## Introduction
6 |
7 | This project is a proof of concept to show how to integrate [Dagger](http://square.github.com/dagger/), [Otto](http://square.github.com/otto/) and [AndroidAnnotations](http://androidannotations.org).
8 |
9 | We can benefit from all those librairies to write Android apps that are both easy to maintain and lightning fast.
10 |
11 | Here is what the result looks like:
12 |
13 | ```java
14 | @EActivity(R.layout.hello_activity)
15 | public class HelloAndroidActivity extends BaseActivity {
16 |
17 | @Subscribe
18 | public void onUpdateTitle(UpdateTitleEvent event) {
19 | setTitle(event.title);
20 | }
21 |
22 | }
23 | ```
24 |
25 | ```java
26 | @EFragment(R.layout.hello_fragment)
27 | public class HelloFragment extends BaseFragment {
28 |
29 | @Inject
30 | Bus bus;
31 |
32 | @Click
33 | void fragmentButtonClicked() {
34 | bus.post(new UpdateTitleEvent("Button clicked"));
35 | }
36 | }
37 | ```
38 |
39 | This project contains only a few classes, go and read the source!
40 |
41 | ## Building and running
42 |
43 | ### Command line
44 |
45 | Here is how to build this project from the command line.
46 |
47 | * First, make sure you have a device plugged in so that the integration tests can run.
48 | * Then you just need to run the following commands:
49 |
50 | ```bash
51 | git clone git@github.com:pyricau/CleanAndroidCode.git
52 | cd CleanAndroidCode
53 | git submodule init
54 | git submodule update
55 | # We use a custom version of Otto, see below
56 | cd otto
57 | mvn clean install -DskipTests
58 | cd ..
59 | # Build, install on device and run the integration tests
60 | mvn clean install
61 | ```
62 |
63 | ### Eclipse
64 |
65 | This project compiles and runs fine on Eclipse Juno. I have commited all the configuration files to make sure you do not spend time configuring it. You should be able to import everything "as maven projects".
66 |
67 | > I haven't tried with IntelliJ, but since everybody keeps telling me how good this IDE is, I assume everything will work perfectly fine :) .
68 |
69 | ## Gotchas
70 |
71 | ### Dagger & AndroidAnnotations
72 |
73 | Dagger requires the definition of entry points on an `@Module` annotation. These entry points are our activities and fragments, created by the system.
74 |
75 | When using both Dagger & AndroidAnnotations, one obvious configuration would be:
76 |
77 | ```java
78 | @Module(
79 | entryPoints = {
80 | HelloFragment_.class,
81 | HelloAndroidActivity_.class,
82 | },
83 | complete = false
84 | )
85 | public class EntryPointsModule {
86 | }
87 | ```
88 |
89 | However, this cannot work directly when doing a full build. Even when you take care of the processor order so that you run AndroidAnnotations first and then Dagger, they run both in the same round, so the classes generated by AndroidAnnotations are not compiled yet when Dagger runs. The `@Module` annotation therefore references an unknown class.
90 |
91 | This can be solved by having an extra annotation processor that generates this module at compile time. The module is picked up by Dagger on a second round, where the generated classes are compiled and therefore available.
92 |
93 | This extra annotation processor is the `cleanandroidcode-processor` project.
94 |
95 | Since this processor creates one class out of several annotations, it needs a caching mechanism to handle Eclipse incremental compiler.
96 |
97 | Check out the [DaggerAAIntegrationProcessor](https://github.com/pyricau/CleanAndroidCode/blob/master/cleanandroidcode-processor/src/main/java/info/piwai/cleanandroidcode/DaggerAAIntegrationProcessor.java) to learn more about this processor.
98 |
99 | ### Otto & AndroidAnnotations
100 |
101 | Unlike its Guava sister, Otto doesn't look for `@Produce` and `@Subscribe` annotations through the class hierarchy for performance reasons.
102 |
103 | However, there is a custom version of Otto that replaces reflection with annotation processing and code generation.
104 | It is a proof of concept from [Jake Wharton](https://github.com/JakeWharton), available on [this branch](https://github.com/square/otto/tree/code-gen) on the Square Otto repo.
105 |
106 | ## Questions?
107 |
108 | Any question? Create a [new issue](https://github.com/pyricau/CleanAndroidCode/issues/new) or ask [@Piwai](http://twitter.com/piwai).
109 |
--------------------------------------------------------------------------------
/assets/android_smell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/assets/android_smell.png
--------------------------------------------------------------------------------
/assets/android_smell.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/assets/android_smell.psd
--------------------------------------------------------------------------------
/cleanandroidcode-it/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/cleanandroidcode-it/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | cleanandroidcode-it
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 | org.eclipse.m2e.core.maven2Builder
30 |
31 |
32 |
33 |
34 |
35 | com.android.ide.eclipse.adt.AndroidNature
36 | org.eclipse.jdt.core.javanature
37 | org.eclipse.m2e.core.maven2Nature
38 |
39 |
40 |
--------------------------------------------------------------------------------
/cleanandroidcode-it/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding//src/main/java=UTF-8
3 | encoding//src/test/java=UTF-8
4 | encoding/=UTF-8
5 |
--------------------------------------------------------------------------------
/cleanandroidcode-it/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
5 | org.eclipse.jdt.core.compiler.source=1.6
6 |
--------------------------------------------------------------------------------
/cleanandroidcode-it/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | activeProfiles=
2 | eclipse.preferences.version=1
3 | resolveWorkspaceProjects=true
4 | version=1
5 |
--------------------------------------------------------------------------------
/cleanandroidcode-it/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
17 |
20 |
21 |
--------------------------------------------------------------------------------
/cleanandroidcode-it/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 |
7 | info.piwai.cleanandroidcode
8 | cleanandroidcode-parent
9 | 1.0-SNAPSHOT
10 |
11 |
12 | cleanandroidcode-it
13 | apk
14 | cleanandroidcode-it - Integration tests
15 |
16 |
17 |
18 | com.google.android
19 | android
20 |
21 |
22 | com.google.android
23 | android-test
24 |
25 |
26 | info.piwai.cleanandroidcode
27 | cleanandroidcode
28 | apk
29 |
30 |
31 | info.piwai.cleanandroidcode
32 | cleanandroidcode
33 | jar
34 |
35 |
36 |
37 |
38 |
39 | com.jayway.maven.plugins.android.generation2
40 | android-maven-plugin
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/cleanandroidcode-it/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-16
15 |
--------------------------------------------------------------------------------
/cleanandroidcode-it/src/main/java/info/piwai/cleanandroidcode/HelloAndroidActivityTest.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode;
2 |
3 | import android.support.v4.app.Fragment;
4 | import android.support.v4.app.FragmentActivity;
5 | import android.test.ActivityInstrumentationTestCase2;
6 | import android.test.UiThreadTest;
7 | import android.view.View;
8 |
9 | public class HelloAndroidActivityTest extends ActivityInstrumentationTestCase2 {
10 |
11 | public HelloAndroidActivityTest() {
12 | super(HelloAndroidActivity_.class);
13 | }
14 |
15 | @UiThreadTest
16 | public void test_click_on_fragment_changes_title() {
17 | FragmentActivity activity = getActivity();
18 | Fragment fragment = activity.getSupportFragmentManager().findFragmentById(R.id.hello_fragment);
19 | View fragmentButton = fragment.getView().findViewById(R.id.fragment_button);
20 |
21 | fragmentButton.performClick();
22 |
23 | String title = activity.getTitle().toString();
24 |
25 | assertTrue("Title should start with [Button clicked]. Title is [" + title + "]", title.startsWith("Button clicked"));
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/cleanandroidcode-processor/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/cleanandroidcode-processor/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | cleanandroidcode-processor
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.m2e.core.maven2Builder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.m2e.core.maven2Nature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/cleanandroidcode-processor/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding//src/main/java=UTF-8
3 | encoding//src/main/resources=UTF-8
4 | encoding//src/test/java=UTF-8
5 | encoding/=UTF-8
6 |
--------------------------------------------------------------------------------
/cleanandroidcode-processor/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
5 | org.eclipse.jdt.core.compiler.source=1.6
6 |
--------------------------------------------------------------------------------
/cleanandroidcode-processor/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | activeProfiles=
2 | eclipse.preferences.version=1
3 | resolveWorkspaceProjects=true
4 | version=1
5 |
--------------------------------------------------------------------------------
/cleanandroidcode-processor/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | cleanandroidcode-parent
9 | info.piwai.cleanandroidcode
10 | 1.0-SNAPSHOT
11 |
12 |
13 | cleanandroidcode-processor
14 | CleanAndroidCode Annotation Processor
15 |
16 |
17 |
18 |
19 | maven-compiler-plugin
20 |
21 | -proc:none
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/cleanandroidcode-processor/src/main/java/info/piwai/cleanandroidcode/DaggerAAIntegrationProcessor.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.BufferedWriter;
5 | import java.io.IOException;
6 | import java.io.PrintWriter;
7 | import java.io.StringWriter;
8 | import java.util.Collections;
9 | import java.util.HashSet;
10 | import java.util.List;
11 | import java.util.Set;
12 |
13 | import javax.annotation.processing.AbstractProcessor;
14 | import javax.annotation.processing.Filer;
15 | import javax.annotation.processing.Messager;
16 | import javax.annotation.processing.ProcessingEnvironment;
17 | import javax.annotation.processing.RoundEnvironment;
18 | import javax.annotation.processing.SupportedAnnotationTypes;
19 | import javax.annotation.processing.SupportedSourceVersion;
20 | import javax.lang.model.SourceVersion;
21 | import javax.lang.model.element.AnnotationMirror;
22 | import javax.lang.model.element.Element;
23 | import javax.lang.model.element.TypeElement;
24 | import javax.lang.model.util.ElementFilter;
25 | import javax.lang.model.util.Elements;
26 | import javax.tools.Diagnostic;
27 | import javax.tools.FileObject;
28 | import javax.tools.JavaFileManager;
29 | import javax.tools.JavaFileObject;
30 | import javax.tools.StandardLocation;
31 |
32 | @SupportedSourceVersion(SourceVersion.RELEASE_6)
33 | @SupportedAnnotationTypes({
34 | /*
35 | * Only supports @EActivity and @EFragment, since this is just a proof of
36 | * concept. This can be extended quite easily though.
37 | */
38 | //
39 | "com.googlecode.androidannotations.annotations.EActivity", //
40 | "com.googlecode.androidannotations.annotations.EFragment", //
41 | })
42 | public class DaggerAAIntegrationProcessor extends AbstractProcessor {
43 |
44 | private static final String CACHE_PACKAGE_NAME = "";
45 | private static final String CACHE_FILE_NAME = "DaggerAAIntegrationCache.txt";
46 |
47 | /**
48 | * We us this to avoid opening files twice in different rounds of the same
49 | * processing, because it otherwhise fails. We shouldn't do this, but rather
50 | * collect instructions on what we should do and output the module in the
51 | * last round.
52 | */
53 | boolean alreadyProcessed = false;
54 |
55 | @Override
56 | public synchronized void init(ProcessingEnvironment processingEnv) {
57 | super.init(processingEnv);
58 | Messager messager = processingEnv.getMessager();
59 | messager.printMessage(Diagnostic.Kind.NOTE, "Init of DaggerAAIntegrationProcessor");
60 | }
61 |
62 | @Override
63 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
64 |
65 | if (!alreadyProcessed) {
66 | Set annotatedElements = getAnnotatedElements(roundEnv);
67 |
68 | generateDaggerModule(annotatedElements);
69 |
70 | cacheAnnotatedElements(annotatedElements);
71 | alreadyProcessed = true;
72 | }
73 |
74 | return false;
75 | }
76 |
77 | private Set getAnnotatedElements(RoundEnvironment roundEnv) {
78 | Set annotationTypeElements = getAnnotationTypeElements();
79 |
80 | Set roundAnnotatedElements = getRoundAnnotatedElements(roundEnv, annotationTypeElements);
81 |
82 | Set cachedElements = loadCachedAnnotatedElement(roundAnnotatedElements);
83 |
84 | Set cachedAnnotatedElements = filterAnnotatedElements(cachedElements, annotationTypeElements);
85 |
86 | Set annotatedElements = new HashSet();
87 | annotatedElements.addAll(roundAnnotatedElements);
88 | annotatedElements.addAll(cachedAnnotatedElements);
89 | return annotatedElements;
90 | }
91 |
92 | private Set filterAnnotatedElements(Set typeElements, Set annotationTypeElements) {
93 | Set annotatedTypeElements = new HashSet();
94 |
95 | for (TypeElement typeElement : typeElements) {
96 | List extends AnnotationMirror> annotationMirrors = typeElement.getAnnotationMirrors();
97 | boolean typeElementIsAnnotated = false;
98 | for (AnnotationMirror annotationMirror : annotationMirrors) {
99 | Element annotationElement = annotationMirror.getAnnotationType().asElement();
100 | if (annotationElement instanceof TypeElement) {
101 | TypeElement annotationTypeElement = (TypeElement) annotationElement;
102 | if (annotationTypeElements.contains(annotationTypeElement)) {
103 | typeElementIsAnnotated = true;
104 | break;
105 | }
106 | } else {
107 | reportNote(typeElement + " is annotated with an annotation element " + annotationElement + " that is not a TypeElement");
108 | }
109 | }
110 | if (typeElementIsAnnotated) {
111 | annotatedTypeElements.add(typeElement);
112 | } else {
113 | reportNote("Cached element " + typeElement + " is not annotated any more");
114 | }
115 | }
116 |
117 | return annotatedTypeElements;
118 | }
119 |
120 | private Set getAnnotationTypeElements() {
121 | Set annotationQualifiedNames = getSupportedAnnotationTypes();
122 | Set annotationTypeElements = new HashSet();
123 | Elements elementUtils = processingEnv.getElementUtils();
124 | for (String annotationQualifiedName : annotationQualifiedNames) {
125 | TypeElement annotationTypeElement = elementUtils.getTypeElement(annotationQualifiedName);
126 | if (annotationTypeElement != null) {
127 | annotationTypeElements.add(annotationTypeElement);
128 | } else {
129 | reportError("Could not find annotation type element for " + annotationQualifiedName);
130 | }
131 | }
132 | return annotationTypeElements;
133 | }
134 |
135 | private Set getRoundAnnotatedElements(RoundEnvironment roundEnv, Set annotationTypeElements) {
136 | Set annotatedElements = new HashSet();
137 | for (TypeElement annotationTypeElement : annotationTypeElements) {
138 | Set extends Element> elementsAnnotatedWithAnnotation = roundEnv.getElementsAnnotatedWith(annotationTypeElement);
139 | Set typesAnnotatedWithAnnotation = ElementFilter.typesIn(elementsAnnotatedWithAnnotation);
140 | annotatedElements.addAll(typesAnnotatedWithAnnotation);
141 | }
142 | return annotatedElements;
143 | }
144 |
145 | /**
146 | *
147 | * @param roundAnnotatedElements
148 | * the annotated elements found in the current round will not be
149 | * loaded
150 | */
151 | private Set loadCachedAnnotatedElement(Set roundAnnotatedElements) {
152 | JavaFileManager.Location location = StandardLocation.SOURCE_OUTPUT;
153 | Filer filer = processingEnv.getFiler();
154 | try {
155 | FileObject resource = filer.getResource(location, CACHE_PACKAGE_NAME, CACHE_FILE_NAME);
156 | final boolean IGNORE_ENCODING_ERRORS = true;
157 | BufferedReader reader = new BufferedReader(resource.openReader(IGNORE_ENCODING_ERRORS));
158 | Elements elementUtils = processingEnv.getElementUtils();
159 | HashSet cachedAnnotatedTypeElements = new HashSet();
160 | String annotatedElementQualifiedName;
161 | while ((annotatedElementQualifiedName = reader.readLine()) != null) {
162 | if (annotatedElementQualifiedName.startsWith("#")) {
163 | continue;
164 | }
165 | TypeElement annotatedTypeElement = elementUtils.getTypeElement(annotatedElementQualifiedName);
166 | if (annotatedTypeElement != null) {
167 | if (!roundAnnotatedElements.contains(annotatedTypeElement)) {
168 | cachedAnnotatedTypeElements.add(annotatedTypeElement);
169 | }
170 | } else {
171 | reportNote("Could not find cached annotated type element for " + annotatedTypeElement);
172 | }
173 | }
174 | reader.close();
175 | return cachedAnnotatedTypeElements;
176 | } catch (Exception e) {
177 | reportNote("Could not load annotated elements cache (fine in case of full build)", e);
178 | return Collections.emptySet();
179 | }
180 | }
181 |
182 | private void generateDaggerModule(Set annotatedElements) {
183 | reportNote("Entry points found: " + annotatedElements);
184 | Filer filer = processingEnv.getFiler();
185 | try {
186 | String packageName = "info.piwai.cleanandroidcode";
187 | String moduleClassName = "EntryPointsModule";
188 | JavaFileObject sourceFile = filer.createSourceFile(packageName + "." + moduleClassName);
189 | BufferedWriter writer = new BufferedWriter(sourceFile.openWriter());
190 | writer.write("package " + packageName + ";");
191 | writer.newLine();
192 | writer.write("import dagger.Module;");
193 | writer.newLine();
194 | writer.write("@Module(");
195 | writer.newLine();
196 | writer.write(" entryPoints = {");
197 | writer.newLine();
198 |
199 | for (TypeElement typeElement : annotatedElements) {
200 | String qualifiedName = typeElement.getQualifiedName().toString();
201 | String aaGeneratedQualifiedName = qualifiedName + "_";
202 | writer.write(" " + aaGeneratedQualifiedName + ".class,");
203 | writer.newLine();
204 | }
205 |
206 | writer.write(" },");
207 | writer.newLine();
208 | writer.write(" complete = false");
209 | writer.newLine();
210 | writer.write(")");
211 | writer.newLine();
212 | writer.write("public final class " + moduleClassName + " {");
213 | writer.newLine();
214 | writer.write("}");
215 | writer.newLine();
216 | writer.close();
217 | } catch (IOException e) {
218 | reportNote("Could not generate Dagger module", e);
219 | }
220 | }
221 |
222 | private void cacheAnnotatedElements(Set annotatedElements) {
223 | try {
224 | TypeElement[] annotatedElementsArray = annotatedElements.toArray(new TypeElement[0]);
225 |
226 | JavaFileManager.Location location = StandardLocation.SOURCE_OUTPUT;
227 | Filer filer = processingEnv.getFiler();
228 | FileObject resource = filer.createResource(location, CACHE_PACKAGE_NAME, CACHE_FILE_NAME, annotatedElementsArray);
229 |
230 | BufferedWriter writer = new BufferedWriter(resource.openWriter());
231 | writer.write("# This file has been generated, please do not edit it");
232 | writer.newLine();
233 | for (TypeElement element : annotatedElements) {
234 | writer.write(element.getQualifiedName().toString());
235 | writer.newLine();
236 | }
237 | writer.close();
238 | } catch (IOException e) {
239 | reportNote("Could not cache annotated elements " + annotatedElements.toString() + " (fine in case of full build)", e);
240 | }
241 | }
242 |
243 | private void reportError(String message) {
244 | processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message);
245 | }
246 |
247 | private void reportNote(String message) {
248 | processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
249 | }
250 |
251 | private void reportNote(String message, Throwable throwable) {
252 | processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message + "\nException:\n" + stackTraceToString(throwable));
253 | }
254 |
255 | private String stackTraceToString(Throwable throwable) {
256 | StringWriter writer = new StringWriter();
257 | PrintWriter pw = new PrintWriter(writer);
258 | throwable.printStackTrace(pw);
259 | return writer.toString();
260 | }
261 | }
262 |
--------------------------------------------------------------------------------
/cleanandroidcode-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor:
--------------------------------------------------------------------------------
1 | info.piwai.cleanandroidcode.DaggerAAIntegrationProcessor
--------------------------------------------------------------------------------
/cleanandroidcode/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/cleanandroidcode/.factorypath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/cleanandroidcode/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | cleanandroidcode
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 | org.eclipse.m2e.core.maven2Builder
30 |
31 |
32 |
33 |
34 |
35 | com.android.ide.eclipse.adt.AndroidNature
36 | org.eclipse.jdt.core.javanature
37 | org.eclipse.m2e.core.maven2Nature
38 |
39 |
40 |
--------------------------------------------------------------------------------
/cleanandroidcode/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding//src/main/java=UTF-8
3 | encoding//src/test/java=UTF-8
4 | encoding/=UTF-8
5 |
--------------------------------------------------------------------------------
/cleanandroidcode/.settings/org.eclipse.jdt.apt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.apt.aptEnabled=true
3 | org.eclipse.jdt.apt.genSrcDir=.apt_generated
4 | org.eclipse.jdt.apt.reconcileEnabled=true
5 |
--------------------------------------------------------------------------------
/cleanandroidcode/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.6
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
12 | org.eclipse.jdt.core.compiler.processAnnotations=enabled
13 | org.eclipse.jdt.core.compiler.source=1.6
14 |
--------------------------------------------------------------------------------
/cleanandroidcode/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | activeProfiles=
2 | eclipse.preferences.version=1
3 | resolveWorkspaceProjects=true
4 | version=1
5 |
--------------------------------------------------------------------------------
/cleanandroidcode/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/cleanandroidcode/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 |
7 | info.piwai.cleanandroidcode
8 | cleanandroidcode-parent
9 | 1.0-SNAPSHOT
10 |
11 |
12 | cleanandroidcode
13 | apk
14 | cleanandroidcode - Application
15 |
16 |
17 |
18 | com.google.android
19 | android
20 |
21 |
22 | com.google.android
23 | support-v4
24 |
25 |
26 | com.squareup
27 | otto
28 |
29 |
30 | com.squareup
31 | dagger
32 |
33 |
34 | com.googlecode.androidannotations
35 | androidannotations-api
36 |
37 |
39 |
40 | info.piwai.cleanandroidcode
41 | cleanandroidcode-processor
42 |
43 |
44 | com.googlecode.androidannotations
45 | androidannotations
46 |
47 |
48 | com.squareup
49 | dagger-compiler
50 |
51 |
52 |
53 |
54 |
55 | com.jayway.maven.plugins.android.generation2
56 | android-maven-plugin
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/cleanandroidcode/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-16
15 |
--------------------------------------------------------------------------------
/cleanandroidcode/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/cleanandroidcode/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/cleanandroidcode/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/cleanandroidcode/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/cleanandroidcode/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/cleanandroidcode/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/cleanandroidcode/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/cleanandroidcode/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/cleanandroidcode/res/layout/hello_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/cleanandroidcode/res/layout/hello_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
19 |
20 |
--------------------------------------------------------------------------------
/cleanandroidcode/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CleanAndroidCode
5 |
6 | Click me!
7 |
8 | This is a fragment!
9 |
10 |
--------------------------------------------------------------------------------
/cleanandroidcode/src/main/java/info/piwai/cleanandroidcode/HelloAndroidActivity.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode;
2 |
3 | import info.piwai.cleanandroidcode.base.BaseActivity;
4 |
5 | import com.googlecode.androidannotations.annotations.EActivity;
6 | import com.squareup.otto.Subscribe;
7 |
8 | @EActivity(R.layout.hello_activity)
9 | public class HelloAndroidActivity extends BaseActivity {
10 |
11 | @Subscribe
12 | public void onUpdateTitle(UpdateTitleEvent event) {
13 | setTitle(event.title);
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/cleanandroidcode/src/main/java/info/piwai/cleanandroidcode/HelloApplication.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode;
2 |
3 | import info.piwai.cleanandroidcode.base.BaseModule;
4 | import info.piwai.cleanandroidcode.base.GraphRetriever.GraphApplication;
5 | import android.app.Application;
6 | import dagger.ObjectGraph;
7 |
8 | public class HelloApplication extends Application implements GraphApplication {
9 |
10 | private ObjectGraph graph;
11 |
12 | @Override
13 | public void onCreate() {
14 | super.onCreate();
15 | graph = ObjectGraph.create(new BaseModule(), new EntryPointsModule());
16 | }
17 |
18 | @Override
19 | public ObjectGraph getGraph() {
20 | return graph;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/cleanandroidcode/src/main/java/info/piwai/cleanandroidcode/HelloFragment.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode;
2 |
3 | import info.piwai.cleanandroidcode.base.BaseFragment;
4 |
5 | import javax.inject.Inject;
6 |
7 | import com.googlecode.androidannotations.annotations.Click;
8 | import com.googlecode.androidannotations.annotations.EFragment;
9 | import com.squareup.otto.Bus;
10 |
11 | @EFragment(R.layout.hello_fragment)
12 | public class HelloFragment extends BaseFragment {
13 |
14 | @Inject
15 | Bus bus;
16 |
17 | @Click
18 | void fragmentButtonClicked() {
19 | bus.post(new UpdateTitleEvent("Button clicked at " + System.currentTimeMillis()));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/cleanandroidcode/src/main/java/info/piwai/cleanandroidcode/UpdateTitleEvent.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode;
2 |
3 | public class UpdateTitleEvent {
4 |
5 | public final CharSequence title;
6 |
7 | public UpdateTitleEvent(String title) {
8 | this.title = title;
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/cleanandroidcode/src/main/java/info/piwai/cleanandroidcode/base/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode.base;
2 |
3 | import javax.inject.Inject;
4 |
5 | import android.os.Bundle;
6 | import android.support.v4.app.FragmentActivity;
7 |
8 | import com.squareup.otto.Bus;
9 |
10 | public class BaseActivity extends FragmentActivity {
11 |
12 | @Inject
13 | Bus bus;
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | GraphRetriever.from(this).inject(this);
19 | bus.register(this);
20 | }
21 |
22 | @Override
23 | protected void onDestroy() {
24 | super.onDestroy();
25 | bus.unregister(this);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/cleanandroidcode/src/main/java/info/piwai/cleanandroidcode/base/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode.base;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 |
6 | public abstract class BaseFragment extends Fragment {
7 |
8 | @Override
9 | public void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GraphRetriever.from(getActivity()).inject(this);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/cleanandroidcode/src/main/java/info/piwai/cleanandroidcode/base/BaseModule.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode.base;
2 |
3 | import javax.inject.Singleton;
4 |
5 | import com.squareup.otto.Bus;
6 |
7 | import dagger.Module;
8 | import dagger.Provides;
9 |
10 | @Module
11 | public class BaseModule {
12 |
13 | @Provides
14 | @Singleton
15 | Bus provideBus() {
16 | return new Bus();
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/cleanandroidcode/src/main/java/info/piwai/cleanandroidcode/base/GraphRetriever.java:
--------------------------------------------------------------------------------
1 | package info.piwai.cleanandroidcode.base;
2 |
3 | import android.app.Activity;
4 | import dagger.ObjectGraph;
5 |
6 | public class GraphRetriever {
7 |
8 | public interface GraphApplication {
9 | ObjectGraph getGraph();
10 | }
11 |
12 | public static ObjectGraph from(Activity activity) {
13 | GraphApplication application = (GraphApplication) activity.getApplication();
14 | return application.getGraph();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | info.piwai.cleanandroidcode
6 | cleanandroidcode-parent
7 | 1.0-SNAPSHOT
8 | pom
9 | cleanandroidcode - Parent
10 |
11 |
12 | cleanandroidcode
13 | cleanandroidcode-it
14 | cleanandroidcode-processor
15 |
16 |
17 |
18 | 1.6
19 | 4.1.1.4
20 | 16
21 | r7
22 | UTF-8
23 | 2.0.0-SNAPSHOT
24 | 0.9.1
25 | 2.7
26 |
27 |
28 |
29 |
30 |
31 | info.piwai.cleanandroidcode
32 | cleanandroidcode-processor
33 | ${project.version}
34 | provided
35 |
36 |
37 | info.piwai.cleanandroidcode
38 | cleanandroidcode
39 | apk
40 | ${project.version}
41 |
42 |
43 | info.piwai.cleanandroidcode
44 | cleanandroidcode
45 | jar
46 | ${project.version}
47 |
48 |
49 | com.google.android
50 | android
51 | ${android.version}
52 | provided
53 |
54 |
55 | com.google.android
56 | android-test
57 | ${android.version}
58 | provided
59 |
60 |
61 | com.google.android
62 | support-v4
63 | ${android-support.version}
64 |
65 |
66 | com.squareup
67 | otto
68 | ${otto.version}
69 |
70 |
71 | com.squareup
72 | dagger
73 | ${dagger.version}
74 |
75 |
76 | com.squareup
77 | dagger-compiler
78 | ${dagger.version}
79 | provided
80 |
81 |
82 | com.googlecode.androidannotations
83 | androidannotations
84 | ${androidannotations.version}
85 | provided
86 |
87 |
88 | com.googlecode.androidannotations
89 | androidannotations-api
90 | ${androidannotations.version}
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | maven-compiler-plugin
100 | 2.5.1
101 |
102 | ${java.version}
103 | ${java.version}
104 |
105 |
106 |
107 | com.jayway.maven.plugins.android.generation2
108 | android-maven-plugin
109 | 3.4.0
110 |
111 |
112 | ${platform.version}
113 |
114 | true
115 |
116 | true
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------