New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically detect ViewHolder fields #4

Open
sockeqwe opened this Issue Oct 16, 2014 · 10 comments

Comments

Projects
None yet
2 participants
@sockeqwe
Owner

sockeqwe commented Oct 16, 2014

Automatically detect fields from the corresponding xml layout files by checking for views with an id. So you don't have to specify fields for the view holder by hand with@Field

However, that's not an easy task:

  1. How do I access resource folder from the annotation processor? It runs in it's own jvm. How do I get the path of the current execution
  2. Layout xml files in different folders like layout, xlarge-layout etc.
  3. The res folder itself is configureable through gradle configuration
  4. xml layout can include other layouts

However it would be awesome to have such a feature!

@sockeqwe sockeqwe self-assigned this Oct 16, 2014

@sockeqwe sockeqwe added this to the 2.0 milestone Oct 16, 2014

@sockeqwe sockeqwe changed the title from Automatically detect fields to Automatically detect ViewHolder fields Oct 16, 2014

@sockeqwe

This comment has been minimized.

Show comment
Hide comment
@sockeqwe

sockeqwe Oct 19, 2014

Owner

Tried to get the path to the folder containing the project with:

 private String getExecutionPath() throws UnsupportedEncodingException {
    String path = AnnotatedAdapterProcessor.class.getProtectionDomain()
        .getCodeSource()
        .getLocation()
        .getPath();
    String decodedPath = URLDecoder.decode(path, "UTF-8");

    return decodedPath;
  }

  private String getWorkingDir() {
    Path currentRelativePath = Paths.get("");
    String s = currentRelativePath.toAbsolutePath().toString();
    return s;
  }

  private String getExcecutionByClassLoader() {
    ClassLoader loader = AnnotatedAdapterProcessor.class.getClassLoader();
    URL url = loader.getResource(".");
    return url.getFile();
  }

  private String getByEnv() {
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null);

    Iterable<? extends File> locations = fm.getLocation(StandardLocation.SOURCE_PATH);
    if (locations.iterator().hasNext()) {
      return locations.iterator().next().getAbsolutePath();
    }
    return null;
  }

None of this method returns the desired result

Owner

sockeqwe commented Oct 19, 2014

Tried to get the path to the folder containing the project with:

 private String getExecutionPath() throws UnsupportedEncodingException {
    String path = AnnotatedAdapterProcessor.class.getProtectionDomain()
        .getCodeSource()
        .getLocation()
        .getPath();
    String decodedPath = URLDecoder.decode(path, "UTF-8");

    return decodedPath;
  }

  private String getWorkingDir() {
    Path currentRelativePath = Paths.get("");
    String s = currentRelativePath.toAbsolutePath().toString();
    return s;
  }

  private String getExcecutionByClassLoader() {
    ClassLoader loader = AnnotatedAdapterProcessor.class.getClassLoader();
    URL url = loader.getResource(".");
    return url.getFile();
  }

  private String getByEnv() {
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null);

    Iterable<? extends File> locations = fm.getLocation(StandardLocation.SOURCE_PATH);
    if (locations.iterator().hasNext()) {
      return locations.iterator().next().getAbsolutePath();
    }
    return null;
  }

None of this method returns the desired result

@fcolasuonno

This comment has been minimized.

Show comment
Hide comment
@fcolasuonno

fcolasuonno Oct 24, 2014

You could pass an argument to the apt processor:
By adding the following to the build.gradle:

apt {
    arguments {
        androidManifestFile variant.processResources.manifestFile
    }
}

the manifest file location will be passed as argument to the processor, then you can retrieve the layouts like this:

final String androidManifestFile = processingEnv.getOptions().get("androidManifestFile");
int index = androidManifestFile.lastIndexOf("manifests");
File androidManifest = new File(androidManifestFile);
String variant = androidManifest.getParentFile().getName();
File layoutsDir = new File(androidManifestFile.substring(0,index),"res/"+variant+"/layout");

for (File file : layoutsDir.listFiles()) {
     processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,file.getAbsolutePath());
}

(error checking omitted)

fcolasuonno commented Oct 24, 2014

