2222import java .io .FileNotFoundException ;
2323import java .io .IOException ;
2424import java .util .ArrayList ;
25+ import java .util .Arrays ;
26+ import java .util .Collections ;
2527import java .util .List ;
2628import java .util .Properties ;
29+ import java .util .regex .Matcher ;
30+ import java .util .regex .Pattern ;
2731
2832import javax .lang .model .util .Elements ;
2933import javax .xml .parsers .DocumentBuilder ;
@@ -46,7 +50,6 @@ public class AndroidManifestFinder {
4650 public static final Option OPTION_MANIFEST = new Option ("androidManifestFile" , null );
4751
4852 private static final Logger LOGGER = LoggerFactory .getLogger (AndroidManifestFinder .class );
49- private static final int MAX_PARENTS_FROM_SOURCE_FOLDER = 10 ;
5053
5154 private final AndroidAnnotationsEnvironment environment ;
5255
@@ -88,7 +91,7 @@ private File findManifestFile() throws FileNotFoundException {
8891 if (androidManifestFile != null ) {
8992 return findManifestInSpecifiedPath (androidManifestFile );
9093 } else {
91- return findManifestInParentsDirectories ();
94+ return findManifestInKnownPaths ();
9295 }
9396 }
9497
@@ -103,43 +106,110 @@ private File findManifestInSpecifiedPath(String androidManifestPath) throws File
103106 return androidManifestFile ;
104107 }
105108
106- /**
107- * We use a dirty trick to find the AndroidManifest.xml file, since it's not
108- * available in the classpath. The idea is quite simple : create a fake
109- * class file, retrieve its URI, and start going up in parent folders to
110- * find the AndroidManifest.xml file. Any better solution will be
111- * appreciated.
112- */
113- private File findManifestInParentsDirectories () throws FileNotFoundException {
114- FileHelper .FileHolder projectRootHolder = FileHelper .findRootProjectHolder (environment .getProcessingEnvironment ());
115-
116- File projectRoot = projectRootHolder .projectRoot ;
117-
118- File androidManifestFile = new File (projectRoot , "AndroidManifest.xml" );
119- for (int i = 0 ; i < MAX_PARENTS_FROM_SOURCE_FOLDER ; i ++) {
120- if (androidManifestFile .exists ()) {
109+ private File findManifestInKnownPaths () throws FileNotFoundException {
110+ FileHelper .FileHolder holder = FileHelper .findRootProjectHolder (environment .getProcessingEnvironment ());
111+ return findManifestInKnownPathsStartingFromGenFolder (holder .sourcesGenerationFolder .getAbsolutePath ());
112+ }
113+
114+ File findManifestInKnownPathsStartingFromGenFolder (String sourcesGenerationFolder ) throws FileNotFoundException {
115+ Iterable <AndroidManifestFinderStrategy > strategies = Arrays .asList (new GradleAndroidManifestFinderStrategy (sourcesGenerationFolder ),
116+ new MavenAndroidManifestFinderStrategy (sourcesGenerationFolder ), new EclipseAndroidManifestFinderStrategy (sourcesGenerationFolder ));
117+
118+ AndroidManifestFinderStrategy applyingStrategy = null ;
119+
120+ for (AndroidManifestFinderStrategy strategy : strategies ) {
121+ if (strategy .applies ()) {
122+ applyingStrategy = strategy ;
121123 break ;
122- } else {
123- if (projectRoot .getParentFile () != null ) {
124- projectRoot = projectRoot .getParentFile ();
125- androidManifestFile = new File (projectRoot , "AndroidManifest.xml" );
126- } else {
127- break ;
128- }
129124 }
130125 }
131126
132- if (!androidManifestFile .exists ()) {
133- LOGGER .error ("Could not find the AndroidManifest.xml file, going up from path [{}] found using dummy file [{}] (max atempts: {})" ,
134- projectRootHolder .sourcesGenerationFolder .getAbsolutePath (), projectRootHolder .dummySourceFilePath , MAX_PARENTS_FROM_SOURCE_FOLDER );
135- throw new FileNotFoundException ();
127+ File androidManifestFile = null ;
128+
129+ if (applyingStrategy != null ) {
130+ androidManifestFile = applyingStrategy .findAndroidManifestFile ();
131+ }
132+
133+ if (androidManifestFile != null ) {
134+ LOGGER .debug ("{} AndroidManifest.xml file found using generation folder {}: {}" , applyingStrategy .name , sourcesGenerationFolder , androidManifestFile .toString ());
136135 } else {
137- LOGGER .debug ( " AndroidManifest.xml file found in parent folder {}: {} " , projectRoot . getAbsolutePath (), androidManifestFile . toString () );
136+ LOGGER .error ( "Could not find the AndroidManifest.xml file, using generation folder [{}]) " , sourcesGenerationFolder );
138137 }
139138
140139 return androidManifestFile ;
141140 }
142141
142+ private static abstract class AndroidManifestFinderStrategy {
143+ final String name ;
144+
145+ final Matcher matcher ;
146+
147+ AndroidManifestFinderStrategy (String name , Pattern sourceFolderPattern , String sourceFolder ) {
148+ this .name = name ;
149+ this .matcher = sourceFolderPattern .matcher (sourceFolder );
150+ }
151+
152+ File findAndroidManifestFile () {
153+ for (String location : possibleLocations ()) {
154+ File manifestFile = new File (matcher .group (1 ), location + "/AndroidManifest.xml" );
155+ if (manifestFile .exists ()) {
156+ return manifestFile ;
157+ }
158+ }
159+ return null ;
160+ }
161+
162+ boolean applies () {
163+ return matcher .matches ();
164+ }
165+
166+ abstract Iterable <String > possibleLocations ();
167+ }
168+
169+ private static class GradleAndroidManifestFinderStrategy extends AndroidManifestFinderStrategy {
170+
171+ static final Pattern GRADLE_GEN_FOLDER = Pattern .compile ("^(.*?)build[\\ \\ /]generated[\\ \\ /]source[\\ \\ /]apt(.*)$" );
172+
173+ GradleAndroidManifestFinderStrategy (String sourceFolder ) {
174+ super ("Gradle" , GRADLE_GEN_FOLDER , sourceFolder );
175+ }
176+
177+ @ Override
178+ Iterable <String > possibleLocations () {
179+ String gradleVariant = matcher .group (2 );
180+
181+ return Arrays .asList ("build/intermediates/manifests/full" + gradleVariant , "build/bundles" + gradleVariant );
182+ }
183+ }
184+
185+ private static class MavenAndroidManifestFinderStrategy extends AndroidManifestFinderStrategy {
186+
187+ static final Pattern MAVEN_GEN_FOLDER = Pattern .compile ("^(.*?)target[\\ \\ /]generated-sources.*$" );
188+
189+ MavenAndroidManifestFinderStrategy (String sourceFolder ) {
190+ super ("Maven" , MAVEN_GEN_FOLDER , sourceFolder );
191+ }
192+
193+ @ Override
194+ Iterable <String > possibleLocations () {
195+ return Arrays .asList ("target" , "src/main" , "" );
196+ }
197+ }
198+
199+ private static class EclipseAndroidManifestFinderStrategy extends AndroidManifestFinderStrategy {
200+
201+ static final Pattern ECLIPSE_GEN_FOLDER = Pattern .compile ("^(.*?)\\ .apt_generated.*$" );
202+
203+ EclipseAndroidManifestFinderStrategy (String sourceFolder ) {
204+ super ("Eclipse" , ECLIPSE_GEN_FOLDER , sourceFolder );
205+ }
206+
207+ @ Override
208+ Iterable <String > possibleLocations () {
209+ return Collections .singleton ("" );
210+ }
211+ }
212+
143213 private AndroidManifest parse (File androidManifestFile , boolean libraryProject ) throws AndroidManifestNotFoundException {
144214 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory .newInstance ();
145215
0 commit comments