Java Annotation processor check for full rebuild - java

I am creating an Annotation Processor in Java and I want to be able to check if the user triggers a full rebuild.
I want to be able distingush between a full rebuild and just building a few files.
Is this possible? Or are there any workarounds for this?
Edit1:
I am going to explain what I want to achieve. I have an annotation processor and 10 annotations. 8 of these Annotations generate a config file called plugin.yml. 3 of these annotations (one annotation is used in both processes) are used to generate a sourcefile called AutoRegister.java. This works like a charm when I trigger a full rebuild and all my annotations get processed. Now the problem arises when I only compile, lets say 3 of the 15 classes using my annotations. Then the plugin.yml and the AutoRegister.java get generated based on the Annotations of the 3 files, thus beeing incomplete.
My workaround is to create a cache file, which contains information about all the other classes, which need to be insertet to the two files plugin.yml and AutoRegister.java. This somewhat works but makes it impossible to remove data from the cache, for example when I remove an annotation from a class. So the only way to remove data from the cache is to remove the cache file and to trigger a full rebuild.

I don't think the term 'workaround' means what you think it means. If there was a way to distinguish, that would just be 'the answer', not 'the workaround'. If you elaborate on WHY you need this, perhaps a different solution is available, that is NOT directly detecting 'full rebuild' versus 'incremental build', which nevertheless is sufficient for your needs. That'd be a workaround, but you'd have to explain why you need it in order for us to try to help you out.
Here's the most common reason I can think of for why you need this:
Let's say your AP will scan all source files, and distill some sort of list from it. For example, all classes that implement com.derteufelqwe.MyAwesomeInterface. Then, it writes this list someplace. Say, META-INF/services/com.derteufelqwe.MyAwesomeInterface. The problem is: During incremental builds, you only see a subset of all sources, therefore the list is incomplete, then you write it where ever it needs to be written and now you have a broken list (as it is incomplete).
The fix for this is that you can ask the Filer for a source file or class file; even if it is not part of the compilation run it is still on the source path or class path and you get a result. Thus, IF you can read the existing list, and you can extract, per entry, the source or class file that is responsible for it (which in our hypothetical case where you are creating a services file, is trivial: The very entry is itself a fully qualified class name you can ask the Filer to find) you can then query the filer if that resource is still around. If yes, keep it, if not, delete it. Now you can update (instead of regenenerate and replace) your list.

Related

Is there a way to use annotations to build a java class, based on the properties of multiple java classes?

There is a way to use annotations to build a java class, based on the properties of multiple java classes?
I want to create a generic log history table for all operations and entities in a spring data jpa project, for this i was thinking if would be possible to get all properties of my entities at compilation time to generate this generic entity log class.
I don't know so much about annotations, but it is used to generate source files so i believe that isn't a impossible ideia.
Could someone give some direction? If it's possible would be nice to point me a good starting point. Or if there is something already done that match my intent.
Annotations themselves do not generate source files -- they signify pointcuts for other classes to enhance/enrich them, or as a marker interface.
However, you can definately use an annotation scanner to scan files and get all the fields.
Then what is left is generating a class from this.
(and then, compile it). Be aweare that this is a multi-step process, and it may seem a bit clunky: you create a file with name GenericEntity, make sure it's in the proper package (so start it with package my.fun.project, write the imports, and write the java class, all as strings which you send tot he file.
From you scan you have an annotated field / class and you can get the type and name (see the reflections library if necessary), and write that to your file as well. Then close the class properly with a }. Now it should a file which should not give compilation errors when loaded in your IDE.
This GenericEntityGenerator then has to be executed (using a maven plugin, probably) on your source code, probably during the generate-sources phase, after which your generated class will be compiled during the compile phase.... and bob's your uncle now.
In all, a fun project

Automatically Delete Temporary Files using "new" Java File API

