Skip to content

Read annotations directly from the .class files#62

Merged
dscho merged 8 commits intomasterfrom
read-annotations-directly
May 12, 2014
Merged

Read annotations directly from the .class files#62
dscho merged 8 commits intomasterfrom
read-annotations-directly

Conversation

@dscho
Copy link
Contributor

@dscho dscho commented May 10, 2014

This fixes #60.

This commit brings the ByteCodeAnalyzer from imagej-updater into SciJava
common. The idea is not so much to move it here, but to modify it for
use with the annotation indexer.

To this end, the ByteCodeAnalyzer's fields, methods and inner classes
were all restricted as much as possible, and the class itself was made
package-local, to make clear that this class is not meant to be part of
the official API of SciJava common.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added 6 commits May 10, 2014 08:03
The result is a map suitable for use by the annotation indexer.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Instead of loading the classes, we read the annotations directly from the
.class files. This has two advantages over the previous method:

1. We avoid polluting the ClassLoader with loaded classes (which can be
   problematic e.g. when ij1-patcher wants to patch the classes before
   loading them at a later stage).

2. It is no longer necessary for the dependencies of the classes to be
   on the class path (though that is only true for the classes, not for
   the annotations).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
These lines were identified by Eclipse as unneeded.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
As far as the annotation indexer is concerned, we need not parse
interfaces, fields nor methods. So let's skip that part and cut to the
chase.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This is a subtle issue: if an annotation for a given class does not
specify a particular value, the developer obviously intended the default
value to be used. Now, if the default value ever changes, it should be
reflected in the values returned by the annotation index. That implies
that we must not write out unspecified settings into the serialized
annotations, but always infer them at runtime from the annotation class
itself.

Happily, our annotation processor does The Right Thing (but the
EclipseHelper in its current form does not). Keep it that way.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The switch to reading annotations directly from .class files in the
EclipseHelper fixed a subtle bug: default values for annotation
parameters must not be serialized into the annotation index, but instead
be inferred at runtime (in case the default values in the annotation
class itself changed).

Keep this bug fixed by testing for it in the unit tests.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho
Copy link
Contributor Author

dscho commented May 11, 2014

So after all, it looks as if this branch is not only a "nice to have" but actually fixes a subtle bug in the EclipseHelper: it used to serialize annotation values including the default values (when we want to make sure that changes of the default values in the annotation class are picked up unless overridden).

@ctrueden could you give it a good shake (i.e. install it locally and use it to test your favorite SciJava common-based project)?

@ctrueden
Copy link
Member

I tried a brief test in Eclipse:

  • Coupled the SciJava Common 2.18.3-SNAPSHOT to net.imagej:imagej by overriding the version in the POM, and verified Eclipse switched to a project-style build path entry.
  • Ran net.imagej.Main, verified that DefaultReadmeService appeared in the System Information window, and that "Show Readme" did not appear in the Command Finder.
  • Quit ImageJ
  • Changed the ShowReadme menuPath to "Plugins > Readme" and reran ImageJ
  • Verified that "Readme" was present in Plugins and displayed the readme.
  • Quit ImageJ
  • Deleted the menuPath again and reran ImageJ
  • Verified that "Readme" was gone again.

All seems good to me. Anything else you want me to check?

@dscho
Copy link
Contributor Author

dscho commented May 12, 2014

Sorry, I ran out of time and did not do a good job of describing things... :-(

The changes affect only the EclipseHelper, i.e. when you compile things normally, with Maven, nothing will change because the helper won't kick in (except of course for scijava-common.jar itself...). Further, the changes will actually change things because of the bug fix that default values of the annotation classes are supposedly not serialized any longer.

The test I had in mind (and that I will perform before merging) is to move all the target/classes/META-INF/json/ directories out of the way just after compiling the ImageJ projects with Maven. Then I wanted to run the EclipseHelper as main class with all the target/classes/ directories in the class path, and after that compare "before" and "after". Ideally, the files in json/ would not look identical (but probably won't be because the order in which the classes are inspected is most likely different from the way the annotation processor does it). Apart from that, though, they should really be identical (including the order of the fields).

Will keep you posted!

@dscho
Copy link
Contributor Author

dscho commented May 12, 2014

Okay, I did not try this with all of ImageJ, but I tested it with imagej-plugins-commands and with imagej-plugins-tools. And I can verify now that apart from the order in which the annotations were written to disk, the annotation index is identical.

I verified this by

  1. building with mvn clean install,
  2. moving target/classes/META-INF/json into the top-level directory,
  3. calling java -classpath target/classes:$HOME/.m2/repository/org/scijava/scijava-common/2.18.3-SNAPSHOT/scijava-common-2.18.3-SNAPSHOT.jar org.scijava.annotations.EclipseHelper,
  4. editing the original org.scijava.plugin.Plugin as well as the new one in vi, first calling :%s/}{/}^M{/g (where ^M really was written as Ctrl+J Ctrl+M) and then calling :%!sort, essentially splitting the annotation index into individual lines per annotated class and sorting them,
  5. diff -u target/classes/META-INF/json/org.scijava.plugin.Plugin json/org.scijava.plugin.Plugin

The end result is that the annotation index written out by the annotation processor and the one written out by the EclipseHelper are identical (module serialization order, of course). There is only one more thing I'd like to fix: the EclipseHelper claims to have problems opening a .zip file (which it should not be a problem, but I would like to shut up the helper in that case).

We recently switched to a more thorough indexing when the EclipseHelper
is called as a main class, including inspecting the Class-Path entry of
the manifest of .jar files. However, said entries might not refer to
existing files, in which case we need to ignore them.

While at it, this fixes the bug that .jar files on the class path would
not have been accessed properly if their paths contained spaces.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit that referenced this pull request May 12, 2014
Read annotations directly from the .class files
@dscho dscho merged commit 4543593 into master May 12, 2014
@dscho dscho deleted the read-annotations-directly branch May 12, 2014 20:07
@dscho
Copy link
Contributor Author

dscho commented May 12, 2014

Now I am happy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Avoid loading classes when building the annotation index

2 participants