Bagaimana saya bisa membuat JAR yang dapat dieksekusi dengan dependensi menggunakan Maven?


2398

Saya ingin mengemas proyek saya dalam satu JAR yang dapat dieksekusi untuk distribusi.

Bagaimana saya bisa membuat paket proyek Maven semua JAR ketergantungan ke output JAR saya?


14
Tolong jelaskan tujuan plugin dependensi mana yang Anda maksud. Saya tahu tidak ada tujuan yang melakukan apa yang diminta pertanyaan asli: untuk meletakkan semua dependensi baik A) di dalam toples penulis melalui pengemasan ulang, atau B) membuat toples yang dapat dieksekusi yang memiliki yang lain di kelas berkelas MANIFEST.MF
Matthew McCullough

2
Anda mungkin menemukan rationaljava.com/2015/02/… yang
Dan


Jawaban:


2361
<build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>fully.qualified.MainClass</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </plugin>
  </plugins>
</build>

dan Anda menjalankannya

mvn clean compile assembly:single

Kompilasi tujuan harus ditambahkan sebelum perakitan: tunggal atau kode proyek Anda sendiri tidak termasuk.

Lihat lebih detail di komentar.


Biasanya tujuan ini terkait dengan fase pembangunan untuk dijalankan secara otomatis. Ini memastikan JAR dibangun saat menjalankan mvn installatau melakukan penyebaran / rilis.

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>fully.qualified.MainClass</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id> <!-- this is used for inheritance merges -->
      <phase>package</phase> <!-- bind to the packaging phase -->
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

22
Terima kasih @IAdapter. Perhatikan bahwa Anda harus selalu melakukan kompilasi sebelumnya karena hanya akan meletakkan apa pun yang ada di "target / kelas" di JAR. Ini akan memastikan bahwa JAR menyertakan perubahan apa pun yang baru-baru ini Anda lakukan pada kode sumber. Jadi, Anda harus melakukan sesuatu seperti: mvn clean compile assembly:single.
Michael

10
Saya telah mengedit pertanyaan untuk menyertakan fase mengikat. Saya menghapus tujuan perakitan yang sudah usang, karena tidak ada yang perlu tahu tentang itu.
Duncan Jones

2
Saya melihat bahwa ini tidak menambahkan toples ke toples uber, sebaliknya ini hanya menambahkan semua file kelas ke toples.
pitchblack408

170
Kiat: Anda juga dapat menambahkan elemen <appendAssemblyId>false</appendAssemblyId>ke dalam configurationuntuk menghindari akhiran "-jar-dengan-dependensi" yang mengganggu dalam nama
maxivis

6
lupakan compiledan kamu kacau.
prayagupd

350

Anda dapat menggunakan dependensi-plugin untuk menghasilkan semua dependensi di direktori terpisah sebelum fase paket dan kemudian memasukkannya ke classpath manifes:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>theMainClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

Atau gunakan ${project.build.directory}/classes/libsebagai OutputDirectory untuk mengintegrasikan semua file jar ke jar utama, tetapi kemudian Anda harus menambahkan kode classloading khusus untuk memuat stoples.


3
+1 Luar Biasa. Alasan saya menggunakan maven-dependency-plugin alih-alih maven-assembly-plugin adalah saya juga menggunakan buildnumber-maven-plugin, dan dengan cara ini saya dapat menyimpan nomor versi di manifes masing-masing toples secara terpisah.
PapaFreud

17
Saya suka solusi Anda. Saya menggunakan ${project.build.directory}/classes/libsebagai outputDirectorymemiliki satu .jar utama dengan semua dependensi dalam, tapi - Cara menambahkan kode classloading kustom untuk memuat guci ini? Saya perlu membuat pelaksanaan pekerjaan seperti: java -jar main-jar-with-deps.jar. Apakah ini mungkin?
marioosh

3
@ André Aronsen, saya menggunakan solusi ini untuk menambahkan dependensi dalam folder lib di dalam toples, tetapi saya selalu mendapat kelas tidak ditemukan pengecualian, dapatkah Anda memberi saran bagaimana cara memperbaikinya.
Mahmoud Saleh

