How to include a Zip file inside a ShadowJar during Gradle build - jar

I am providing below what I have at the moment.
In the example below, the Jar task produces a Jar with a Zip file ( artifact from another project ) inside it.
But, My ultimate aim is to produce an uber jar that will self contain it's dependencies. I came by Shadow plugin and it seems a clean solution.
I tried to tell my ShadowJar task to include the Zip file - but it doesn't work. See commented out ShadowJar section.
So, what I have now is to create the shadow jar but then producing another jar that includes the contents of shadow jar and the zip. I can see that this path is full of gotchas (I had to enforce the Manifest again) ....
Ideally I would think that there is an way to include a artifact from different configuration in Shadow Jar and it is my limitation of Gradle knowledge that is failing here.
buildscript {
repositories { jcenter() }
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:1.1.1'
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'com.github.johnrengelman.shadow'
project.version = rootProject.ext.deployerVersion
// In this section you declare where to find the dependencies of your project
repositories {
// Use 'maven central' for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
mavenCentral()
}
configurations {
pkg
}
// In this section you declare the dependencies for your production and test code
dependencies {
compile project(':Concenter.Foundation')
pkg project(path: ':Concenter.Platform', configuration: 'pkg')
// Declare the dependency for your favourite test framework you want to use in your tests.
// TestNG is also supported by the Gradle Test task. Just change the
// testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
// 'test.useTestNG()' to your build script.
testCompile 'junit:junit:4.11'
}
jar {
dependsOn ':Concenter.Platform:distZip'
manifest {
attributes(
'Main-Class': 'aqilco.concenter.deployer.Deployer',
)
}
from configurations.pkg
}
/*
shadowJar {
dependsOn ':Concenter.Platform:distZip'
manifest {
attributes(
'Main-Class': 'aqilco.concenter.deployer.Deployer',
)
}
from configurations.pkg
}
*/
task pkg(type: Jar) {
dependsOn ':Concenter.Platform:distZip'
dependsOn 'shadowJar'
archiveName = jar.baseName + "-" + jar.version + "-pkg." + jar.extension
from zipTree(shadowJar.archivePath)
from configurations.pkg
manifest {
attributes(
'Main-Class': 'aqilco.concenter.deployer.Deployer',
)
}
}

Related

Severely truncated attribute while compiling JavaFX Undertow Websockets project for Android with jfxmobile-plugin

I am having an issue while compiling my JavaFX project for Android.
The project includes a bunch of libraries, Undertow Websockets is among them. I downloaded all required jars to my lib directory and included them into dependencies / compile files block of build.gradle file.
I was able to solve other issues with jar-files dependencies (mostly DuplicateFileException), but one Undertow library - undertow-core-1.3.14.Final.jar gives me a little bit of a headache.
When I add it to compile file block of gradle.build file ‘gradlew android’ gives me an error message:
What went wrong: Execution failed for task ‘:createMainDexList’.
Exception in thread “main” com.android.dx.cf.iface.ParseException:
severely truncated attribute at
com.android.dx.cf.direct.StdAttributeFactory.throwSeverelyTruncated(StdAttributeFactory.java:736)
at
com.android.dx.cf.direct.StdAttributeFactory.runtimeVisibleParameterAnnotations(StdAttributeFactory.java:661)
at
com.android.dx.cf.direct.StdAttributeFactory.parse0(StdAttributeFactory.java:162)
at
com.android.dx.cf.direct.AttributeFactory.parse(AttributeFactory.java:96)
at
com.android.dx.cf.direct.AttributeListParser.parse(AttributeListParser.java:141)
at
com.android.dx.cf.direct.AttributeListParser.parseIfNecessary(AttributeListParser.java:115)
at
com.android.dx.cf.direct.AttributeListParser.getEndOffset(AttributeListParser.java:96)
at
com.android.dx.cf.direct.MemberListParser.parse(MemberListParser.java:213)
at
com.android.dx.cf.direct.MemberListParser.parseIfNecessary(MemberListParser.java:108)
at
com.android.dx.cf.direct.MethodListParser.getList(MethodListParser.java:54)
at
com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:542)
at
com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
at
com.android.dx.cf.direct.DirectClassFile.parseToEndIfNecessary(DirectClassFile.java:397)
at
com.android.dx.cf.direct.DirectClassFile.getAttributes(DirectClassFile.java:311)
at
com.android.multidex.MainDexListBuilder.hasRuntimeVisibleAnnotation(MainDexListBuilder.java:191)
at
com.android.multidex.MainDexListBuilder.keepAnnotated(MainDexListBuilder.java:167)
at
com.android.multidex.MainDexListBuilder.(MainDexListBuilder.java:121)
at
com.android.multidex.MainDexListBuilder.main(MainDexListBuilder.java:91)
at
com.android.multidex.ClassReferenceListBuilder.main(ClassReferenceListBuilder.java:58)
…while parsing RuntimeVisibleParameterAnnotations attribute at offset 0009c07 > …while parsing attributes[3]
…while parsing methods[1]
…while parsing io/undertow/client/http/HttpResponseParser$$generated.class
Below is my build.gradle file contents:
task wrapper(type: Wrapper) {
gradleVersion = '2.10'
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.0.7'
}
}
apply plugin: 'org.javafxports.jfxmobile'
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
jcenter()
}
mainClassName = 'com.simlayserstudio.SimlayserStudio'
jfxmobile {
android {
manifest = 'src/android/AndroidManifest.xml'
// compileSdkVersion = 16 // version 4.2.1
compileSdkVersion = 23 // version 6
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/INDEX.LIST'
exclude 'META-INF/services/io.undertow.attribute.ExchangeAttributeBuilder'
exclude 'META-INF/services/io.undertow.predicate.PredicateBuilder'
exclude 'META-INF/services/io.undertow.server.handlers.builder.HandlerBuilder'
//exclude 'META-INF/services/javax.annotation.processing.Processor'
}
}
ios {
infoPList = file('src/ios/Default-Info.plist')
}
}
dependencies {
compile ('commons-codec:commons-codec:1.10',
'commons-io:commons-io:2.4',
'commons-lang:commons-lang:2.6',
// 'io.undertow:undertow-servlet:1.3.14.Final' // Duplicate zip entry [allclasses.jar:javax/annotation/Generated.class
)
compile files(
'/lib/jboss-logging-3.2.1.Final.jar', //ok wtih exclude 'META-INF/INDEX.LIST'
// '/lib/undertow-core-1.3.14.Final.jar', // ERROR com.android.dx.cf.iface.ParseException: severely truncated attribute
'/lib/undertow-servlet-1.3.14.Final.jar', // ok wtih exclude ExchangeAttributeBuilder, PredicateBuilder, HandlerBuilder
'/lib/undertow-websockets-jsr-1.3.14.Final.jar', //ok with exclude 'META-INF/INDEX.LIST'
'/lib/xnio-api-3.3.4.Final.jar', //ok with exclude 'META-INF/INDEX.LIST'
'/lib/xnio-nio-3.3.4.Final.jar', //ok with exclude 'META-INF/INDEX.LIST'
'/lib/apache-commons.jar', //ok
'/lib/com.thoughtworks.xstream.jar', //ok
'/lib/javax.websocket-api-1.0.jar', //ok
'/lib/log4j-1.2.17.jar', //ok
'/lib/xmlpull-xpp3-1.1.4c.jar', //ok
)
}
Did anybody manage generating apk with Undertow Websockets, or encounter similar issues with 3-rd party libraries?
Any help would be much appreciated.
Thank you!
I've been able to reproduce the same error you've posted, just by using this dependencies and running ./gradlew android:
dependencies {
compile ('io.undertow:undertow-servlet:1.3.19.Final') {
exclude group: 'org.jboss.spec.javax.annotation'
}
compile ('io.undertow:undertow-core:1.3.19.Final') {
exclude group: 'org.jboss.spec.javax.annotation'
}
compile ('io.undertow:undertow-websockets-jsr:1.3.19.Final') {
exclude group: 'org.jboss.spec.javax.annotation'
}
}
So in order to find out about the possible issue, I've downloaded the io.undertow` sources from here, added the required dependencies (maybe I'm not using the exact versions):
dependencies {
compile 'org.jboss.logging:jboss-logging-annotations:2.0.1.Final'
compile 'org.jboss.classfilewriter:jboss-classfilewriter:1.0.4.Final'
compile 'org.eclipse.jetty.alpn:alpn-api:1.0.0'
compile 'org.jboss.xnio:xnio-nio:3.3.4.Final'
compile 'org.jboss.xnio:xnio-api:3.3.4.Final'
compile 'org.jboss.logging:jboss-logging:3.2.1.Final'
compile 'org.jboss.spec.javax.websocket:jboss-websocket-api_1.1_spec:1.1.0.Final'
compile 'org.jboss.spec.javax.servlet:jboss-servlet-api_3.1_spec:1.0.0.Final'
}
And to avoid duplicated classes from javax.annotation, I've downloaded the sources of org.jboss.spec.javax.annotation:jboss-annotations-api_1.1_spec from here, and removed these three classes: Generated.java, PostConstruct.java and PreDestroy.java.
I was able to run ./gradlew android successfully, but I haven't tested it.
In case you still have issues building it or later running it on the device, maybe you can consider other alternatives for websockets like the Tyrus project.
This is a project were we have used it successfully.