You could pass an argument to the apt processor:
By adding the following to the build.gradle:

apt {
    arguments {
        androidManifestFile variant.processResources.manifestFile
    }
}

the manifest file location will be passed as argument to the processor, then you can retrieve the layouts like this:

final String androidManifestFile = processingEnv.getOptions().get("androidManifestFile");
int index = androidManifestFile.lastIndexOf("manifests");
File androidManifest = new File(androidManifestFile);
String variant = androidManifest.getParentFile().getName();
File layoutsDir = new File(androidManifestFile.substring(0,index),"res/"+variant+"/layout");

for (File file : layoutsDir.listFiles()) {
     processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,file.getAbsolutePath());
}

(error checking omitted)

@sockeqwe

This comment has been minimized.

Show comment
Hide comment
@sockeqwe

sockeqwe Oct 24, 2014

Owner

Thanks, good idea!
That looks really promising!

android {
 sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            res.srcDirs = ['res']
        }
    }
}

I guess that the path to res folder can be passed directly as annotation processor option somehow ...

Owner

sockeqwe commented Oct 24, 2014

Thanks, good idea!
That looks really promising!

android {
 sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            res.srcDirs = ['res']
        }
    }
}

I guess that the path to res folder can be passed directly as annotation processor option somehow ...

@fcolasuonno

This comment has been minimized.

Show comment
Hide comment
@fcolasuonno

fcolasuonno Oct 24, 2014

According to http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Manipulating-tasks
you could get the resource dir by using

apt {
    arguments {
        androidManifestFile variant.processResources.resDir
    }
}

But I don't know if it's valid in case multiple resource dirs are specified in the sourceSets

fcolasuonno commented Oct 24, 2014

According to http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Manipulating-tasks
you could get the resource dir by using

apt {
    arguments {
        androidManifestFile variant.processResources.resDir
    }
}

But I don't know if it's valid in case multiple resource dirs are specified in the sourceSets

@sockeqwe

This comment has been minimized.

Show comment
Hide comment
@sockeqwe

sockeqwe Oct 24, 2014

Owner

Awesome! Thanks! I will try that tomorrow!

Owner

sockeqwe commented Oct 24, 2014

Awesome! Thanks! I will try that tomorrow!

@sockeqwe

This comment has been minimized.

Show comment
Hide comment
@sockeqwe

sockeqwe Oct 25, 2014

Owner

But what if you want to use AnnotatedAdapter within a android library project? The layoutfiles will be somewhere in build/generated/intermediates/library-package-name/res/

But I guess to getting started we could say: Use the @Field annotations for library projects because you have to specify them explicit because auto detecting ViewHolder classes by scanning xml layouts does not work for library projects.

For the normal app project we could use the auto ViewHolder detection mode by scanning xml files of the app projects res folder passed as Annotation Processor option like suggested by you:

apt {
    arguments {
        androidManifestFile variant.processResources.resDir
    }
}

Do you see a better solution?

Owner

sockeqwe commented Oct 25, 2014

But what if you want to use AnnotatedAdapter within a android library project? The layoutfiles will be somewhere in build/generated/intermediates/library-package-name/res/

But I guess to getting started we could say: Use the @Field annotations for library projects because you have to specify them explicit because auto detecting ViewHolder classes by scanning xml layouts does not work for library projects.

For the normal app project we could use the auto ViewHolder detection mode by scanning xml files of the app projects res folder passed as Annotation Processor option like suggested by you:

apt {
    arguments {
        androidManifestFile variant.processResources.resDir
    }
}

Do you see a better solution?

@fcolasuonno

This comment has been minimized.

Show comment
Hide comment
@fcolasuonno

fcolasuonno Oct 26, 2014

I though about that, apart from scanning recursively from the intermediates dir looking for res folders I can't think of anything else. If as layout they use android.R.layout.simple_list_item_2, for example, it won't be in the intermediates at all, because it's part of the android framework and it's located in the android sdk dir..

I think the most common case will be with the layout xml in the project, anyway.

A better name for the apt argument would probably be androidResourceDir, I forgot to change it in the previous comment, so in gradle there will be