11
Memberi +1 kepada Anda !! Sepertinya maven assembly plugin 'jar-with-dependencies' tidak benar-benar berfungsi dengan baik. Saya kehilangan beberapa entri dari META-INF / spring.schemas dalam tabung yang dihasilkan. Jadi saya membatalkan toples-dengan-dependensi dan menggunakan solusi Anda di atas. Sempurna terima kasih !!!
Derek

9
Untuk orang lain yang mengalami masalah ini, Anda harus memasukkan folder lib dalam direktori yang sama dengan toples Anda ke mana pun Anda memindahkan toples tersebut.
Sparticles

224

Saya membuat blog tentang beberapa cara berbeda untuk melakukan ini.

Lihat Jar yang Dapat Dieksekusi dengan Apache Maven (WordPress)

atau executable-jar-with-maven-example (GitHub)

Catatan

Pro dan kontra itu disediakan oleh Stephan .


Untuk Penggunaan Manual

  • Pro
  • Cons
    • Ketergantungan berada di luar tabung terakhir.

Salin Dependensi ke direktori tertentu

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>copy-dependencies</id>
      <phase>prepare-package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/${project.build.finalName}.lib</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

Jadikan Jar Executable dan Classpath Sadar

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <addClasspath>true</addClasspath>
        <classpathPrefix>${project.build.finalName}.lib/</classpathPrefix>
        <mainClass>${fully.qualified.main.class}</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

Pada titik jarini sebenarnya dapat dieksekusi dengan elemen classpath eksternal.

$ java -jar target/${project.build.finalName}.jar

Buat Arsip yang Dapat Digunakan

The jarfile hanya executable dengan saudara ...lib/direktori. Kita perlu membuat arsip untuk disebarkan dengan direktori dan kontennya.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>antrun-archive</id>
      <phase>package</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <target>
          <property name="final.name" value="${project.build.directory}/${project.build.finalName}"/>
          <property name="archive.includes" value="${project.build.finalName}.${project.packaging} ${project.build.finalName}.lib/*"/>
          <property name="tar.destfile" value="${final.name}.tar"/>
          <zip basedir="${project.build.directory}" destfile="${final.name}.zip" includes="${archive.includes}" />
          <tar basedir="${project.build.directory}" destfile="${tar.destfile}" includes="${archive.includes}" />
          <gzip src="${tar.destfile}" destfile="${tar.destfile}.gz" />
          <bzip2 src="${tar.destfile}" destfile="${tar.destfile}.bz2" />
        </target>
      </configuration>
    </execution>
  </executions>
</plugin>

