Eclipse generated files should be put in the same place as the Gradle generated files

The Eclipse/Gradle plugin by default uses the “bin” directory. This is the Eclipse defaults from the very old days when it was IBM’s C/C++ development tool. In addition, several sites that I work with use the “bin” directory to store the sources for supporting scripts.

Eclipse & Gradle are both (generally) smart enough to determine when the files they are working with have been modified by an outside party, or need updating. As a result, it would be helpful to both (and the project I am currently working on) if their generated artifacts could be in the same place with the same layout.

My recollection is that this was discussed earlier, but one of the problems is the eclipse will “partially compile” a class that contains errors. This is useful within eclipse when running unit tests for example. However, these partially compiled class files can be a real pain as gradle javaCompile can succeed even though there are compile errors. In other words a .class file generated by the partial compile by eclipse hides the fact that gradle really needs to recompile that java file. Can lead to some really hard to figure out bugs and means that you have to do a ‘gradle clean’ often to make sure your compile really did succeed.

What the default eclipse output directory should be called is I guess a separate question, but it shouldn’t be the same as gradle’s output directory.

Philip

I’ve run into the partially compiled class file a couple of times. The only times I’ve hit it has been when Unit tests have been run in Eclipse. While I don’t think this is an issue, I can see where others might prefer to have a different output folder for Eclipse. Q: Would it be possible to set up an API to redirect the generated artifacts on a per-source basis?

Right now, you can only set one generic output directory for Eclipse, which would then hold all Test & Main classes. This would probably be useful for a number of scenarios.

The only times I’ve hit it has been when Unit tests have been run in Eclipse.

There are other issues. For example, when Eclipse compiles into the Gradle output directory it will overwrite the class files but not the metadata that Gradle keeps for each (compile) task, which can lead to issues on the next Gradle compilation.

Q: Would it be possible to set up an API to redirect the generated artifacts on a per-source basis?

I can’t see how this could work. Eclipse doesn’t have a concept of source sets. It will compile the whole project at once, hence there can only be one output directory per project.

In the future, the STS Gradle plugin might support additional ways to map Gradle builds to Eclipse. For example, it could offer to turn each source set into its own Eclipse project. So far, we’ve more often heard the opposite wish: Have just one Eclipse project for the whole Gradle build.

I have run into the same issue and I am aware of the problem of partially compiled class files. But on the other hand, having different output folders can be a much greater pain.

For example in the case when you did a gradle build, resources are copied to the output folder. When you do open resource (str-shift-r) in eclipse after the gradle build you will get both the resource file in the build directory as well as the resource file in the source directory. This can lead to very annoying situations, where you loose your latest changes.

Would it be possible to add a flag to the gradle eclipse target, which will configure the same output directories for eclipse as for gradle.

For the mean time we created a hack which configures the output folders for the java directory

Map<String, String> pathMappings = [:];

SourceSetContainer sourceSets = project.sourceSets;

sourceSets.each { SourceSet sourceSet ->

String relativeJavaOutputDirectory = project.relativePath(sourceSet.output.classesDir);

String relativeResourceOutputDirectory = project.relativePath(sourceSet.output.resourcesDir);

sourceSet.java.getSrcDirTrees().each { DirectoryTree sourceDirectory ->

String relativeSrcPath = project.relativePath(sourceDirectory.dir.absolutePath);

pathMappings[relativeSrcPath] = relativeJavaOutputDirectory;

}

sourceSet.resources.getSrcDirTrees().each { DirectoryTree resourceDirectory ->

String relativeResourcePath = project.relativePath(resourceDirectory.dir.absolutePath);

pathMappings[relativeResourcePath] = relativeResourceOutputDirectory;

}

}

project.eclipse.classpath.file {

whenMerged { classpath ->

classpath.entries.findAll { entry ->

return entry.kind == ‘src’;

}.each { entry ->

if(pathMappings.containsKey(entry.path)) {

entry.output = pathMappings[entry.path];

}

}

}

}

After looking at a place where this flag could be integrated I would assume the best place would be on Line 74 in org.gradle.plugins.ide.eclipse.model.internal.SourceFoldersCreator. I could also help and provide a patch with the changes needed.

As an alternative approach to avoid the duplicate resources problem, we configured a bit of magic to modify the eclipse project file to ignore the build directory. That way you can have Eclipse and Gradle spitting out their output into separate folders without getting the artifacts in the build directory appearing when you do an ‘open resource’

Something like:

project.eclipse.project.file.withXml { provider ->
            ignoreResourcesFromDirectories(provider, ["build"])
}
  // And the method looks something like:
def ignoreResourcesFromDirectories(provider, directories) {
        def filter = provider.asNode()
          .appendNode("filteredResources")
          .appendNode("filter")
        // the following value needs to be unique
        filter.appendNode("id", String.valueOf(System.currentTimeMillis()))
        filter.appendNode("name")
        filter.appendNode("type", "26")
        def matcher = filter.appendNode("matcher")
        matcher.appendNode("id", "org.eclipse.ui.ide.orFilterMatcher")
        def arguments = matcher.appendNode("arguments")
        directories.each {
            def dirMatcher = arguments.appendNode("matcher")
            dirMatcher.appendNode("id", "org.eclipse.ui.ide.multiFilter")
            dirMatcher.appendNode("arguments", "1.0-projectRelativePath-matches-false-false-${it}")
        }
    }

I might not be understanding your issue correctly, but I believe you can mark the “build” folder, in Eclipse, as “derived”, in which case its contents will not show up when you do Ctrl+Shift+R. It would be great if the Gradle Eclipse plugin would do this automatically.

Thanks,

Jamie

I’m pretty sure marking it as derived only works until you do a gradle clean and the build directory gets deleted and recreated, losing it’s ‘derived’ status.