After years of coding with the old File API, I'm finally ready to hop onto the whole Path/Paths train. For the most part, this has gone smoothly, however, I'm stumped on this particular aspect: temporary files.
The documentation on java.nio.Files#createTempFile says:
As with the File.createTempFile methods, this method is only part of a temporary-file facility. Where used as a work files, the resulting file may be opened using the DELETE_ON_CLOSE option so that the file is deleted when the appropriate close method is invoked. Alternatively, a shutdown-hook, or the File.deleteOnExit() mechanism may be used to delete the file automatically.
I don't see where the DELETE_ON_CLOSE option is supposed to be specified. Using a shutdown hook is incredibly inconvenient (unless I'm thinking of it wrong). In an effort to avoid using both Path objects and File objects, I am looking for a solution similar to the File.deleteOnExit() for the Path object, but obviously one that doesn't require using Path.toFile().[...].toPath() sort of calling pattern.
What is the correct way to implement "self-destructing" temporary files using the java.nio.Files API?
You set that option when you write, for example:
Path myTempFile = Files.createTempFile(...);
Files.write(myTempFile, ..., StandardOpenOption.DELETE_ON_CLOSE);

Java webapplication - properties file nightmare

I recently started working on a POORLY designed and developed web application.. I am finding that it uses about 300 properties files, and all the properties files are being read somewhat like this:
Properties prop= new Properties();
FileInputStream fisSubsSysten = new FileInputStream("whatever.properties");
prop.load(fisSubsSysten);
That is, it is reading the properties files from current working directory.. Another problem is the developers have chosen to use the above lines multiple times within the same java file. For example if there are 10 methods, each method will have the above code instead of having one method and calling it wherever necessary..
This means, we can NEVER change the location of the properties files, currently they are directly under the websphere profiles directory, isn't this ugly? If I move them somewhere else, and set that location in classpath, it does not work.
I tried changing the above lines like this using Spring IO utils library:
Resource resource = new ClassPathResource("whatever.properties");
Properties prop = PropertiesLoaderUtils.loadProperties(resource);
But this application has over 1000 files, and I am finding it impossible to change each file.. How would you go about refactoring this mess? Is there any easy way around?
Thanks!
In these cases of "refactoring" i use a simple find and replace approach. Notepad++ has a " find in files" feature but there are plenty of similar programs.
Create a class which does the properties loading with a method probably with a name parameter for the property file.
This can be a java singleton or a spring bean.
Search and replace all "new Properties()" lines with an empty line.
Replace all "load..." lines with a reference to your new class/ method. Notepad++ supports regex replacement, so you can use the filename as a parameter.
Once this is done go to eclipse and launch a "cleanup" or "organize imports" and fix some compile errors manually if needed.
This approach is quite straight forward and takes no more than 10min if you are lucky or 1 hour if you are unlucky, f.e. the code formatting is way of and each file looks different.
You can make your replace simpler if you format the project once before with a line length of 300 or more so each java statement is on one line. This makes find and replace a bit easier as you dont have newlines to consider.
I can only agree that I find your project a bit daunting, from your reference.
However, the choice of how to maintain or improve of it is a risk that merely needs to be assessed and prioritised.
Consider building a highrise and subsequently realising the bolts that holds the infrastructure have a design flaw. The prospect of replacing them all is indeed daunting as well, so considerations into how to change them and if they really, really needs to be replaced, few, many or all.
I assume it must be a core system for the company, which somebody built and they have probably left the project (?), and you have consideration about improvement or maintaining them. But again, you must assess whether it really is important to move your property files, or if you can just for instance use symbolic links in your file system. Alternatively, do you really need to move them all or is there just a few that would really benefit from being moved. Can you just mark all places in the code with a marker to-be-fixed-later. I sometimes mark bad classes with deprecation, and promise to fix affected classes but postpone until I have other changes in those classes until finally the deprecated class can be safely removed.
Anyway you should assess your options, leave files, replace all or partials, and provide some estimation of cost and consequences, and ask your manager which course to take.
Just note that always overestimate the solution you don't want to do, as you would be twice as likely to stop for coffee breaks, and a billboard of told-you-so's is a great leverage for decision making :)
On the technology side of your question, regex search and replace is probably the only option. I would normally put configuration files in a place accessible by classpath.
You can try using eclipse search feature. For example if you right click on load() method of the properties class and select References -> Project it will give you all location in your project where that method is used.
Also from there maybe you can attempt a global regex search and replace.

Is it possible to add custom metadata to .class files?