gradle replace class file into modifying the MANIFEST

Is possible to replace class files into a jar keeping the MANIFEST file with Gradle?
I need to do it to apply a patch from the vendor that give me only the class files.
Id tried this:
task applayPatch(type: Jar) {
destinationDir = new File("${rootProject.projectDir}/libs/tool")
archiveName = "myfile.jar"
from(zipTree("${rootProject.projectDir}/libs/myfile.jar")) {
exclude "com/tool/frontoffice/partymanager/partysearch/DynamicPartySearchWidget.class"
}
from ("${rootProject.projectDir}/point-release/FFO-33758/com/fineos/frontoffice/partymanager/partysearch") {
include "MyClass.class"
}
}
but didn't work giving me a jar with an empty MANIFEST and only the class MyClass.class
Try using a task of type Zip instead of Jar to avoid having Gradle generate a new manifest for you.
task patchedJar(type: Zip, dependsOn: jar) {
extension 'jar'
from(zipTree(jar.archivePath)) {
exclude '**/MyClass.class'
}
from("patches/dir") {
include 'com/foo/package/MyClass.class'
}
}
Take note that by default this puts the resulting jar in build/distributions. Simply change the destinationDir property if you would like the output somewhere else.

Spring Boot Thymeleaf fragment subdirectory view error with jar

