Fast development with Gradle in Eclipse. Is it possible?


(Marcos Antonio Pereira Silva) #1

I’m working on two projects: project A (a library) and project B (an application that uses the library). The two projects are independent projects. They’re not a multibuild project. When someday I finish my development a jar will be generated for project A and the project B jar will have a dependency on that jar.

Before using Gradle, in Eclipse, I just had to configura the build path for project B and add project A as a dependent project. So it means that Eclipse doesn’t have to generate a jar for project A every time I need to run project B. This is really fast development.

But now, using Gradle, everytime I have to generate the jar for project A in order to test project B. I think there’s no way (correct me if I’m wrong) to do the build path thing with Gradle. I think that this really slows down development.

Does Gradle (and Buildship) have a solution to this, to speed up development as Eclipse alone?

Thank you in advance.

Marcos


(François Guillot) #2

You can declare a multi-project build and specifically set the subprojects location (ie not following the conventional way “rootDir/subProjectName”)
Then you can declare your compile dependency on the other project, and buildship / eclipse plug-in should pick it up


(Marcos Antonio Pereira Silva) #3

But remember that, as I said, at the end I will need to artifacts: A.jar and B.jar. Will I still be able to do this declaring a multi-project build or the multi-project build will generate just one artifact, as if the two projects were just one?

Really? Are you really sure about this (I mean, when I run project A in Eclipse, the jar for project B will not need to be created for the execution of project A to work)? If this is already tested, that’s what I want.


(François Guillot) #4

Yes, each build will declare its artifact. You can leave them like that, or do whatever fancy thing you want with them.

At least Eclipse plug-in can generate .classpath files with dependency to another project, if I recall correctly. (as if the .classpath file was generated manually with such dependency)
I’m unsure if buildship can do it or not though.


(Marcos Antonio Pereira Silva) #5

I think that this issue is of paramount importance, not only for me, but for all Gradle users. I would just like to have a final word about it. Gradle has nice features, like dependency management and other things, but if I have to (in the development stage) generate a library jar every time just to test it in another application (and also generate the application jar, which is not necessary in this case), I think that Gradle usefulness is questionable here (to say the least) when we talk about development performance. IDEs alone have a much better support for this. In my opinion there should be a way to adapt Gradle (and the Buildship plugin) for this.


(François Guillot) #6

Well, let me give you an example then.

  • Project A
    build.gradle

    apply plugin: 'java’
    apply plugin: ‘eclipse’

    dependencies {
    compile project(’:B’)
    }

settings.gradle

include 'B'
project(":B").projectDir = new File('../B')
  • Project B
    located at …/B, from project A

If you import both project A and B into eclipse, and run gradle eclipse in project A, you get a .classpath file in A, with
a classpathentry that references project B directly (not the library that is eventually produced by B)

Isn’t it what you want ?


(Marcos Antonio Pereira Silva) #7

I’ll give a try to this and see if it solves the problem. I’ll report any results when I reach a conclusion.


(René Groeschke) #8

Hey some more thoughts about this.

If your library and your application is so closely coupled, then it might make sense to have them in one multiproject build.

In earlier gradle versions there we run the test task for example against the output of the classes tasks and not against the generated jar. The issue is, that it does not strictly behave as in a jared environment. we saw couple of issues, one I remember is problems with jpa.

One other option to get this working in your IDE is to manually tweak the .classpath file using the eclipse.classpath.file.whenMerged hook in your applications build.gradle file to replace the binary dependency with a module dependency.


(Marcos Antonio Pereira Silva) #9

I’m afraid that this setup can’t be made in this case. The library jar that I’m working on is some kind of ‘common’ or ‘base’ library that has to be used for all applications that I develop, not only this particular application. Was that the case (only this application) I think that there wouldn’t be any problem to have a multiproject build, as suggested by you. I really can’t make a lot of unrelated applications make part of a big multibuild project just to share a library.

Thank you for the tip. I’ll see if this is necessary when I give a try to Francois’ suggestion. Any other suggestions would be appreciated.


(Marcos Antonio Pereira Silva) #10

One last doubt before trying this solution: is this a multiproject build? Will project A need to be located in a directory named ‘master’? I’m asking this because I see a settings.gradle file and from what I know from Gradle this file is only needed in multiproject builds.


(François Guillot) #11

Yes, it’s a multi project Gradle Build.
But that should not be a problem at all. Each build in a multi project build can behave independently.
They happen to also be part of a larger, multi-project build, that may do other things.

Not at all. I suppose ‘master’ comes from the fact that you’re thinking about Git ?
You can still deal with them with two different git repositories.


(Marcos Antonio Pereira Silva) #12

Francois, just to make sure: by Project A in your example you mean the application project, right? And by Project B you mean the library project, right? So the settings.gradle file will be located in the application project. Because as I said it is the applications that will depend on the library, not the other way around.

Could you confirm this for me please?


(François Guillot) #13

Yup, here A is the application
And B the library, since I wrote a compilation dependency on B, in project A.


(Marcos Antonio Pereira Silva) #14

