निर्भरता के साथ एक जार बनाने के लिए ग्रैडल का उपयोग करना


122

मेरे पास एक मल्टीप्रोजेक्ट बिल्ड है और मैंने सबप्रोजेक्ट में से एक में एक मोटा जार बनाने के लिए एक कार्य दिया। मैंने कुकबुक में वर्णित एक के समान कार्य बनाया ।

jar {
  from configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  manifest { attributes 'Main-Class': 'com.benmccann.gradle.test.WebServer' }
}

इसे चलाने से निम्नलिखित त्रुटि होती है:

कारण: आप एक कॉन्फ़िगरेशन नहीं बदल सकते हैं जो अनसुलझे स्थिति में नहीं है!

मुझे यकीन नहीं है कि इस त्रुटि का क्या मतलब है। मैंने यह बात ग्रैगल JIRA पर भी रिपोर्ट की है कि यह एक बग है

जवाबों:


195

अपडेट: नए ग्रेडल संस्करणों (4+) में compileक्वालीफायर को नए apiऔर implementationकॉन्फ़िगरेशन के पक्ष में हटा दिया जाता है । यदि आप इनका उपयोग करते हैं, तो निम्नलिखित को आपके लिए काम करना चाहिए:

// Include dependent libraries in archive.
mainClassName = "com.company.application.Main"

jar {
  manifest { 
    attributes "Main-Class": "$mainClassName"
  }  

  from {
    configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
  }
}

पुराने ग्रेडल संस्करणों के लिए, या यदि आप अभी भी अपनी निर्भरता के लिए "संकलन" क्वालीफायर का उपयोग करते हैं, तो यह काम करना चाहिए:

// Include dependent libraries in archive.
mainClassName = "com.company.application.Main"

jar {
  manifest { 
    attributes "Main-Class": "$mainClassName"
  }  

  from {
    configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  }
}

