2010-09-03 17 views
14

Mam ten projekt złożony z wielu słoików i wojny, by zrobić ucho. Buduję wszystko w migawce i działa świetnie. Potem wydałem wersję dla każdego projektu i zobaczyłem, że słoiki i wojna miały nieco inny rozmiar niż te z migawkami.Dodatek do wtyczki Maven: określ wersję kompilatora Javy

Porównywanie pliku do pliku zdałem sobie sprawę, że pliki .class były tam wszystkie, ale nieco większe lub większe, nie więcej niż 40 bajtów ogólnie.

wymusić kompilację użyć Java 1.5 przy użyciu tego znacznika w Maven:

<build> 
    <pluginManagement> 
     <plugins> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-compiler-plugin</artifactId> 
       <version>2.0.2</version> 
       <configuration> 
        <source>1.5</source> 
        <target>1.5</target> 
       </configuration> 

Używam tego znacznik do wtyczki wydaniu:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-release-plugin</artifactId> 
    <version>2.0</version> 
    <configuration> 
     <releaseProfiles>release</releaseProfiles> 
     <goals>deploy</goals> 
    </configuration> 
</plugin> 

Czy to możliwe, że plugin uwolnienia kompiluje w 1.6 lub inne, wyjaśniające różnicę wielkości klas? Jeśli tak, czy mogę sprawić, by wtyczka wydania została skompilowana w wersji 1.5?

Dzięki za twój wkład.

+0

Jeśli spróbujesz uruchomić zwolnione słoiki w wersji 1.5, czy działają one w wersji 1.5? Czy otrzymasz nieważny wyjątek jar/corrupted jar, informujący o tym, że prawdopodobnie zostały skompilowane w nowszej wersji? – aperkins

+0

Wygląda na to, że zarówno soki migawkowe, jak i wydań działają, działające w wersji 1.5. Nie dostaję jeszcze żadnego błędu, ale nie rozumiem, co sprawia, że ​​klasy różnią się rozmiarem. Mam tylko nadzieję, że coś mi się nie podskoczy, kiedy to osiągnie produkcję. – IceGras

+0

@IceGras, to może być niebezpieczne, wyjaśniam dlaczego w mojej odpowiedzi poniżej ... W skrócie, _referencje do nieistniejących metod mogą zostać włączone_ – Lucas

Odpowiedz

1

Możesz zweryfikować wersję, dla której klasa jest kompilowana, używając narzędzia javap dołączonego do JDK. Z wiersza poleceń:

javap -verbose MyClass 

W wynikach wyszukiwania javap dla "mniejszej wersji" i "głównej wersji" około dziesięciu wierszy w dół.

Następnie użyj poniższej tabeli: różnica wielkości

 
major  minor  Java platform version 
45   3   1.0 
45   3   1.1 
46   0   1.2 
47   0   1.3 
48   0   1.4 
49   0   1.5 
50   0   1.6 

.class może być spowodowane skompilować wersję, ale również mogą być spowodowane innymi opcjami kompilacji takich kompilacji z informacjami debug (numery linii w stacktraces).

+0

Na MacOS (przynajmniej 10.12.6), wynik z pliku ** * Polecenie jest jeszcze bardziej pomocne, np 'plik MyClass.class' może produkować:' MyClass.class: skompilowane dane klasy Java, wersja 50.0 (Java 1.6) ' – Gary

0

Could it be that the release plugin is compiling in 1.6 or other, explaining the classes size difference ?

Nie może być IMO. Plugin Release Maven nie kompiluje niczego, tylko uruchamia fazę, która sama wyzwala fazę compile i Plugin kompilatora Maven. Innymi słowy, zostanie użyta wtyczka Maven Compiler i jej ustawienia.

można użyć następujących poleceń, aby kontrolować, co dokładnie się dzieje:

mvn help:active-profiles -Prelease 

sprawdzić profile. Aby sprawdzić pom. Pom., Należy wykonać

mvn help:effective-pom -Prelease 

.

+0

Mam ten sam problem. Mam '' i '' określone w moim pliku pom jako 1.6. Kiedy uruchamiam 'pakiet mvn', osiągam sukces. Jednak po uruchomieniu 'mvn release: prepare' nie powiedzie się z błędem' TunneledDataSourceWrapper.java:[17,7]: TunneledDataSourceWrapper nie jest abstrakcyjny i nie zastępuje abstrakcyjnej metody getParentLogger() w CommonDataSource' co oznacza, że ​​próbuje skompilować java 7 _ (java 7 dodała metodę do CommonDataSource czyniąc ją niekompatybilną z 6) _. – Lucas

