In my Android Application I have an annotation processor which generates files using JavaPoet and places them under the package generated.schema.
The files are generating correctly. Whenever I use the generated file like so
GeneratedFile.someGeneratedMethod();
I get the following error:
error: package generated.schema does not exist.
But if I include the fully qualified class name instead of importing like so
generated.schema.GeneratedFile.someGeneratedMethod();
the code compiles and runs without any error.
I don't want to add complete package each time I am using GeneratedFile. I'm not sure what I did wrong, since I'm still learning to work with Annotation Processor.
Files generated by other libraries including Realm, DataBinding are all working correctly as expected.
File Generation :
using JavaPoet I run the following code.
if (roundEnvironment.processingOver()) {
for (TypeElement element : apiList) {
TypeSpec clazz = generateFile(element);
JavaFile.builder(NamespaceCreator.generateClassPackage(element), clazz)
.build()
.writeTo(filer);
}
}
NamespaceCreator.generateClassPackage(element) returns the package name for class i.e generated.schema.
While generating classes I was waiting for the last processing pass. the code generation encapsulated by
if (roundEnvironment.processingOver())
I was getting a warning because of this:
File for type 'generated.schema.GeneratedFile' created in the last round will not be subject to annotation processing.
I was aware of this warning before I posted the question, however I was willing to ignore further annotation processing on my generated files for simplicity of generating all files in one go.
Even though, after removing the last round/pass check from file generation I can correctly (with import) access the generated files without any error; I still don't understand how generating files throughout all rounds affects accessing files during build with import.
For that I will be posting a new question.
Related
I'm writing a Java annotation processor that creates package-info for packages in a Java project.
The code to actually generate the source file looks somewhat like this:
JavaFileObject builderFile = filer.createSourceFile(packageName + ".package-info");
try (PrintWriter out = new PrintWriter(builderFile.openWriter()))
{
out.println("... file content ...");
}
Unfortunately, this code crashes when there already is a package-info for the given package, either in the source code or generated by a previous round.
Normally, I would just skip the generation if a package-info already exists, but I couldn't find any way to test for the existence of a package-info.
processingEnv.getElementUtils().getPackageElement(packageName)
Always returns a PackageElement, regardless of whether there is a package-info or not, which seams reasonable, because the package exists with or without the package-info.
There also doesn't seem to be an ElementKind for package-info either and PackageElement.getEnclosedElements() only returns the top level classes and interfaces in that package.
In lack of a better solution, I'm currently catching and ignoring the IOException thrown by Filer.createSourceFile(String) in case the package-info already exists.
Is there a way to check if a certain package already contains a package-info?
Edit:
FWIW, the source file can be found on Github
I want to get the directories of the source files which are getting compiled after annotation processing while doing the annotation processing without relying on directory/build tool conventions.
public class MyProcessor extends AbstractProcessor {
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// Get the directories with source files to be compiled here
// For example, I should be able to find all classes which I obtain via the following in the directories I want:
roundEnv.getElementsAnnotatedWith(MyAnnotation.class)
}
}
I have tried:
A relative path which I got with Paths.get("."). But not only would I still have to rely on directory/build tool conventions to get to the source directories, it also doesn't work when the build is started from anywhere else but the project root.
Checking all properties in System.getProperties() and System.getenv() to see if there is anything useful being set.
Checked javax.lang.model.element.TypeElement, javax.lang.model.type.TypeMirror and the corresponding utility methods to see if I can get an instance's location (Did I miss something?)
Checked various combinations of StandardJavaFileManager's methods, some of which suggest to return what I want, but returning either null/empty collections or throwing exceptions for module related parameters. Example: standardJavaFileManager.list(StandardLocation.SOURCE_PATH, "", Set.of(Kind.SOURCE), true).
// edit
I'm trying to create a functionality where classes can be picked up based on super-types. For that, I created an Annotation where I can specify these super-types. I now need to scan all source files to check for classes that are sub-types of X, for which I am using a library. Said library needs to be pointed to a directory containing the classes to scan, which is why I need the source folder.
I have developed eclipse plugin which for any given java project create GUI in form of package structure. I have successfully run my plugin for different java project.
Now, I thought should try my code in some open source project, therefore, I download JDOM Framework.
However, I found that the JDOM source code has this structure.
JDOM -> contrib -> src -> java -> org -> jdom2......
where as i assume that the project will have always below structure
Project Name -> Src -> PACKAGE NAME STARTS HERE.....
I load the classes using below code,
IPackageFragment[] packages = javaProject.getPackageFragments();
for (IPackageFragment mypackage : packages) {
if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
for (ICompilationUnit unit : mypackage.getCompilationUnits()) {
// unit.getPath().toString() give me path, but how to extract only class name with package
// save it in to MAP with Package as key
}
}
}
Now, I want to show classes with only package name, therefore, I remove first two string (PROJECT NAME, SRC), but this cannot be always the case as for JDOM Framework.
Therefore, how can I get only package name along with class name using my method above? Or should I use different mechanism?
Looking at the directory structure alone seems to be an awfully error-prone way to go about it. Who knows how deep the directory tree goes? If instead you scan for Java source files, you should be able to construct a reader that finds the package declaration at the beginning of the file. If there isn't one, you don't need to worry about it. Do I need to say you can store package names in a HashSet to avoid duplicate package declarations?
The ICompilationUnit has a findPrimaryType method:
IType primaryType = unit.findPrimaryType();
and IType has getFullyQualifiedName():
String name = primaryType.getFullyQualifiedName();
I have an object profileModel in my profile package and my profile.scala.html file have following code
#(model: ProfileModel)
when I compiles, it is giving an error recursive value model needs type
But when I moved this class to models with my application.conf as
ebean.default="models.*"
it works.
My guess is scala compiler automatically adds models.* to class path at the time of compilation
Is there a way to make this work without moving the class back to models package ?
I am using play 2.2.1 built with Scala 2.10.2
If I understand you right, if your ProfileModel exists in profile package correct declaration in the view should be:
#(myProfile: profile.ProfileModel)
And 'yes', Play imports automatically all models and controllers (and also other well known types), but if you want to use any type in custom package (or ie. imported lib) you need to use full qualified path to it.
I have successfully created an Acceleo module for M2T purposes and am trying to execute it from a Java program.
This is what I tried :
String[] str = {"/home/hamza/workspace/HLRedundancy/model/System1.xmi", "/home/hamza/workspace/HLRedundancy/"};
Generate.main(str);
Generate being the name of the Acceleo module I created and thus, the name of the Java class containing the Acceleo generation methods.
Here is the error I'm always getting :
Exception in thread "main" org.eclipse.acceleo.engine.AcceleoEvaluationException: The type of the first parameter of the main template named 'generateElement' is a proxy.
at org.eclipse.acceleo.engine.service.AcceleoService.doGenerate(AcceleoService.java:566)
at org.eclipse.acceleo.engine.service.AbstractAcceleoGenerator.generate(AbstractAcceleoGenerator.java:193)
at org.eclipse.acceleo.engine.service.AbstractAcceleoGenerator.doGenerate(AbstractAcceleoGenerator.java:158)
at HighLevelGenerator.main.Generate.doGenerate(Generate.java:250)
at HighLevelGenerator.main.Generate.main(Generate.java:160)
at Execute.main(Execute.java:11)
I've been searching for a while about this error but I have no idea about its cause.
Any idea about a solution to my problem ?
Thanks
The most common cause of this issue is failure in properly registering the metamodel and factory corresponding to your inpu model (System1.xmi).
If you look at the comments in the generated class "Generate.java", you will notice a number of places where we indicate steps to follow if running in standalone. The most important begin registerPackages where you are required to register your metamodel.
If you debug the launch down to the point where the model is loaded (place a breakpoint right after the line model = ModelUtils.load(newModelURI, modelResourceSet);), you can look at the model.eResource().getErrors() list to see whether there were errors loading your model.
You might also be interested in looking at this video describing the process (registration required) .
Check out the first line of your acceleo module,
what is the URI of the metamodel? Does it start with 'http://' ?
Maybe this can help:
Acceleo stand alone - first parameter is proxy
This issue happen when your meta model contains sub-packages and the top package not contain any class.
to solve the problem, add a Dummy class the the top package and regenerate the meta-model code. It worked fine for me.