We have used liquibase at our company for a while, and we've had a continuous integration environment set up for the database migrations that would break a job when a patch had an error.
An interesting "feature" of that CI environment is that the breakage had a "likely culprit", because all patches need to have an "author", and the error message shows the author name.
If you don't know what liquibase is, that's ok, its not the point.
The point is: having a person name attached to a error is really good to the software development proccess: problems get addressed way faster.
So I was thinking: Is that possible for Java stacktraces?
Could we possibly had a stacktrace with peoples names along with line numbers like the one below?
java.lang.NullPointerException
at org.hibernate.tuple.AbstractEntityTuplizer.createProxy(AbstractEntityTuplizer.java:372:john)
at org.hibernate.persister.entity.AbstractEntityPersister.createProxy(AbstractEntityPersister.java:3121:mike)
at org.hibernate.event.def.DefaultLoadEventListener.createProxyIfNecessary(DefaultLoadEventListener.java:232:bob)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:173:bob)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:87:bob)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:862:john)
That kind of information would have to be pulled out from a SCM system (like performing "svn blame" for each source file).
Now, forget about trashing the compilation time for a minute: Would that be even possible?
To add metadata to class files like that?
In principle you can add custom information to .class files (there's and attribute section where you can add stuff). You will have to write your own compiler/compiler extension to do so. There is no way to add something to your source code that then will show up in the class file.
You will also have major problems in practice:
The way stack-traces a built/printed is not aware of anything you add to the class file. So if you want this stuff printed like you show above, you have to hack some core JDK classes.
How much detail do you want? The last person who committed any change to a given file? That's not precise enough in practice, unless files are owned by a single developer.
Adding "last-committed-by" information at a finer granularity, say per method, or even worse, per line will quickly bloat your class file (and class files are limited in size to 64K)
As a side note, whether or not blaming people for bugs helps getting bugs fixed faster strongly depends on the culture of the development organization. Make sure you work in one where this helps before you spend a lot of time developing something like this.
Normally such feature can be implemented on top of the version control system. You need to know revision of your file in your version control system, then you can call blame/annotate command to get information on who has changed each individual line. You don't need to store this info into the class file, as long as you can identify revision of each class you deploy (e.g. you only deploy certain tag or label).
If you don't want to go into the version control when investigating stack trace, you could store line annotation info into the class file, e.g. using class post processor during your build that can add a custom annotation at the class level (this is relatively trivial to implement using ASM). Then logger that prints stack trace could read this annotation at runtime, similarly to showing jar versions.
One way to add add custom information to your class files using annotations in the source code. I don't know how you would put that information reliably in the stack trace, but you could create a tool to retrieve it.
As #theglauber correctly pointed out , you can use annotations to add custom metadata. Althougth i am not really sure you if you cant retrieve that information from your database implementing beans and decorating your custom exceptions manager.

Is there a way to get all the classes that implement a certain method?

The title speaks for itself. The language is Java.
Yes, there is. This is however a tedious and expensive work. You need to crawl through all class files and all JAR files with help of ClassLoader#getResources() and a shot of java.io.File and load all classes of it with help of Class#forName() and finally check if the method is there by Class#getMethod().
However, there are 3rd party API's which can take the tedious work from hands, but it is still expensive, because loading a class would cause its static initializers being executed.
A cleaner way is to make use of annotations and annotate the methods in question and then make use of libraries which searches for classes/methods/fields based on the annotations, such as Google Reflections.
On the other hand, if the entire package name or the JAR file name is known beforehand, then the work will be less tedious and expensive (no need to do stuff recursively nor to load the all of the classes of entire classpath).
Update: I remember, I ever wrote sample code to achieve something like that, you can find it here. It's good to start with, you only need to change it a bit to check the method.
No, you can't, in general. If you could get a complete list of available classes you could check each of them using reflection - but you can't ask a classloader for a list of everything that's available. (For instance, it may be fetching classes over HTTP, and may not know all the files available.)
If you knew that you were interested in classes in a jar file, however, you could open the jar file, find all the class files within it and ask the classloader for those classes. It would be somewhat fiddly.
What's the bigger picture here? There may be a better way to approach the problem.
Also, in Eclipse, you can simply ask for this :
Clic on the method, and type Ctrl-T.

Categories

Resources