18

--- SPOILER ALERT ---

Krótka odpowiedź jest taka, że ​​w celu zestawienia źródło do starszej wersji, trzeba dostarczać zarówno opcję -source jak również -bootclasspath. Zobacz this article. A jeśli chcesz skompilować źródła do nowszej wersji, trzeba ustawić <source>, <target>, <compilerVersion>, <fork> i <executable> na wtyczce kompilator i ustawić <jvm> na wtyczce murowany ...

a teraz za historię ...

Wpadłem na ten sam problem. Okazuje się, że kompilowanie poprzedniej wersji może nie być tak proste jak ustawienie <source> i <target>. Mój konkretny przypadek jest taki, że mam JDK Java 1.7 i moja klasa ma niekompatybilność z 1.7 (dodali nową metodę do interfejsu, który implementuję). Kiedy próbowałem ją skompilować, kompilator dał mi komunikat o błędzie stwierdzający, że nie zaimplementowałem metody interfejsu. W każdym razie, próbowałem ustawić wtyczkę kompilatora:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-compiler-plugin</artifactId> 
    <version>2.3.2</version> 
    <configuration> 
     <source>1.6</source> 
     <target>1.6</target> 
     <encoding>UTF-8</encoding> 
    </configuration> 
    </plugin> 

, ale po uruchomieniu kompilacji wystąpił ten sam błąd. Więc wpadłem Maven w debugowania i zobaczyłem to:

[INFO] [DEBUG] Command line options: 
[INFO] [DEBUG] -d C:\... -nowarn -target 1.6 -source 1.6 -encoding UTF-8 

Należy pamiętać, że ... jest umieścić w miejscu rzeczywistych argumentów dla zwięzłości

na wyjściu. Komunikat zaczynający się od -d jest faktyczną pełną listą argumentów kompilacji. Tak więc, jeśli usunąć flagę -nowarn i wklej odpoczynek po javac w wierszu poleceń można zobaczyć rzeczywiste wyjście z kompilatora:

javac -d C:\... -target 1.6 -source 1.6 -encoding UTF-8 
warning: [options] bootstrap class path not set in conjunction with -source 1.6 

ten wypisuje handy-dandy ostrzegawczy bootstrap klasy ścieżki nie ustawiony w w połączeniu z -source 1.6. Trochę googling na który włącza się this article który stanowi:

To use javac from JDK N to cross-compiler to an older platform version, the correct practice is to:

  • Use the older -source setting.
  • Set the bootclasspath to compile against the rt.jar (or equivalent) for the older platform.

If the second step is not taken, javac will dutifully use the old language rules combined with new libraries, which can result in class files that do not work on the older platform since references to non-existent methods can get included.

Teraz przedstawieniu the maven documentation for the compiler plugin daje:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-compiler-plugin</artifactId> 
    <version>2.5.1</version> 
    <configuration> 
     <compilerArguments> 
     <verbose /> 
     <bootclasspath>${java.home}\lib\rt.jar</bootclasspath> 
     </compilerArguments> 
    </configuration> 
    </plugin> 

które można następnie połączyć ze swojej wcześniejszej konfiguracji, aby uzyskać:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-compiler-plugin</artifactId> 
    <version>2.3.2</version> 
    <configuration> 
     <source>1.6</source> 
     <target>1.6</target> 
     <encoding>UTF-8</encoding> 
     <bootclasspath>${java.home}\lib\rt.jar</bootclasspath> 
    </configuration> 
    </plugin> 

I teraz wystarczy udostępnić zmienną ${java.home} dla swoich właściwości systemu mvn (przez -D systemu lub poprzez zwykły stare zmienne środowiskowe, lub możesz się naprawdę spodobać i umieścić go w profilu java 6 w ustawieniach użytkownika).

Teraz wystarczy uruchomić build i przejść chwycić zimne piwo podczas gdy chugs dala ...

---- EDIT ----

... Ostatnią rzeczą w tym rt.jar Twoja bootclasspath jest zawsze wymagana, jednak odkryłem, że więcej może być potrzebnych dla każdego przypadku. Musiałem dołączyć plik jce.jar (w tym samym katalogu, co rt.jar), ponieważ moja aplikacja pracowała przy kryptografii.

---- EDIT 2 ----