As I said, I would report my findings after trying it out. And the result is that unfortunatelly it didn’t work as expected. I see that everytime I make a change in the library project and run the application project, the library project jar is generated (I see it is generated in the ‘libs’ dir).

I’ll show some of my files below for you to see if there’s something wrong or if I missed something. The ‘desenvolvimento’ project is the library project and the ‘teste’ project is the application project (sorry because the names are in Portuguese, but I think that the names doesn’t matter in this case).

build.gradle (library)

apply plugin: 'java'

sourceCompatibility = 1.8

repositories
{
	mavenCentral()
}

dependencies
{
	compile 'org.hibernate:hibernate-entitymanager:5.0.0.Final'
	compile 'org.hibernate:hibernate-validator:5.2.1.Final'
	compile 'org.slf4j:slf4j-api:1.7.12'
}

build.gradle (application)

apply plugin: 'application'
apply plugin: 'eclipse'

sourceCompatibility = 1.8
mainClassName = 'br.desenvolvimento.teste.iu.Teste'

repositories
{
	mavenCentral()
}

dependencies
{
	compile 'org.hibernate:hibernate-entitymanager:5.0.0.Final'
	compile 'org.hibernate:hibernate-validator:5.2.1.Final'
	compile 'org.slf4j:slf4j-api:1.7.12'
	compile project(':desenvolvimento')

	runtime 'javax.el:javax.el-api:3.0.0'
	runtime 'ch.qos.logback:logback-classic:1.1.3'
	runtime 'org.postgresql:postgresql:9.4-1201-jdbc41'
	
	testCompile 'org.testng:testng:6.9.6'
}

test
{
	useTestNG
	{
		suites 'src/test/resources/padrao.xml',
			'src/test/resources/personalizado.xml'
	}
}

jar
{
	manifest
	{
		attributes 'Specification-Title': 'Sistema',
                   'Description': 'Sistema Teste'
	}
}

settings.gradle (application)

include 'desenvolvimento'
project(':desenvolvimento').projectDir = new File('../../desenvolvimento/desenvolvimento')

entry generated in the .classpath file after running the eclipse task in the application project:

<classpathentry kind="src" path="/desenvolvimento"/>

Is there anything left to be done to achieve what I want?


(François Guillot) #15

Well, isn’t it what you want?
You can develop your application, and see instantaneously the changes you make in the library, since it’s a project dependency in your Eclipse .classpath file from your application project.
Of course, the library classpath file must as well contains source entries (e.g. It can be generated by the eclipse gradle plug-in as well) if you want that your modification on the library project can be seen in the application project.

Gradle is “just” used here to generate the .classpath files of your projects.
Of course it generates as well libraries for both projects, but that’s not relevant for you right now, during development.

Could you explain again what is wrong with this approach, regarding your initial request ?


(Marcos Antonio Pereira Silva) #16

This is very nice. I really wanted this as I didn’t have it before when the projects were independent projects. But the real point, the real issue is not this (explained below).

My initial request was this:

Before using Gradle, I was using only Eclipse to build and run my application. I didn’t use any other build tool.

So, when I made some change to a source file in the library project and saved the file to disk, the Eclipse Java Builder kicks in and compiles only that file. Then when I run my application project in Eclipse (the application project depends on the library project), Eclipse runs my application very fast because it doesn’t generate the library jar file (the thing that Gradle is doing here). Am I being clear here? Eclipse just do all the magic assembling the classpath and classload thing in memory and runs my application as if I was executing it outside it, running it from the application jar file using the library jar file. Do you get what I mean?

I want to achive the same thing with Gradle while I’m in development stage. Later, when I want (when I’m about to go to production), I want to instruct Gradle to finally generate the library jar file and application jar file.

This feature is a very nice feature of Eclipse. It saves us a lot of time in development. I think that any build tool can’t have less than any IDE. If I can’t accomplish this with Gradle, my only option will be to come back to raw Eclipse do develop my library and application. All those milliseconds and seconds generating a jar file without necessity every time I make a little change and want to see it will make me waste a lot of time. It is definitely a no-no.


(François Guillot) #17

So you want to completely get rid of your IDE, and mimic the Eclipse builder behavior, using just Gradle on the command line?

The closest thing I can think of is [gradle continuous build] (https://docs.gradle.org/current/userguide/continuous_build.html)


(Marcos Antonio Pereira Silva) #18

Maybe my English is really very bad. Nowhere I said that I want to get rid of Eclipse and use Gradle on the command line simulating Eclipse behavior.

I want to keep developing in Eclipse using Gradle, but I want Gradle to behave like Eclipse regarding the feature I mentioned. I think that I didn’t explain it so bad in my last post.

If someone understood what I want I just want you to tell me: no, you can’t do this with Gradle or yes, you can do this with Gradle, here’s how. Simple like this.


(Etienne Studer) #19

No, you cannot do this with Gradle. I think given your description, the best option is to go back to raw Eclipse development.


(Marcos Antonio Pereira Silva) #20

Thanks for the direct answer.

Does Gradle (or Buildship) have any plan to support it in the future as a request for enhancement?