apt {
    arguments {
        androidResourceDir variant.processResources.resDir
    }
}

and in the processor:

final String androidResourceDir = processingEnv.getOptions().get("androidResourceDir");
File layoutsDir = new File(androidResourceDir);

for (File file : layoutsDir.listFiles()) {
     processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,file.getAbsolutePath());
}

fcolasuonno commented Oct 26, 2014

I though about that, apart from scanning recursively from the intermediates dir looking for res folders I can't think of anything else. If as layout they use android.R.layout.simple_list_item_2, for example, it won't be in the intermediates at all, because it's part of the android framework and it's located in the android sdk dir..

I think the most common case will be with the layout xml in the project, anyway.

A better name for the apt argument would probably be androidResourceDir, I forgot to change it in the previous comment, so in gradle there will be

apt {
    arguments {
        androidResourceDir variant.processResources.resDir
    }
}

and in the processor:

final String androidResourceDir = processingEnv.getOptions().get("androidResourceDir");
File layoutsDir = new File(androidResourceDir);

for (File file : layoutsDir.listFiles()) {
     processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,file.getAbsolutePath());
}
@sockeqwe

This comment has been minimized.

Show comment
Hide comment
@sockeqwe

sockeqwe Dec 24, 2015

Owner

Somewhere in the android gradle plugin documentation site is described how
to get the path for the resource folder, but at the end you have to pass
this path to your annotation processor (annotation processor can have
options).

andbrain notifications@github.com schrieb am Do., 24. Dez. 2015 um
17:07 Uhr:

how are you friends i need working sample for access to resource folder
from the annotation processor
his codes not work for me hope helps me so soon :D


Reply to this email directly or view it on GitHub
#4 (comment)
.

Owner

sockeqwe commented Dec 24, 2015

Somewhere in the android gradle plugin documentation site is described how
to get the path for the resource folder, but at the end you have to pass
this path to your annotation processor (annotation processor can have
options).

andbrain notifications@github.com schrieb am Do., 24. Dez. 2015 um
17:07 Uhr:

how are you friends i need working sample for access to resource folder
from the annotation processor
his codes not work for me hope helps me so soon :D


Reply to this email directly or view it on GitHub
#4 (comment)
.

@sockeqwe

This comment has been minimized.

Show comment
Hide comment
@sockeqwe

sockeqwe Dec 24, 2015

Owner

what do you mean with "to my annotation processor?". This feature is not
implemented yet in AnnotatedAdapter. Are you going to implement your own
annotation processor?

andbrain notifications@github.com schrieb am Do., 24. Dez. 2015 um
17:12 Uhr:

THANK Hannes Dorfmann happy to see your replying please just tell how pass
this path to your annotation processor :D


Reply to this email directly or view it on GitHub
#4 (comment)
.

Owner

sockeqwe commented Dec 24, 2015

what do you mean with "to my annotation processor?". This feature is not
implemented yet in AnnotatedAdapter. Are you going to implement your own
annotation processor?

andbrain notifications@github.com schrieb am Do., 24. Dez. 2015 um
17:12 Uhr:

THANK Hannes Dorfmann happy to see your replying please just tell how pass
this path to your annotation processor :D


Reply to this email directly or view it on GitHub
#4 (comment)
.

@sockeqwe

This comment has been minimized.

Show comment
Hide comment
@sockeqwe

sockeqwe Dec 24, 2015

Owner

You have to override getSupportedOptions() in your annotation processor. Like this: https://github.com/sockeqwe/fragmentargs/blob/master/processor/src/main/java/com/hannesdorfmann/fragmentargs/processor/ArgProcessor.java#L107

Then with android apt plugin you can do something like this:

apt {
  arguments {
    resPath "path/to/res/folder"
  }
}
Owner

sockeqwe commented Dec 24, 2015

You have to override getSupportedOptions() in your annotation processor. Like this: https://github.com/sockeqwe/fragmentargs/blob/master/processor/src/main/java/com/hannesdorfmann/fragmentargs/processor/ArgProcessor.java#L107

Then with android apt plugin you can do something like this:

apt {
  arguments {
    resPath "path/to/res/folder"
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment