Eclipse plugin did not configure default output directory to "build"?

Hi there,

I have a very simple Java project with Eclipse plugin applied. However when I run “gradle eclipse” the Eclipse’s project build output goes into “bin” instead of the “build” folder. Shouldn’t this be consistent so user doesn’t have to manually change this?

Here is my build.gradle content: apply plugin: ‘java’ apply plugin: ‘eclipse’ repositories { mavenCentral() } dependencies {

compile group: ‘org.slf4j’, name: ‘slf4j-api’, version: ‘1.7.1’

testCompile group: ‘org.hamcrest’, name: ‘hamcrest-library’, version: ‘1.3’

testCompile group: ‘junit’, name: ‘junit-dep’, version: ‘4.10’ }

You shouldn’t change this. It won’t help and will only cause problems.

Hum… I don’t get it, so we will have “bin” from Ecilpse, and “build” from command line. Why?

1 Like

Both use different compilers and have their own incremental build logic. You don’t want A to overwrite or delete B’s files without B knowing. It will only lead to inconsistent build results.

Hum… having two output folders is annoying and hard to track which one is up to date.

I don’t mean to to be picky, but the Maven command line and their “m2e” eclipse plugin integrate seemlessly and they both write to target folder.

Another thing I see the difference is that “m2e” have a context menu that allow you to “update project” to re-sync from the pom.xml. It would be nice gradle have this feature too, so user doesn’t have to re-run “gradle eclipse” whenever they added a new dependency outside of the IDE.

It’s just my opionion and feedback. I hope it helps.

1 Like

Can you name a concrete problem with having two output folders? I think it’s just a good practice. In the end, the Gradle build should be the “master” telling you if your build is ok or not, and hence you shouldn’t mingle the two. Anyway, it’s trivial to reconfigure this to your liking.

If you want deeper Eclipse integration, check out the Eclipse Gradle Integration.

Hi Peter, Thank you for answering my questions.

I can try list few things about having two output folder that’s user unfriendly to me.

  1. The default “bin” directory is not ideal to use as a folder for generated class files. Many project use “bin” to store executable scripts that they add into source control. Default output here means harder to clean, or you need filter to diff which one is generate vs which one you actually want.

We sure can change the Eclipse’s “bin” to some where else, but that’s the original point of this post, why not default to more user friendly output folder?

  1. With two folder output, now we need to add extra entry into ignore file to source control so to ignore eclipse output folder.

  2. With two folders, now “gradle clean” is not clean because it won’t delete the bin generated files. If we must use two separate folder, I rather it be under “build/eclipse”. Seems more manageable.

  3. For project that has script to load “build/classes” during development as classpath, now they also need

to add “bin”, but then they would need to know which one has the latest compiled classes or else they are staled.

  1. I usually develop on IDE, and let gradle run in CI. Of course I do command line build too, but hardly while I am still editing files with Eclipse together. So separating two class output folder doesn’t make sense to me.

All these comes because there two output generated folders to deal with. Obviously I have no knowledge of how gradle compiler vs Eclipse compiler work, but it just seems hard to manage.

Again, I dont’ mean to be picky or rude. I just want to give you feedback.

2 Likes

ad 1. ‘bin’ is the Eclipse default, which is honored by Gradle.

ad 2. Trivial.

ad 3. I can’t see any reason why Gradle should clean the files generated by Eclipse. This should be left to Eclipse itself. And if you really want this, it’s trivial to add - a single line of configuring the ‘clean’ task.

ad 4. Both Gradle and Eclipse will always have the latest class files (if you configure them correctly). No need for the script to use both output directories. If you want the script to use Gradle’s build output, make it executable via a Gradle task that depends on ‘classes’.

ad 5. You won’t notice any drawbacks, and you’ll get more stable builds. I’ve more than once seen incorrect build results when sharing output folders between the build tool and Eclipse, both with Gradle and Maven.

Thanks for the feedback. I firmly believe that Gradle’s default is the right one in general, for the reasons outlined earlier. And if it’s not the right one for you, reconfiguring the Eclipse output directory is very easy. That’s one of the strengths of Gradle. We can’t make the defaults right for everyone, but we can make them configurable.

1 Like

Perhaps you are right Peter. I haven’t used gradle enough to get the feel yet, but like to give it try. I use maven quiet a bit, and so far, this separate output folder seems to be different in comparison with m2e.

Thanks for the info.

Hi. Sorry for reviving an old thread but I think I do have a nice concrete case where managing two class output folders causes trouble. Picture this:

  • A project generates CXF web service clients and the generation process also relies on generating Model classes based on XMLBeans like so:
