Implementing a ClassInstrumentingCompiler: how to get the generated class files

I'm writing a plugin that needs to modify the class files that were just generated by javac.

I've browsed the elusive OpenAPI docs and found about ClassInstrumentingCompiler. My login is mostly in place now, and only one question remains: how do I get a reference (VirtualFile, URL, path, whatever) to the class files?

7 comments
Comment actions Permalink

"My login is mostly in place now"


Read "My logic is mostly in place now"...

0
Comment actions Permalink

Reading a bit more it looks like ClassPostProcessingCompiler sounds more like what I need:

A tag interface indicating that the file processing compiler will actually take java classes and perform some activities on them.

But I still need to figure out how to find the classes to be processed.

0
Comment actions Permalink

For the record, I've found a way. Not pretty, but it works:

 classes = new LinkedList();

        for (Module module : context.getCompileScope().getAffectedModules())
        {
            VirtualFile outputDirectory = context.getModuleOutputDirectory(module);
            classes.addAll(getAllChildren(outputDirectory, "class"));
        }

        return classes.toArray(new VirtualFile[classes.size()]);
    }

    private List getAllChildren(VirtualFile rootDir, String extension)
    {
        assert rootDir.isDirectory() : "rootDir isn't a directory";

        List children = new LinkedList();

        for (VirtualFile entry : rootDir.getChildren())
        {
            if (entry.isDirectory())
                children.addAll(getAllChildren(entry, extension));
            else if (extension.equals(entry.getExtension()))
                children.add(entry);
        }

        return children;
    }]]>

0
Comment actions Permalink

Yep, the approach is ok.
You might also need to check output path for tests
context.getModuleOutputDirectoryForTests().
Please note that there can be a situation when several modules have the same output path. To prevent extra directory traversals,
it's better to make a collection of unique output paths and then process them.
Also your plugin might want to consider dependencies between modules to process output paths in the corresponding order (this
depends on the functionality of the plugin).

Does the plugin perform ok when collecting classes in such a way?

--
Best regards,
Eugene Zhuravlev
Software Developer
JetBrains Inc.
http://www.jetbrains.com
"Develop with pleasure!"


"Marcus Brito" <mbrito@gmail.com> wrote in message news:18280830.1119460112161.JavaMail.itn@is.intellij.net...

For the record, I've found a way. Not pretty, but it works:

>

    private VirtualFile[] getClassFiles(CompileContext context)
>    {
>        List classes = new LinkedList();
>
>        for (Module module : context.getCompileScope().getAffectedModules())
>        {
>            VirtualFile outputDirectory = context.getModuleOutputDirectory(module);
>            classes.addAll(getAllChildren(outputDirectory, "class"));
>        }
>
>        return classes.toArray(new VirtualFile[classes.size()]);
>    }
>
>    private List getAllChildren(VirtualFile rootDir, String extension)
>    {
>        assert rootDir.isDirectory() : "rootDir isn't a directory";
>
>        List children = new LinkedList();
>
>        for (VirtualFile entry : rootDir.getChildren())
>        {
>            if (entry.isDirectory())
>                children.addAll(getAllChildren(entry, extension));
>            else if (extension.equals(entry.getExtension()))
>                children.add(entry);
>        }
>
>        return children;
>    }]]>



0
Comment actions Permalink

Eugene Zhuravlev (JetBrains) wrote:

Yep, the approach is ok.


In a ClassInstrumentingCompiler, is there a way to get a list of just the classes that
have been compiled in the current run? I think this type of compiler should have a way of
determining which classes actually need to be instrumented. I looked at the compiler
interfaces some time ago and could not find a way. Is that possible?

Sascha

0
Comment actions Permalink

In a ClassInstrumentingCompiler, is there a way to
get a list of just the classes that
have been compiled in the current run? I think this
type of compiler should have a way of
determining which classes actually need to be
instrumented. I looked at the compiler
interfaces some time ago and could not find a way. Is
that possible?


Actually, the getProcessingItems() method of your plugin must return all items that could be processed in this run. IDEA will later filter this list and call process() only on those that actually need to be processed.

And yeah, the plugin is performing reasonably well with this approach -- but mind you, I haven't tested it on anything with more than a 1500 classes.

0
Comment actions Permalink

Marcus Brito wrote:

Actually, the getProcessingItems() method of your plugin must return all items that could be processed in this run. IDEA will later filter this list and call process() only on those that actually need to be processed.


Aha, I see. Should have looked more closely then. I see there's even real documentation
for that ;)

Thanks for the info.

Sascha

0

Please sign in to leave a comment.