ध्यान दें कि mainClassNameपहले दिखाई देना चाहिए jar {


4
मुझे अपनी परियोजना के लिए इसे विन्यासों में परिवर्तित करना था। क्रमबद्ध करना। क्योंकि मेरे पास रनटाइम निर्भरता भी है।
वेक्टर्सपर्स

2
मुझे def mainClassNameकोड काम करने के लिए जोड़ना था ... मैं प्राप्त कर रहा था रूट परियोजना के लिए अज्ञात संपत्ति 'mainClassName' सेट नहीं कर सका
'12:45

1
आप फ़ाइल नाम टकराव को कैसे संभालते हैं? अलग-अलग JAR में एक ही रास्ते पर फाइलें ओवरराइट की जाएंगी।
wst

3
दुर्भाग्य से यह कोई और काम नहीं करता है। अब मैं implementationपदावनत के बजाय ४.१० और नए विन्यास का उपयोग करता हूं compile। उपरोक्त कोड निर्भरता के बिना मुझे एक छोटा जार बनाता है। जब मैं इसे बदल देता हूं ( from { configurations.implementation.collect {...} }), एक त्रुटि होती है जो कहती है कि कॉन्फ़िगरेशन 'कार्यान्वयन' को सीधे हल करने की अनुमति नहीं है
बस्तियन वोइगट

1
@BastianVoigt configurations.compileClasspathसभी implementations को ठीक कर देगा , लेकिन apiनिर्भरता को छोड़ देगा। समाधान का एक और जवाब में यहां मिला runtimeClasspath। इसमें apiआश्रित भी शामिल हैं।
rekire

64

@ फेलिक्स का जवाब मुझे लगभग वहाँ ले आया। मेरे पास दो मुद्दे थे:

  1. ग्रैड 1.5 के साथ, मेनिफेस्ट टैग को वसाजर कार्य के अंदर मान्यता नहीं दी गई थी, इसलिए मेन-क्लास विशेषता को सीधे सेट नहीं किया जा सकता था
  2. जार में बाहरी मेटा-इन फ़ाइलों की परस्पर विरोधी थी।

निम्न सेटअप यह हल करता है

jar {
  manifest {
    attributes(
      'Main-Class': 'my.project.main',
    )
  }
}

task fatJar(type: Jar) {
  manifest.from jar.manifest
  classifier = 'all'
  from {
    configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
  } {
    exclude "META-INF/*.SF"
    exclude "META-INF/*.DSA"
    exclude "META-INF/*.RSA"
  }
  with jar
}

इसे मानक असेंबल करने या टास्क बनाने के लिए जोड़ने के लिए:

artifacts {
    archives fatJar
}

संपादित करें: @mjaggard के लिए धन्यवाद: ग्रेडल के हाल के संस्करणों में, में बदलाव configurations.runtimeकरेंconfigurations.runtimeClasspath


3
इससे मुझे एक समस्या भी ठीक हो गई जहां मेरे एक निर्भरता जार पर हस्ताक्षर किए गए थे। हस्ताक्षर फाइलें मेरे जार के मेटा-इन में डाल दी गईं, लेकिन हस्ताक्षर अब सामग्री से मेल नहीं खाते।
फ्लेविन

2
के लिए विशेष धन्यवाद artifacts: वास्तव में मैं क्या देख रहा था।
एलेक्सा

जब आप gradle fatJarरनटाइम निर्भरताएँ चलाते हैं , तो उन्हें संकलित नहीं किया जाता है, इसलिए उन्हें कॉपी नहीं किया जा सकता है।
मेजरगार्ड

64

यदि आप चाहते हैं कि jarकार्य सामान्य रूप से व्यवहार करे और एक अतिरिक्त fatJarकार्य भी करे, तो निम्नलिखित का उपयोग करें:

task fatJar(type: Jar) {
    classifier = 'all'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

महत्वपूर्ण हिस्सा है with jar। इसके बिना, इस परियोजना के वर्ग शामिल नहीं हैं।


1
निम्न समस्या भी देखें यदि आप हस्ताक्षरित जार का उपयोग कर रहे हैं और हस्ताक्षर के साथ एक समस्या में शामिल हैं: stackoverflow.com/questions/999489/…
पीटर एन। स्टाइनमेटज़

6
यह काम नहीं करता। इस समाधान के साथ मेनिफेस्ट फ़ाइल खाली है।
जोनास

4
मेरे 2 सेंट: नाम बदलने की तुलना में एक क्लासिफायरियर सेट करना बेहतर है। BaseName = project.name + '-all' के बजाय क्लासिफ़ायर = 'सभी' लगाएं। इस तरह आप मावेन / नेक्सस नीतियों के अनुपालन में विरूपण साक्ष्य नाम रखते हैं।
taciosd

1
जोड़ें group "build"और यह कार्य buildसमूह में होगा (अन्य कार्यों के साथ, अर्थात jarकार्य।
MAGx2

1
मुझे with jarकीवर्ड पर किसी भी तरह का कोई दस्तावेज़ नहीं मिल रहा है , यह वास्तव में क्या करता है?
फिलिप हेमलमेयर

9

यह मेरे लिए ठीक काम करता है।

मेरा मुख्य वर्ग:

package com.curso.online.gradle;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

public class Main {

    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Main.class);
        logger.debug("Starting demo");

        String s = "Some Value";

        if (!StringUtils.isEmpty(s)) {
            System.out.println("Welcome ");
        }

        logger.debug("End of demo");
    }

}

और यह मेरी फ़ाइल build.gradle की सामग्री है:

apply plugin: 'java'

apply plugin: 'eclipse'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
    testCompile group: 'junit', name: 'junit', version: '4.+'
    compile  'org.apache.commons:commons-lang3:3.0'
    compile  'log4j:log4j:1.2.16'
}

task fatJar(type: Jar) {
    manifest {
        attributes 'Main-Class': 'com.curso.online.gradle.Main'
    }
    baseName = project.name + '-all'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

और मैं अपने कंसोल में निम्नलिखित लिखता हूं:

java -jar ProyectoEclipseTest-all.jar

और आउटपुट बहुत अच्छा है:

log4j:WARN No appenders could be found for logger (com.curso.online.gradle.Main)
.
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more in
fo.
Welcome

6

एक मुख्य निष्पादन योग्य वर्ग के साथ एक मोटी JAR उत्पन्न करने के लिए, हस्ताक्षरित JAR के साथ समस्याओं से बचने के लिए, मुझे सुझाव है कि ग्रेड-वन-जार प्लगइन । एक साधारण प्लगइन जो वन-जार प्रोजेक्ट का उपयोग करता है ।

प्रयोग करने में आसान:

apply plugin: 'gradle-one-jar'

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.github.rholder:gradle-one-jar:1.0.4'
    }
}