My Spring Boot app works fine in Eclipse and from gradle run in command line. However fails to load fragment from a sub directory when launched from java -jar....
Using default Spring Boot and Thymeleaf settings and gradle.
Folder structure
src/main/resources/
---templates/
---homepages/
---homepage
---head
Tried explicit view resolver for Thymeleaf. No luck.
fragment causing problem.
<head th:include="/homepages/head"></head>
error when launched from jar
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri May 16 18:54:44 EDT 2014
There was an unexpected error (type=Internal Server Error, status=500).
Error resolving template "/homepages/head", template might not exist or might not be accessible by any of the configured Template Resolvers (homepages/homepage:5)
Using default setting for Spring Boot.
buildscript {
repositories {
maven { url "http://repo.spring.io/libs-snapshot" }
mavenLocal()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.0.2.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
jar {
baseName = 'base-app'
version = '0.1.0'
}
repositories {
mavenCentral()
maven { url "http://repo.spring.io/libs-snapshot" }
maven { url "https://repository.jboss.org/nexus/content/repositories/releases" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web") {
}
compile("org.springframework.boot:spring-boot-starter-security")
compile("org.thymeleaf:thymeleaf-spring4")
testCompile("junit:junit")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-jdbc")
compile("org.postgresql:postgresql:9.2-1004-jdbc4")
compile("org.hibernate:hibernate-validator")
compile('org.hibernate:hibernate-entitymanager:4.0.1.Final')
compile("org.springframework:spring-tx")
compile("org.springframework.boot:spring-boot-starter-actuator")
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
Template paths normally do not start with "/". Try removing that from your include path.

How To Specify main class when using fatjar plugin in gradle.build

I am interested in building a single jar containing all the module dependencies and external jars in a single executable jar file which I will be able to run with java -jar myApp.jar.
I have module A which is dependent on module B.
Currently I'm using gradle, and my build.gradlescript looks like this:
apply plugin: 'fatjar'
description = "A_Project"
dependencies {
compile project(':B_Project')
compile "com.someExternalDependency::3.0"
}
When I build it through gradle command: clean build fatjar a fat jar 'A.jar' is created as expected.
But running it with as I written above results in:
no main manifest attribute, in A.jar
How can I modify my build.gradle file and specify the main class, or the manifest?
I have figured it out myself:
I've used uberjar Gradle task.
now my build.gradle file looks like this:
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'com.organization.project.package.mainClassName'
version = '1.0'
task uberjar(type: Jar) {
from files(sourceSets.main.output.classesDir)
from {configurations.compile.collect {zipTree(it)}} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
manifest {
attributes 'Main-Class': 'com.organization.project.package.mainClassName'
}
}
dependencies {
compile project(':B_Project')
compile "com.someExternalDependency::3.0"
}
and now I i use it with the command:
clean build uberjar
and it builds one nice runnable jar :)
To get it working using fatjar, I added a manifest section in fatJar task:
task fatJar(type: Jar) {
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
manifest {
attributes 'Implementation-Title': 'Gradle Quickstart', 'Implementation-Version': version
attributes 'Main-Class': 'com.organization.project.package.mainClassName'
}
}

gradle: adding jar to web-inf

i have created a gradle build and added java, scala, war, jetty code and its all working fine.
apply plugin: 'java'
apply plugin: 'scala'
apply plugin: 'war'
apply plugin: 'jetty'
List compileTime = [
"javax.servlet:servlet-api:2.4#jar",
"org.scalatra:scalatra_2.8.0:2.0.0.M2#jar",
"org.mortbay.jetty:jetty:6.1.22#jar",
"com.mongodb.casbah:casbah_2.8.0:2.0.2#jar",
"org.scala-lang:scala-library:2.8.1#jar"
]
List runTime = [
"org.scalatra:scalatra_2.8.0:2.0.0.M2#jar",
"com.mongodb.casbah:casbah_2.8.0:2.0.2#jar",
"org.scala-lang:scala-library:2.8.1#jar"
]
// "org.mortbay.jetty:servlet-api:2.5-20081211#jar",
repositories {
mavenCentral()
mavenRepo urls: ["http://scala-tools.org/repo-releases","http://mirrors.ibiblio.org/pub/mirrors/maven2","http://repo1.maven.org/maven2","https://oss.sonatype.org/content/repositories/snapshots","https://oss.sonatype.org/content/repositories/releases"]
}
dependencies {
scalaTools 'org.scala-lang:scala-compiler:2.8.1'
scalaTools 'org.scala-lang:scala-library:2.8.1'
compile compileTime
runtime runTime
testCompile "junit:junit:3.8.2"
}
task myTask (type: War) {
println configurations.runtime.collect
println classpath()
}
war {
// from 'main/webapp'
webInf { from 'src/main/webapp/WEB-INF' }
// classpath classpath() /
classpath configurations.runtime
webXml = file('src/main/webapp/WEB-INF/web.xml')
}
I like to
1) Add only the necessary jars. in the war, in the above code i am getting Jetty and servlet jars in my war. !
For dependencies that should not go into the War, use the "providedCompile" or "providedRuntime" scope.
Some remarks on your build script:
You don't have to put dependencies on the "runtime" class path that are already on the "compile" class path. Gradle does this for you. Same for "providedCompile" and "providedRuntime".
Do you really have compile dependencies on servlet API and Jetty? (Could be true, just wondering.)
Your usage of "mavenRepo urls: ..." is wrong. You need to list the repos one by one. For more information, see 32.5.1 Maven repositories in the Gradle user guide.
Not sure why you use "#jar" everywhere. This effectively disables transitive dependency management. Maybe a result of 3. ?
Your "war { ... }" configuration is the default and can be omitted. See 23.6 War in the user guide.

Resources