Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle multiple jars from single source folder

Tags:

java

gradle

jar

As for now we have a project structure with single source folder named src, which contains source code for three modules. What I want to do is:

1) Compile source code. This is easily done with sourceSets definition:

sourceSets {     main {         java {             srcDir 'src'         }     } } 

2) Put compilation results into three jars. I am doing this via three 'jar' type tasks:

I am doing this now via three separate tasks:

  • util.jar

    task utilJar(type: Jar) {     from(sourceSets.main.output) {         include "my/util/package/**"     } } 
  • client.jar

    task clientJar(type: Jar) {     from(sourceSets.main.output) {         include "my/client/package/**"     } } 
  • server.jar

    task serverJar(type: Jar) {     from(sourceSets.main.output) {         include "**"     }     excludes.addAll(utilJar.includes)     excludes.addAll(clientJar.includes) } 

The thing is that server.jar should contain all classes that are not contained within client.jar and util.jar. In ant build script we solve this problem by using difference ant task. How this can be done in gradle (my current approach doesn't work)?

Maybe my approach is completely wrong. Please advice.

P.S. as for now we CAN NOT change the project source code folder structure.

like image 949
vitalidze Avatar asked Nov 15 '13 18:11

vitalidze


People also ask

What is multi Release jar?

A multi-release JAR file allows for a single JAR file to support multiple major versions of Java platform releases. For example, a multi-release JAR file can depend on both the Java 8 and Java 9 major platform releases, where some class files depend on APIs in Java 8 and other class files depend on APIs in Java 9.

Can you have multiple build gradle files?

Yes. You can have multiple build files in one project. The only thing you can't do, of course, is have multiple files named build. gradle in the same folder.

Where does gradle store dependency jars?

Gradle declares dependencies on JAR files inside your project's module_name /libs/ directory (because Gradle reads paths relative to the build. gradle file).


2 Answers

I will post my working solution here as an answer (I've got a hint on gradle's forum).

The scopes in gradle are very strange thing :) I thought that every task definition creates an object of some 'Task' class, which is something like 'JarTask' in this particular case. Then I can access any property of the class from anywhere in my build.gradle script. However, I found the only place where I can see the patterns, which are included in jar file - inside a from block of a task. So my working solution for now is to:

1) Define a project-level collection to contain patterns to be excluded from server.jar

2) Exclude all patterns in from block of serverJar task.

Please see final version below

sourceSets {       main {           java {               srcDir 'src'           }       }   }   // holds classes included into client.jar and util.jar, so they are to be excluded from server.jar ext.serverExcludes = []  // util.jar task utilJar(type: Jar) {       from(sourceSets.main.output) {           include "my/util/package/**"          project.ext.serverExcludes.addAll(includes)     }   }  // client.jar task clientJar(type: Jar) {       from(sourceSets.main.output) {           include "my/client/package/**"         project.ext.serverExcludes.addAll(includes)     }   }  // server.jar task serverJar(type: Jar) {       from(sourceSets.main.output) {           exclude project.ext.serverExcludes     }   } 
like image 171
vitalidze Avatar answered Sep 28 '22 17:09

vitalidze


I think the approach is wrong. I recommend making a project with 3 sub projects.

project - util - server (depends on util) - client (depends on util) 

If for some reason you cannot change the class structure use this kind of build files:

settings.gradle

include 'util', 'client', 'server' 

build.gradle

subprojects {     apply plugin: 'java' }  project(':util') {     sourceSets {         main {             java {                 srcDir '../src'                 include 'util/**'             }         }     } }  project(':server') {     sourceSets {         main {             java {                 srcDir '../src'                 include 'server/**'             }         }     }     dependencies {         compile project(':util')     } }  project(':client') {     sourceSets {         main {             java {                 srcDir '../src'                 include 'client/**'             }         }     }     dependencies {         compile project(':util')     } } 

You still need directories for subprojects but the sources are in one place as you wanted.

When you run gradle assemble you will have 3 jars with separate set of classes. The advantage of this solution is that we make a proper Gradle multi module project with correct dependencies, not just tasks for building jars.

Please read Multi-Project Builds.

like image 38
Grzegorz Żur Avatar answered Sep 28 '22 17:09

Grzegorz Żur