Sekarang Anda memiliki target/${project.build.finalName}.(zip|tar|tar.bz2|tar.gz)yang masing-masing berisi jardan lib/*.


Plugin Majelis Apache Maven

  • Pro
  • Cons
    • Tidak ada dukungan relokasi kelas (gunakan maven-shade-plugin jika relokasi kelas diperlukan).
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <archive>
          <manifest>
            <mainClass>${fully.qualified.main.class}</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </execution>
  </executions>
</plugin>

Kamu punya target/${project.bulid.finalName}-jar-with-dependencies.jar.


Plugin Apache Maven Shade

  • Pro
  • Cons
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>${fully.qualified.main.class}</mainClass>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

Kamu punya target/${project.build.finalName}-shaded.jar.


onejar-maven-plugin

  • Pro
  • Cons
    • Tidak didukung secara aktif sejak 2012.
<plugin>
  <!--groupId>org.dstovall</groupId--> <!-- not available on the central -->
  <groupId>com.jolira</groupId>
  <artifactId>onejar-maven-plugin</artifactId>
  <executions>
    <execution>
      <configuration>
        <mainClass>${fully.qualified.main.class}</mainClass>
        <attachToBuild>true</attachToBuild>
        <!-- https://code.google.com/p/onejar-maven-plugin/issues/detail?id=8 -->
        <!--classifier>onejar</classifier-->
        <filename>${project.build.finalName}-onejar.${project.packaging}</filename>
      </configuration>
      <goals>
        <goal>one-jar</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Plugin Spring Boot Maven

  • Pro
  • Cons
    • Tambahkan potensi yang tidak perlu terkait Spring dan Spring Boot.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
      <configuration>
        <classifier>spring-boot</classifier>
        <mainClass>${fully.qualified.main.class}</mainClass>
      </configuration>
    </execution>
  </executions>
</plugin>

Kamu punya target/${project.bulid.finalName}-spring-boot.jar.


2
@caiohamamura Anda dapat mengkloning GitHub Repository dan melihat bagaimana semua profil bekerja.
Jin Kwon

Masalahnya adalah dengan paket yang saya gunakan: stackoverflow.com/a/12622037/2548351
caiohamamura

1
Saya pikir ini mungkin jawaban yang paling lengkap untuk topik ini.
Petr Bodnár

139

Mengambil jawaban yang Belum Dijawab dan memformatnya kembali, kami memiliki:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

Selanjutnya, saya akan merekomendasikan menjadikan ini bagian alami dari bangunan Anda, daripada sesuatu untuk memanggil secara eksplisit. Untuk menjadikan ini bagian integral dari bangunan Anda, tambahkan plugin ini ke Anda pom.xmldan ikat ke packageacara siklus hidup. Namun, gotcha adalah bahwa Anda perlu memanggil assembly:singletujuan jika meletakkan ini di pom.xml Anda, sementara Anda akan memanggil 'assembly: assembly' jika mengeksekusi secara manual dari baris perintah.

<project>
  [...]
  <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <configuration>
                  <archive>
                      <manifest>
                          <addClasspath>true</addClasspath>
                          <mainClass>fully.qualified.MainClass</mainClass>
                      </manifest>
                  </archive>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
              </configuration>
              <executions>
                  <execution>
                      <id>make-my-jar-with-dependencies</id>
                      <phase>package</phase>
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      [...]
      </plugins>
    [...]
  </build>
</project>

10
Menggunakan pendekatan dalam jawaban ini menghasilkan pesan galat berikut: 'Gagal memuat atribut manifes Kelas Utama dari <jar file>', ketika mencoba menjalankan JAR menggunakan 'java-jar <jar file>'
Elmo

3
Bagian arsip dari pengaya-jar-plugin diperlukan <archive> <manifest> <addClasspath> true </addClasspath> <mainClass> sepenuhnya.kualifikasi .Kelas Utama </mainClass> </manifest> </archive>
Rade_303

4
Maaf, jawaban ini benar-benar salah, tag mainClass harus ada di entri maven-assembly-plugin karena Anda memanggilnya selama tujuan paket
Alex Lehmann

Saya terkejut, mengapa pom.xml tidak dapat memiliki ini termasuk setelah mvn archetype: menghasilkan perintah? Agak menyebalkan untuk secara manual menyalin-menempelkan ini setiap kali ketika saya membuat proyek pakar baru ...
wintermute

i agak tidak memiliki metode atau kelas utama, saya hanya memiliki kelas dengan fungsi. bagaimana saya bisa membuat toples dan menggunakannya
parlad

97

Gunakan maven-shade-plugin untuk mengemas semua dependensi ke dalam satu jar-uber. Ini juga dapat digunakan untuk membangun jar yang dapat dieksekusi dengan menentukan kelas utama. Setelah mencoba menggunakan maven-assembly dan maven-jar, saya menemukan bahwa plugin ini paling sesuai dengan kebutuhan saya.

Saya menemukan plugin ini sangat berguna karena menggabungkan konten file tertentu daripada menimpa mereka. Ini diperlukan ketika ada file sumber daya yang memiliki nama yang sama di seluruh stoples dan plugin mencoba mengemas semua file sumber daya

Lihat contoh di bawah ini

      <plugins>
    <!-- This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <artifactSet>
                        <!-- signed jars-->
                            <excludes>
                                <exclude>bouncycastle:bcprov-jdk15</exclude>
                            </excludes>
                        </artifactSet>

                         <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- Main class -->
                                <mainClass>com.main.MyMainClass</mainClass>
                            </transformer>
                            <!-- Use resource transformers to prevent file overwrites -->
                            <transformer 
                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>properties.properties</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>applicationContext.xml</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/cxf/cxf.extension</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>META-INF/cxf/bus-extensions.xml</resource>
                            </transformer>
                     </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>

Jadi bagaimana cara bcprov-jdk15.jar masuk ke classpath saat runtime, mengingat bahwa itu dikecualikan dari proses shading?
Andrew Swan

Itu ditarik oleh cxf-rt-ws-security yang merupakan bagian dari ketergantungan saya
Vijay Katam

Belum pernah mendengar tentang plugin ini sebelumnya, tetapi itu memecahkan masalah saya dengan spring.handlers di dalam stoples. Terima kasih!
Alexandre L Telles

11
Mereka yang mendapat pengecualian keamanan, mengecualikan DSA dari Manifest. Periksa maven.apache.org/plugins/maven-shade-plugin/examples/…
ruhsuzbaykus

+1 Saya telah menggunakan minijar: ueberjar di masa lalu, tetapi plugin minijar sekarang sudah tidak digunakan lagi dan diganti dengan shade
rds

19

Lama menggunakan plugin perakitan pakar , tapi saya tidak bisa menemukan solusi untuk masalah dengan "already added, skipping". Sekarang, saya menggunakan plugin lain - onejar-maven-plugin . Contoh di bawah ini ( mvn packagebuild toples):

<plugin>
    <groupId>org.dstovall</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <version>1.3.0</version>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.company.MainClass</mainClass>
            </configuration>
            <goals>
                <goal>one-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Anda perlu menambahkan repositori untuk plugin itu:

<pluginRepositories>
    <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>

bagaimana cara menghilangkan pesan tambahan di output?
Alexandr

17

Anda dapat menggunakan maven-dependency-plugin, tetapi pertanyaannya adalah bagaimana membuat JAR yang dapat dieksekusi. Untuk melakukan itu diperlukan perubahan berikut pada respons Matthew Franglen (btw, menggunakan plugin dependensi lebih lama untuk dibangun ketika mulai dari target bersih):

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>${basedir}/target/dependency</directory>
        </resource>
    </resources>
</build>

16

Anda dapat menggunakan plugin maven-shade untuk membuat jar uber seperti di bawah ini

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Tapi lalu bagaimana ini akan digunakan untuk repo?
Francesco Gualazzi

15

Opsi lain jika Anda benar-benar ingin mengemas kembali isi JAR lain di dalam JAR hasil tunggal Anda adalah plugin Maven Assembly . Itu membongkar dan kemudian mengemas semuanya ke dalam direktori melalui <unpack>true</unpack>. Maka Anda akan memiliki pass kedua yang membuatnya menjadi satu JAR besar.

Opsi lain adalah plugin OneJar . Ini melakukan tindakan pengemasan ulang di atas semua dalam satu langkah.


14

Anda dapat menambahkan yang berikut ke pom.xml Anda :

<build>
<defaultGoal>install</defaultGoal>
<plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.3.1</version>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
    <executions>
      <execution>
        <id>make-my-jar-with-dependencies</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>
</build>

Setelah itu Anda harus beralih melalui konsol ke direktori, di mana pom.xml berada. Maka Anda harus menjalankan mvn assembly: tunggal dan kemudian file JAR Anda yang dapat dieksekusi dengan dependensi akan dibangun. Anda dapat memeriksanya saat beralih ke direktori keluaran (target) dengan cd ./target dan memulai toples Anda dengan perintah yang serupa dengan java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies.jar .

Saya menguji ini dengan Apache Maven 3.0.3 .


13

Saya memeriksa setiap respons ini dengan berusaha membuat toples lemak yang bisa dieksekusi berisi semua dependensi dan tidak ada yang berfungsi dengan baik. Jawabannya adalah plugin teduh, sangat mudah dan langsung.

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>2.3</version>
      <executions>
         <!-- Run shade goal on package phase -->
        <execution>
        <phase>package</phase>
        <goals>
            <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
             <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>path.to.MainClass</mainClass>
             </transformer>
          </transformers>
        </configuration>
          </execution>
      </executions>
    </plugin>

Perlu diketahui bahwa dependensi Anda perlu memiliki ruang lingkup kompilasi atau runtime agar ini berfungsi dengan baik.

Contoh ini berasal dari mkyong.com


Ketika saya memperbaiki ini, maukah Anda memperbarui ulasan Anda. Saya belum mempertimbangkan sebelum memposting dan dengan cepat memperbaiki komentar Anda
dsutherland

2
The pluginelemen berjalan di pom.xmlbawah build/plugins.
isapir

12

Anda dapat menggabungkan maven-shade-plugindan maven-jar-plugin.

  • The maven-shade-pluginpaket kelas dan semua dependensi dalam file jar tunggal.
  • Konfigurasikan maven-jar-pluginuntuk menentukan kelas utama toples Anda yang dapat dieksekusi (lihat Menyiapkan Classpath , bab "Jadikan Jar Dapat Dieksekusi").

Contoh konfigurasi POM untuk maven-jar-plugin:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.example.MyMainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

Akhirnya buat jar yang dapat dieksekusi dengan memohon:

mvn clean package shade:shade

3
Plugin Shade sekarang memiliki cara untuk menentukan entri Kelas Utama dalam manifes: maven.apache.org/plugins/maven-shade-plugin/examples/…
Chadwick

9

Menurut saya, Ken Liu benar. Plugin maven dependency memungkinkan Anda untuk memperluas semua dependensi, yang kemudian dapat Anda perlakukan sebagai sumber daya. Ini memungkinkan Anda untuk memasukkannya dalam artefak utama . Penggunaan plugin rakitan membuat artefak sekunder yang sulit diubah - dalam kasus saya, saya ingin menambahkan entri manifes khusus. Pom saya berakhir sebagai:

<project>
 ...
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
     <execution>
      <id>unpack-dependencies</id>
      <phase>package</phase>
      <goals>
       <goal>unpack-dependencies</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
  </plugins>
  ...
  <resources>
   <resource>
    <directory>${basedir}/target/dependency</directory>
    <targetPath>/</targetPath>
   </resource>
  </resources>
 </build>
 ...
</project>

1
Benar-benar bagus! Bukankah lebih baik menggunakan fase menghasilkan sumber daya untuk pembongkaran?
nawroth

9

Seharusnya seperti itu:

<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>unpack-dependencies</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>unpack-dependencies</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Pembongkaran harus dalam fase menghasilkan-sumber daya karena, jika dalam fase paket, tidak akan dimasukkan sebagai sumber daya. Coba paket bersih dan Anda akan melihat.


7

Ada masalah dengan mencari file assembly bersama dengan maven-assembly-plugin-2.2.1?

Coba gunakan parameter konfigurasi descriptorId daripada parameter deskriptor / descriptor atau descriptorRefs / descriptorRef.

Tak satu pun dari mereka melakukan apa yang Anda butuhkan: mencari file di classpath. Tentu saja Anda perlu menambahkan paket di mana rakitan bersama berada di classpath maven-assembly-plugin (lihat di bawah). Jika Anda menggunakan Maven 2.x (bukan Maven 3.x), Anda mungkin perlu menambahkan ketergantungan ini di pom.xml induk paling atas di bagian pluginManagement.

Lihat ini untuk lebih jelasnya.

Kelas: org.apache.maven.plugin.assembly.io.DefaultAssemblyReader

Contoh:

        <!-- Use the assembly plugin to create a zip file of all our dependencies. -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <descriptorId>assembly-zip-for-wid</descriptorId>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>cz.ness.ct.ip.assemblies</groupId>
                    <artifactId>TEST_SharedAssemblyDescriptor</artifactId>
                    <version>1.0.0-SNAPSHOT</version>
                </dependency>
            </dependencies>
        </plugin>

7

Untuk mengatasi masalah ini kami akan menggunakan Maven Assembly Plugin yang akan membuat JAR bersama dengan JAR ketergantungannya menjadi satu file JAR yang dapat dieksekusi. Cukup tambahkan konfigurasi plugin di bawah ini di file pom.xml Anda.

<build>
   <pluginManagement>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
               <archive>
                  <manifest>
                     <addClasspath>true</addClasspath>
                     <mainClass>com.your.package.MainClass</mainClass>
                  </manifest>
               </archive>
               <descriptorRefs>
                  <descriptorRef>jar-with-dependencies</descriptorRef>
               </descriptorRefs>
            </configuration>
            <executions>
               <execution>
                  <id>make-my-jar-with-dependencies</id>
                  <phase>package</phase>
                  <goals>
                     <goal>single</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </pluginManagement>
</build>

Setelah melakukan ini jangan lupa untuk menjalankan alat MAVEN dengan perintah ini mvn clean compile assembly: single

http://jkoder.com/maven-creating-a-jar-together-with-its-dependency-jars-into-a-single-executable-jar-file/


5

Saya tidak akan menjawab langsung pertanyaan seperti yang sudah dilakukan orang lain sebelumnya, tapi saya benar-benar bertanya-tanya apakah itu ide yang baik untuk menanamkan semua dependensi dalam toples proyek itu sendiri.

Saya melihat intinya (kemudahan penyebaran / penggunaan) tetapi itu tergantung pada kasus penggunaan dari poject Anda (dan mungkin ada alternatif (lihat di bawah)).

Jika Anda menggunakannya sepenuhnya mandiri, mengapa tidak.

Tetapi jika Anda menggunakan proyek Anda dalam konteks lain (seperti di webapp, atau jatuh di folder tempat guci lain), Anda mungkin memiliki duplikat jar di classpath Anda (yang di folder, yang di guci). Mungkin bukan penawaran, tetapi saya biasanya menghindari ini.

Alternatif yang baik:

  • gunakan aplikasi Anda sebagai .zip / .war: arsip berisi toples proyek Anda dan semua toples yang tergantung;
  • menggunakan mekanisme classloader dinamis (lihat Spring, atau Anda dapat dengan mudah melakukan ini sendiri) untuk memiliki satu titik masuk proyek Anda (satu kelas untuk memulai - lihat mekanisme Manifest pada jawaban lain), yang akan menambahkan (secara dinamis) ke classpath saat ini semua guci yang dibutuhkan.

Seperti ini, dengan pada akhirnya hanya manifes dan "utama classloader dinamis khusus", Anda dapat memulai proyek Anda dengan:

java -jar ProjectMainJar.jar com.stackoverflow.projectName.MainDynamicClassLoaderClass

1
Bagaimana cara menempatkan toples proyek dan semua toples yang tergantung pada arsip?

4

Untuk membuat JAR yang dapat dieksekusi dari baris perintah itu sendiri, cukup jalankan perintah di bawah ini dari jalur proyek:

mvn assembly:assembly

3
Saya pikir Anda masih perlu melakukan beberapa hal pom.xmlselain Anda dapatkan Error reading assemblies: No assembly descriptors found.. Itulah yang terjadi pada saya.
Sridhar Sarnobat

3

Ini adalah cara terbaik yang saya temukan:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.4</version>
    <configuration>
      <archive>
        <manifest>
        <addClasspath>true</addClasspath>
        <mainClass>com.myDomain.etc.MainClassName</mainClass>
        <classpathPrefix>dependency-jars/</classpathPrefix>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
      <execution>
        <id>copy-dependencies</id>
        <phase>package</phase>
        <goals>
            <goal>copy-dependencies</goal>
        </goals>
        <configuration>
            <outputDirectory>
               ${project.build.directory}/dependency-jars/
            </outputDirectory>
        </configuration>
      </execution>
    </executions>
  </plugin>

Dengan konfigurasi ini, semua dependensi akan berlokasi di /dependency-jars. Aplikasi saya tidak memiliki Mainkelas, hanya konteks, tetapi salah satu dependensi saya memiliki Mainkelas ( com.myDomain.etc.MainClassName) yang memulai server JMX, dan menerima parameter startatau stop. Jadi dengan ini saya dapat memulai aplikasi saya seperti ini:

java -jar ./lib/TestApp-1.0-SNAPSHOT.jar start

Saya tunggu semoga bermanfaat untuk Anda semua.


3

Saya membandingkan plugin pohon yang disebutkan dalam posting ini. Saya menghasilkan 2 toples dan direktori dengan semua toples. Saya membandingkan hasilnya dan tentu saja maven-shade-plugin adalah yang terbaik. Tantangan saya adalah bahwa saya memiliki banyak sumber daya pegas yang perlu digabung, serta layanan jax-rs, dan JDBC. Mereka semua digabungkan dengan benar oleh plugin warna dibandingkan dengan plugin maven-assembly-plugin. Dalam hal ini pegas akan gagal kecuali Anda menyalinnya ke folder sumber daya Anda sendiri dan menggabungkannya secara manual satu kali. Kedua plugin menghasilkan pohon ketergantungan yang benar. Saya memiliki beberapa ruang lingkup seperti tes, menyediakan, mengkompilasi, dll tes dan disediakan dilewati oleh kedua plugin. Mereka berdua menghasilkan manifes yang sama tetapi saya dapat mengkonsolidasikan lisensi dengan plugin teduh menggunakan transformator mereka. Dengan maven-dependency-plugin tentu saja Anda tidak t memiliki masalah karena guci tidak diekstraksi. Tetapi seperti yang telah ditunjukkan beberapa orang lainnya, Anda perlu membawa satu file tambahan agar berfungsi dengan baik. Ini adalah snip dari pom.xml

            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        <includeScope>compile</includeScope>
                        <excludeTransitive>true</excludeTransitive>
                        <overWriteReleases>false</overWriteReleases>
                        <overWriteSnapshots>false</overWriteSnapshots>
                        <overWriteIfNewer>true</overWriteIfNewer>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.rbccm.itf.cdd.poller.landingzone.LandingZonePoller</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-my-jar-with-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <configuration>
                <shadedArtifactAttached>false</shadedArtifactAttached>
                <keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/services/javax.ws.rs.ext.Providers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.factories</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.handlers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.schemas</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.tooling</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer">
                    </transformer>
                </transformers>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

2

Sesuatu yang berhasil bagi saya adalah:

  <plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>prepare-package</phase>
        <goals>
          <goal>unpack-dependencies</goal>
        </goals>
        <configuration>
          <outputDirectory>${project.build.directory}/classes</outputDirectory>
        </configuration>
      </execution>

    </executions>
  </plugin>


  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>package</phase>
      </execution>
    </executions>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <classpathPrefix>lib/</classpathPrefix>
          <mainClass>SimpleKeyLogger</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>

Saya memiliki kasus luar biasa karena ketergantungan saya pada sistem satu:

<dependency>
  ..
  <scope>system</scope>
  <systemPath>${project.basedir}/lib/myjar.jar</systemPath>
</dependency>

Saya telah mengubah kode yang disediakan oleh @ user189057 dengan perubahan: 1) maven-dependency-plugin dieksekusi di "prep-package" fase 2) Saya mengekstraksi classess yang tidak dibongkar secara langsung ke "target / class"


2

Saya mencoba jawaban paling banyak dipilih di sini, dan bisa mendapatkan jar runnable. Tetapi program tidak berjalan dengan benar. Saya tidak tahu alasannya. Ketika saya mencoba lari dariEclipse , saya mendapatkan hasil yang berbeda tetapi ketika saya menjalankan jar dari baris perintah saya mendapatkan hasil yang berbeda (crash dengan kesalahan runtime khusus-program).

Saya memiliki persyaratan yang sama dengan OP hanya bahwa saya memiliki terlalu banyak (Maven) dependensi untuk proyek saya. Untungnya, satu-satunya solusi yang berhasil bagi saya adalah menggunakan itu Eclipse. Sangat sederhana dan sangat mudah. Ini bukan solusi untuk OP tetapi merupakan solusi untuk seseorang yang memiliki persyaratan serupa tetapi dengan banyak ketergantungan Maven,

1) Cukup klik kanan pada folder proyek Anda (di Eclipse) dan pilih Export

2) Kemudian pilih Java ->Runnable Jar

3) Anda akan diminta untuk memilih lokasi file jar

4) Akhirnya, pilih kelas yang memiliki metode Utama yang ingin Anda jalankan dan pilih Package dependencies with the Jar filedan klikFinish


2

Ini juga bisa menjadi pilihan, Anda dapat membuat file jar Anda

<build>
    <plugins>
        <plugin>
            <!-- Build an executable JAR -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>WordListDriver</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

2

Bagi siapa pun yang mencari opsi untuk mengecualikan dependensi tertentu dari uber-jar, ini adalah solusi yang berfungsi untuk saya:

<project...>
<dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>1.6.1</version>
            <scope>provided</scope> <=============
        </dependency>
</dependencies>
<build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>...</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Jadi ini bukan konfigurasi mvn-assembly-plugin tetapi properti dari ketergantungan.


2

Sudah ada jutaan jawaban, saya ingin menambahkan Anda tidak perlu <mainClass>jika Anda tidak perlu menambahkan entryPoint ke aplikasi Anda. Misalnya API mungkin belum tentu memiliki mainmetode.

konfigurasi plugin maven

  <build>
    <finalName>log-enrichment</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>

membangun

mvn clean compile assembly:single

memeriksa

ll target/
total 35100
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ./
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ../
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 archive-tmp/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 classes/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-sources/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-test-sources/
-rwxrwx--- 1 root vboxsf 35929841 Sep 29 16:10 log-enrichment-jar-with-dependencies.jar*
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 maven-status/

2

Tambahkan ke pom.xml:

  <dependency>
            <groupId>com.jolira</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
            <version>1.4.4</version>
  </dependency>

dan

<plugin>
       <groupId>com.jolira</groupId>
       <artifactId>onejar-maven-plugin</artifactId>
       <version>1.4.4</version>
       <executions>
              <execution>
                     <goals>
                         <goal>one-jar</goal>
                     </goals>
              </execution>
       </executions>
</plugin>

Itu dia. Paket mvn berikutnya juga akan membuat satu guci lemak, termasuk semua guci ketergantungan.


1

Maven-assembly-plugin bekerja sangat baik untuk saya. Saya menghabiskan berjam-jam dengan maven-dependency-plugin dan tidak bisa membuatnya bekerja. Alasan utamanya adalah bahwa saya harus mendefinisikan di bagian konfigurasi secara eksplisit item artefak yang harus dimasukkan seperti yang dijelaskan dalam dokumentasi . Ada contoh di sana untuk kasus-kasus ketika Anda ingin menggunakannya seperti:, di mvn dependency:copymana tidak ada artifactItems tetapi tidak berfungsi.


1

Posting blog ini menunjukkan pendekatan lain dengan menggabungkan plugins maven-jar dan maven-assembly. Dengan konfigurasi perakitan xml dari posting blog, itu juga dapat dikontrol jika dependensi akan diperluas atau hanya dikumpulkan dalam folder dan direferensikan oleh entri classpath di manifes:

Solusi yang ideal adalah memasukkan toples ke folder lib dan file manifest.mf dari toples termasuk semua toples di classpath.

Dan persis yang dijelaskan di sini: https://caffebig.wordpress.com/2013/04/05/executable-jar-file-with-dependent-jars-using-maven/


0
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <!-- get all project dependencies -->
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!-- bind to the packaging phase -->
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

1
Perlu sedikit penjelasan lebih lanjut tentang ini; apakah komentar itu hanya dokumentasi, atau apakah perlu ada opsi tambahan yang perlu ditempatkan di lokasi komentar itu?
Mark Stewart

-2

Oke, jadi ini solusi saya. Saya tahu ini tidak menggunakan file pom.xml. Tapi saya punya masalah programmme saya mengkompilasi dan berjalan di Netbeans tetapi gagal ketika saya mencoba Java -jar MyJarFile.jar. Sekarang, saya tidak sepenuhnya mengerti Maven dan saya pikir ini mengapa mengalami kesulitan untuk mendapatkan Netbeans 8.0.2 untuk memasukkan file jar saya di perpustakaan untuk memasukkannya ke file jar. Saya berpikir tentang bagaimana saya menggunakan file jar tanpa Maven di Eclipse.

Itu Maven yang dapat mengkompilasi semua dependanice dan plugin. Bukan Netbeans. (Jika Anda bisa mendapatkan Netbeans dan dapat menggunakan java .jar untuk melakukan ini tolong beri tahu saya caranya (^. ^) V)

[Dipecahkan - untuk Linux] dengan membuka terminal.

Kemudian

cd /MyRootDirectoryForMyProject

Lanjut

mvn org.apache.maven.plugins:maven-compiler-plugin:compile

Lanjut

mvn install

Ini akan membuat file jar di direktori target.

MyJarFile-1.0-jar-with-dependencies.jar

Sekarang

cd target

(Anda mungkin perlu menjalankan chmod +x MyJarFile-1.0-jar-with-dependencies.jar:)

Dan akhirnya

java -jar MyJarFile-1.0-jar-with-dependencies.jar

Tolong lihat

https://cwiki.apache.org/confluence/display/MAVEN/LifecyclePhaseNotFoundException

Saya akan memposting solusi ini pada beberapa halaman lain dengan masalah yang sama. Semoga saya bisa menyelamatkan seseorang dari rasa frustrasi selama seminggu.


2
Coba buka proyek Maven yang Anda buat dengan Netbeans. Aturan dasar Netbeans adalah selalu membuat proyek Maven dan tidak pernah menjadi 'aplikasi Java'. Menambahkan plugin maven-shade-plugin seperti salah satu jawaban. Bekerja seperti pesona.
rjdkolb
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.