Gradle ShadowJar output contains obfuscated and non-obfuscated classes - gradle

in my simple gradle build I would like to use ShadowJar and ProGuard together. I have found examples where the output of the shadowJar task is the input of the proguard one, which works fine, however in my case I would prefer first creating the small obfuscated jar first where I nicely specify the library dependencies and get proguard to focus only on my code and then I would like to pass that to the shadowjar plugin for fatjar packaging.
My setup is the following:
task obfuscate(type: proguard.gradle.ProGuardTask) {
injars jar
outjars "build/libs/foo-${project.version}-pg.jar"
...
}
shadowJar {
from obfuscate
configurations = [project.configurations.embed]
}
shadowJar.dependsOn obfuscate
And my problem is that the shadowJar output contains all the libraries unobfuscated (fine), my obfuscated code (fine) and my unobfuscated code. So somehow the original classes sneak in and I am not seeing how is that happening. I am not able to specify to shadowJar to package the dependencies and the proguard output jar together.
Do you see where is the problem in my approach?

Try this, works for me:
task shadowJar2( type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar ) {
baseName = jar.baseName
from obfuscate
configurations = [project.configurations.embed]
classifier = 'shadow'
//version =
}
The problem is that the default shadowJar task takes your 'main' sourceset in addition to the obfuscated + library jars. By defining your own custom 'shadowJar2' task, you are explicitly defining your sources, which in this case is only jars ('obfuscate' + 'embed') and not a sourceset.

Related

how to call a gradle task which inside a jar with a parameter

I want to run a gradle task embedded in a jar, the jar which I am not producing myself. Is this even possible? I could also paste in the gradle task into my local build.gradle and run it but all the code would still need to reference the jar to actually run the main class.
You can add the jar which contains the Task you want to use in your buildscript classpath, using buildscript block. This way, you will be able to import and use this Task class in your build script. The buildscript block is generally used to add external Gradle Plugin jars into the script classpath, so that they can be applied, but you can also reference jars that provide no plugin implementation but only Task implementation classes.
Example
Assuming that:
the coordinates of the external jar is org.company.gradle:custom-tasks:0.1
the Task implementation class is org.company.gradle.tasks.MyTask
the Task implementation has a configurable property message
Then you can implement your build script as follows:
buildscript {
repositories {
// define repositories
}
dependencies {
// make the external jar available in the build script classpath
classpath "org.company.gradle:custom-tasks:0.1"
}
}
// use the Task
task 'myTask'(type: org.company.gradle.tasks.MyTask) {
message = "custom message"
}

Sequencing dependencies of multiple Gradle plugin tasks