Dla uśmiechami, próbowałem go innym kierunku. Zamiast biegać Maven Java 7 kompilacji dla Java 6, wpadłem Maven Java 6 kompilacji Java 7. Pierwsza próba jest dość prosta:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-compiler-plugin</artifactId> 
    <version>2.5.1</version> 
    <configuration> 
     <source>1.7</source> 
     <target>1.7</target> 
     <fork>true</fork> 
     <verbose>true</verbose> 
     <compilerVersion>1.7</compilerVersion> 
     <executable>${JAVA_7_HOME}/bin/javac</executable> 
     <encoding>UTF-8</encoding> 
    </configuration> 
    </plugin> 

Zasadniczo mogę ustawić <source> i <target> do 1,7, ale to oczywiście nie wystarczy, ponieważ 6 cant skompiluje 7 kodów. Wracając do wtyczki kompilatora, faktycznie jest an example page opisujące, co należy zrobić.Mianowicie, musisz <fork> wyłączyć nowy proces, używając java 7 <executable>. Więc teraz myślę, że wszystko gotowe. Czas odpalić budowy ...

C:\Projects\my-project>mvn package 
... 
Caused by: java.lang.UnsupportedClassVersionError: mypackage.StupidTest : Unsup 
ported major.minor version 51.0 
... 
[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD FAILURE 
[INFO] ------------------------------------------------------------------------ 

Co do cholery jest UnsupportedClassVersionError? Bliższe spojrzenie mówi nam o tym, że wtyczka maven-surefire nie działa. Więc próbuję tylko mvn compile i na pewno osiągam sukces, ponieważ wtyczka "surefire" nigdy się nie uruchamia. Więc biegnę mvn -X package i zauważy ten klejnot:

Forking command line: cmd.exe /X /C ""C:\Program Files\Java\jdk1.6.0_29\jre\bin\ 
java" -jar C:\Projects\my-project\target\surefire\surefirebooter2373372991878002 
398.jar C:\Projects\my-project\target\surefire\surefire1861974777102399530tmp C: 
\Projects\my-project\target\surefire\surefire4120025668267754796tmp" 

Ok, więc jego bieg java 6. Dlaczego? Dokumentacja dla SureFire daje to:

jvm: 
Option to specify the jvm (or path to the java executable) to use with the forking 
options. For the default, the jvm will be a new instance of the same VM as the one 
used to run Maven. JVM settings are not inherited from MAVEN_OPTS. 

Ponieważ zabrakło mvn z Java 6 VM jej rozwidlenia na Java 6 VM dla swoich testów jednostkowych. Więc ustawienie tej opcji odpowiednio:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-surefire-plugin</artifactId> 
    <version>2.12</version> 
    <configuration> 
     <jvm>${JAVA_7_HOME}/bin/java</jvm> 
    </configuration> 
    </plugin> 

I rozpalania kompilacji ...

[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD SUCCESS 
[INFO] ------------------------------------------------------------------------ 
+0

Czy coś się zmieniło w Javie 8? Buduję z docelowym językiem Java 6 i jeśli ustawię 'bootclasspath' w moim' pom.xml', otrzymam plik 'dreaded' class ma złą wersję 52.0, powinien być 50.0'. Kiedy * usunę * 'compilerArguments' i zachowam' source' oraz 'target', moja kompilacja nie zawiedzie. To jest dokładne przeciwieństwo tej odpowiedzi. Więcej szczegółów na to pytanie: http://stackoverflow.com/questions/34854961/class-file-has-wrong-version-after-jenkins-upgrade –

+0

@AmedeeVanGasse, przepraszam, nie mam żadnej wiedzy o czymś, co spowodowałoby, że Java 8 zachowywać się inaczej niż powyższa sytuacja. – Lucas

+0

Nieważne. Podejrzewam bardzo starą wersję wtyczki kompilatora Maven, ponieważ działa dokładnie tak, jak w twoim przykładzie z aktualną wersją 3.3 i parametrami dokładnie takimi, jak w twoich odpowiedziach. Najbardziej osobliwe, ale takie są subtelności Mavena. –

0

Tylko uwaga, jeśli źle wersja podniósł, dostaniesz coś podobnego błędu

xxxx is not supported in -source 1.5 
[ERROR] (use -source 7 or higher to enable yyyy) 

Podczas wydania programu maven zwolnij wtyczkę (ustawia/domyślnie) wersję 1.5 kompilatora. Aby upewnić się, że odbiera poprawną wersję, określ właściwości.

<properties> 
<maven.compiler.source>1.7</maven.compiler.source> 
<maven.compiler.target>1.7</maven.compiler.target> 
</properties> 
Powiązane problemy