// Custom task to generate CXF Java classes from WSDL.
 task wsdl2java(type: JavaExec) {
    ext {
   wsdlFile = 'src/main/resources/ath/btrans/xath.wsdl'
   outputDir = project.ext.generatedSrcDir
  }
    inputs.file file(wsdlFile)
  outputs.dir outputDir
    main = 'org.apache.cxf.tools.wsdlto.WSDLToJava'
  classpath = configurations.provided
    args '-p', 'https.my.web.service.package'
  args '-d', outputDir
  args '-client'
  args '-verbose'
  args '-validate'
  args '-wsdlLocation', 'classpath:my/wsdl/file.wsdl'
  args wsdlFile
 }
   task xmlbean << {
  ant.taskdef(name: 'xmlbean', classname: 'org.apache.xmlbeans.impl.tool.XMLBean', classpath: configurations.compile.asPath)
  ant.xmlbean(srconly: true, srcgendir: project.ext.generatedSrcDir.absolutePath, classgendir: "$buildDir/classes/main") {
   fileset(dir: 'src/main/resources/my/xml/schemas/dir', includes: '**/*.xsd **/*.xsdconfig')
  }
 }

The ‘xmlbean’ task avobe will place this peculiar class structure folder inside ‘$buildDir/classes/main’ containing an assortment of ‘.xsb’ files and a class named ‘TypeSystemHolder’, all of them generated by the latter task.

During unit test time, Eclipse will know that it can find any necessary class files inside the ‘bin’ folder. That even includes the model classes generated at , say, ‘my.xml.models’ defined inside an XMLBeans ‘.xsdconfig’ file because the source code was correctly placed inside ‘build/generated-src’ with this instruction:

project.ext.generatedSrcDir = file("$buildDir/generated-src")

What Eclipse doesn’t know is that XMLBeans also generated metadata classes which are necessary to construct instances of my model classes, which are only located at ‘$buildDir/classes/main’ and not in ‘bin’, which results in a runtime exception.

How could I deal with this issue in a sensible manner? Thanks!

You can put generated classes into a separate directory and then configure the Eclipse plugin to put that on the Eclipse class path.

I’m also having problems with the separated folders. I startup my webapp from CL using Gradle and develop in Eclipse.

My webapp startups with the JRebel agent. The JRebel Gradle plugin generates a rebel.xml which classes point to build/classes/main

Now when I change a class in Eclipse it’s compiled to bin folder which in this case Rebel is not looking at.

Im using Maven for years in which Eclipse write to same folder als Maven CL actions and never had any problems.

I understand that other projects might problems with same folders so it should be (easily) configurable.

The burning question now is what should I do in my case to solve it?

Cheers, Marcel

It is easily reconfigurable. A quick glance at the EclipseClasspath docs will tell you how.

Yes :slight_smile: was just looking at it

defaultOutputDir = file(‘build/classes/main’)

Is there some existing property already pointing to that folder?

‘sourceSets.main.output.classesDir’

Ah thx, I have so much to learn in Gradle…

Note that I now encountered a problem with Eclipse and Gradle having the same output folder. The problem is related to different behavior between Gradle and Maven.

Maven outputs both compiled Java classes and resources to the same output folder, where Gradle has separated this in build/classes and build/resources.

As in earlier discussion I changed the output folder for eclipse to: sourceSets.main.output.classesDir This also means both compiled Java classes and resources go to the output classesDir.

The generated JRebel rebel.xml watched both the build/classes and build/resources file which now contains double files. E.g. persistence.xml lives in both build/classes and build/resources which will give a error when starting the container.

Maybe simplest approach would be to change output.resourcesDir and output these files to output classesDir as well. This would give the exact same behavior as Maven does. However my feeling is I’m trying to much to configure Gradle to behave like Maven… and therefore I have to deviate to much from default Gradle settins (which I don’t like). That’s what I liked in Maven setup, that I use the default and it worked without problems.

Any suggestions? I will also start the same discussion on JRebel forum as it is off course also related how and to what the Rebel plugin is looking, and maybe they have some good advise as well.

Would it be possible to specify the default output folders for java and resources separately?

‘sourceSets.main.output.classesDir’ vs. ‘sourceSets.main.output.resourcesDir’. Another approach might be to use different output directories in Gradle and Eclipse (i.e. the default), and supply both with a ‘rebel.xml’.

Yes I was thinking of that as well. But in case I supply both e.g build/resources and bin/resources to rebel this means that config files will be mltiple times on the classpath. And this will cause again a problem with persistence.xml which will have a conflict again (it wants to create twice the persistence unit; which will result in fatal error from container).