task myjar(type: OneJar) {
    mainClass = 'com.benmccann.gradle.test.WebServer'
}

5

सरल सुस्ती

jar {
    manifest {
        attributes 'Main-Class': 'cova2.Main'
    } 
    doFirst {
        from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
    }
}

5

@बेन का जवाब मेरे लिए लगभग काम करता है, सिवाय इसके कि मेरी निर्भरता बहुत बड़ी है और मुझे निम्नलिखित त्रुटि मिली

Execution failed for task ':jar'.
> archive contains more than 65535 entries.

  To build this archive, please enable the zip64 extension.

इस समस्या को ठीक करने के लिए, मुझे निम्नलिखित कोड का उपयोग करना होगा

mainClassName = "com.company.application.Main"

jar {
  manifest { 
    attributes "Main-Class": "$mainClassName"
  }  
  zip64 = true
  from {
    configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  }
}

1

उन लोगों के लिए जिन्हें परियोजना से एक से अधिक जार बनाने की जरूरत है।

ढ़ाल में एक समारोह बनाएँ:

void jarFactory(Jar jarTask, jarName, mainClass) {
    jarTask.doFirst {
        println 'Build jar ' + jarTask.name + + ' started'
    }

    jarTask.manifest {
        attributes(
                'Main-Class':  mainClass
        )
    }
    jarTask.classifier = 'all'
    jarTask.baseName = jarName
    jarTask.from {
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
    {
        exclude "META-INF/*.SF"
        exclude "META-INF/*.DSA"
        exclude "META-INF/*.RSA"
    }
    jarTask.with jar 
    jarTask.doFirst {
        println 'Build jar ' + jarTask.name + ' ended'
    }
}

फिर कॉल करो:

task makeMyJar(type: Jar) {
    jarFactory(it, 'MyJar', 'org.company.MainClass')
}

ढाल 5 पर काम करता है।

जार पर रखा जाएगा ./build/libs


0

मैं shadowJarप्लगइन द्वारा कार्य का उपयोग करता हूं. com.github.jengelman.gradle.plugins:shadow:5.2.0

उपयोग रन रन ./gradlew app::shadowJar फ़ाइल पर होगाMyProject/app/build/libs/shadow.jar

शीर्ष स्तर की build.gradleफाइल:

 apply plugin: 'kotlin'

buildscript {
    ext.kotlin_version = '1.3.61'

    repositories {
        mavenLocal()
        mavenCentral()
        jcenter()
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
    }
}

एप्लिकेशन मॉड्यूल स्तर build.gradleफ़ाइल

apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'

sourceCompatibility = 1.8

kapt {
    generateStubs = true
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation "org.seleniumhq.selenium:selenium-java:4.0.0-alpha-4"
    shadow "org.seleniumhq.selenium:selenium-java:4.0.0-alpha-4"

    implementation project(":module_remote")
    shadow project(":module_remote")
}

jar {
    exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
    manifest {
        attributes(
                'Main-Class': 'com.github.kolyall.TheApplication',
                'Class-Path': configurations.compile.files.collect { "lib/$it.name" }.join(' ')
        )
    }
}

shadowJar {
    baseName = 'shadow'
    classifier = ''
    archiveVersion = ''
    mainClassName = 'com.github.kolyall.TheApplication'

    mergeServiceFiles()
}


0

ग्रैडल 6.3, जावा लाइब्रेरी। "जार टास्क" से कोड "ग्रेड बिल्ड " कार्य चलाने पर निर्भरता को "बिल्ड / लिबास / xyz.jar" में जोड़ता है ।

plugins {
    id 'java-library'
}

jar {
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

-1

यदि आप चींटी के लिए उपयोग किए जाते हैं तो आप ग्रैडल के साथ भी यही कोशिश कर सकते हैं:

task bundlemyjava{
    ant.jar(destfile: "build/cookmyjar.jar"){
        fileset(dir:"path to your source", includes:'**/*.class,*.class', excludes:'if any')
        } 
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.