Please note: Although I specifically mention two Gradle plugins here, this is 100% a question about understanding task dependencies in Gradle, and does not require any knowledge of the individual plugins (I think)!
I have a project that will use two Gradle plugins:
The Gradle Shadow plugin, which will produce a self-contained "fat jar" (basically a large jar with all my classes plus the classes of all my transitive dependencies, which then allows me to just run java -jar myapp.jar without having to manage the jar's external classpath, etc.). This will produce a fat jar at build/libs/myapp.jar; and
The Gradle Launch4J plugin, which uses Launch4J under the hood to convert a jar into a native executable (EXE, etc.). Obviously the fat jar has to be created prior to the Launch4J tasks run, otherwise they'll have nothing to wrap inside of an EXE!
Here's my build.gradle:
import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer
plugins {
id 'groovy'
id 'application'
id 'maven-publish'
id 'com.github.johnrengelman.shadow' version '1.2.3'
id 'edu.sc.seis.launch4j' version '2.3.0'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
group = 'hotmeatballsoup'
mainClassName = 'com.me.myapp.Driver'
repositories {
mavenCentral()
jcenter()
}
dependencies {
compile(
'org.codehaus.groovy:groovy-all:2.4.7'
,'org.slf4j:slf4j-api:1.7.24'
,'org.slf4j:slf4j-simple:1.7.24'
)
}
manifest {
attributes 'Main-Class': mainClassName
}
jar {
manifest {
attributes 'Main-Class': mainClassName
}
baseName = 'zimbus'
}
shadowJar {
transform(ServiceFileTransformer) {
exclude 'META-INF/*.DSA'
exclude 'META-INF/*.RSA'
exclude 'LICENSE*'
}
transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer) {
resource = 'reference.conf'
}
classifier = ''
}
publishing {
publications {
shadow(MavenPublication) {
from components.shadow
artifactId = 'zimbus'
}
}
}
launch4j {
outfile = 'zimbus.exe'
mainClassName = 'com.me.myapp.Driver'
icon = 'zimbus.ico'
jar = 'build/libs/gradle-launch4j-example.jar'
}
At the command-line I run:
./gradlew clean build shadowJar createAllExecutables
The intention here is that I want the fat jar created first (invoked when shadowJar runs) and then for Launch4J to kick in (which is invoked when createAllExecutables runs). But when I run this I get the following exception:
:createExe FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':createExe'.
> Launch4J finished with non-zero exit value 1
launch4j: Application jar doesn't exist.
I'm pretty sure the createAllExecutables task is firing before the shadowJar task, and thus having nothing (no fat jar) to bundle up inside an EXE.
Can someone confirm my suspicion and help me define the dependsOn declaration that will order my tasks correctly? Or if the tasks are executing in the correct order, maybe offer any ideas as to what is causing the error?
Once you write
createAllExecutables.dependsOn shadowJar
you'll define the dependency between createAllExecutables task and shadowJar, which means every time Gradle decide to invoke createAllExecutables (e.g. because you pass that to the command line, or other task will depend on it) shadowJar will also be added to the task graph. So in that case when you invoke gradle createAllExecutables the shadowJar will be also executed.
But you can also write
createAllExecutables.mustRunAfter shadowJar
In that case, you won't introduce any dependency relation between tasks, but you will instrument Gradle about anticipated order for those two tasks. In that case, once you invoke gradle createAllExecutables the shadowJar won't be executed.
I think the dependsOn relation is more applicable in your case, since in order to create executables you need to have fat jar already, so it's a depend on relation, not must run after.

How to remove a class from the classpath after Gradle build

I have a jar that I need to include in my dependencies...
compile files('WebContent/WEB-INF/lib/wls-api.jar')
There's a class inside that jar that is causing trouble that I want to not be on the classpath when I run my app after a gradle build.
How do I get rid of that class after doing a gradle build?
it's a bit trickier than it looks like at first blink; because you will modify the original input!
You should create a configuration for the your modified artifact (this is a proof of concept build.gradle snipplet):
apply plugin: 'java'
task filteredJar(type:Jar){
// you may use a remote artifact by configuring a separate configuration for it and using a jar from:
// configurations.theConfig.resolvedConfiguration.resolvedArtifacts
from zipTree('a.jar')
archiveName 'xx.jar'
// use standard Copy/Sync like filters here, for the example i used
include '**/Tool.class'
}
configurations {
z1
}
artifacts {
z1 filteredJar
}
dependencies {
compile project(path: getPath(), configuration: 'z1')
}
or..alternatively, and might be more preferably:
put this magic into some separate project which will repackage this jar into a usebale one.

How to include the guava libraries to my output jar?

I have the following dependencies in my build.gradle:
dependencies {
compile 'com.google.guava:guava:18.0'
}
It works during compile time and the output jar is generated for my source code (which uses classes like com.google.common.collect.Maps from the guava libraries).
I have a dex task which converts the output jar into a dex file:
task dex(dependsOn: jar, type:Exec) {
project.dexDir.mkdirs()
commandLine 'dx', '--dex', '--no-strict', '--output=' + buildDir +'/dex/' + project.name + '.jar', jar.archivePath
}
The problem is that the output jar doesn't have the guava dependencies, so when it's converted to dex, pushed to an android device and run there, I am getting java.lang.ClassNotFoundException: Didn't find class com.google.common.collect.Maps
Is there a way to get the guava dependencies to be included in the output jar for the javaCompile task that generates the output jar from my other source code? Thank you very much in advance!
This is usually called a "jar with dependencies" or sometimes, a "fat" jar. This solution is probably what you need:

Gradle : Generating sources from WSDL & XSD and adding it to main classpath for compilation

I am failry new to gradle and have a multiproject gradle build to which want to add a WSDL2Java related tasks to one of the project.
I have coded the necessary tasks to generate,compile,package the generated stubs into a jar and add it to the classpath.
Now , i want to perform these tasks before the java compilation is started.
Below is how i coded the new tasks
task genClasses(type: JavaExec) {
//Run WSDL2Java and generate java source files.
}
task compileClasses(dependsOn:'genClasses'){
//Use ant.javac or add type:JavaCompile in task defination as shown below
// task compileClasses(dependsOn:'genClasses',type:JavaCompile)
}
task packageClasses(dependsOn:'compileClasses',type:Jar){
//package my jar
}
task createStubs(dependsOn: 'packageClasses'){
//add created jar to the classpath
}
compileJava.dependsOn createStubs
The build fails with exception and shows below message
Circular dependency between tasks. Cycle includes [task ':projectx:genWsdlClasses', task ':projectx:classes'].
I figured out that the compileClasses tasks somehow is causing this circular dependency, but not sure how to get rid of it?
Are there any other better or idiomatic ways to perform this source generation, compilation of generated source,packaging and adding it to the main sourceset classpath before the main source gets build?
I use the Jaxb-Plugin available here. My Gradle build file looks like this:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'no.entitas.gradle.jaxb:gradle-jaxb-plugin:2.0'
}
}
dependencies {
jaxb 'com.sun.xml.bind:jaxb-xjc:2.2.5-1'
jaxb 'com.sun.xml.bind:jaxb-impl:2.2.5-1'
}
generateSchemaSource.destinationPackage = "my.custom.package"
I believe that this will create the jaxb classes that you want. Does that help?
Use the plugin "no.nils.wsdl2java"
https://plugins.gradle.org/plugin/no.nils.wsdl2java
The plugin takes care of hooking it in to the build and clean tasks.

Resources