Написал для себя несколько библиотек на Java для своих небольших внутренних проектов. Целевые платформы: "обычная" Java, GWT и Android. Сборка всех модулей на Maven. К сожалению, из-за отсутствия поддержки Java 8 в GWT и Android некоторые из библитек написаны на старой Java 6, если эти библиотеки предполагалось использовать на этих платформах. Планирую полностью перейти на "восьмёрку", поэтому в тестовом режиме перевел исходный код этих библиотек на языковые конструкции Java 8 (лямбды, методы по умолчанию и т.д.).
С GWT проблем, по-видимому, нет, хотя это дело пока заработало только под GWT 2.8.0, релиз которого пока не состоялся. Но никак не могу заставить это работать под Android. Проблема в том, что Retrolambda во время сборки проекта по Maven (retrolambda-maven-plugin) не видит класс-файлов зависимостей, а преобразовывает только класс-файлы текущего модуля, из-за чего ломается сборка:
[INFO] UNEXPECTED TOP-LEVEL EXCEPTION:
[INFO] com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
[INFO] at com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)
[INFO] at com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
[INFO] at com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)
[INFO] at com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)
[INFO] at com.android.dx.command.dexer.Main.processClass(Main.java:665)
[INFO] at com.android.dx.command.dexer.Main.processFileBytes(Main.java:634)
[INFO] at com.android.dx.command.dexer.Main.access$600(Main.java:78)
[INFO] at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:572)
[INFO] at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
[INFO] at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
[INFO] at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
[INFO] at com.android.dx.command.dexer.Main.processOne(Main.java:596)
[INFO] at com.android.dx.command.dexer.Main.processAllFiles(Main.java:498)
[INFO] at com.android.dx.command.dexer.Main.runMonoDex(Main.java:264)
[INFO] at com.android.dx.command.dexer.Main.run(Main.java:230)
[INFO] at com.android.dx.command.dexer.Main.main(Main.java:199)
[INFO] at com.android.dx.command.Main.main(Main.java:103)
[INFO] ...while parsing foo/bar/Java8Driven.class
Сам плагин для Maven настроен следущим образом:
<plugin>
<groupId>net.orfjackal.retrolambda</groupId>
<artifactId>retrolambda-maven-plugin</artifactId>
<version>2.0.2</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>process-main</goal>
<goal>process-test</goal>
</goals>
</execution>
</executions>
<configuration>
<target>1.6</target>
<defaultMethods>true</defaultMethods>
</configuration>
</plugin>
Можно ли заставить Retrolambda и его Maven-плагин в частности обрабатывать класс-файлы зависимостей, и если да, то как? Или, может, стоит отказаться от Retrolambda в пользу другого инструмента, если такой существует? И вообще, как обстоят дела в мире Android с использованием библиотек на Java 8?
Спасибо!
P.S. Я тут подумал, что можно было бы все свои библиотеки прогонять через Retrolambda ещё до того, как они попадут в сборку Android-проекта. Но есть один минус: это тогда
always-Java-8-like-проекты (а на самом деле Java 6) + это невозможно для зависимостей извне.
-------------------
ОБНОВЛЕНИЕ №1
Похоже, я был неправ по поводу Retrolambda. Немного поковырявшись, я понял, что "обвинять" можно android-maven-plugin, потому что этот плагин тянет неинструментированные JAR-ки прямо из Maven-репозитория, а не из директории target. Включив более подробный лог, я получил команду, которую генерирует android-maven-plugin.
$JAVA_HOME/jre/bin/java
-Xmx1024M
-jar "$ANDROID_HOME/sdk/build-tools/android-4.4/lib/dx.jar"
--dex
--output=$BUILD_DIRECTORY/classes.dex
$BUILD_DIRECTORY/classes
$M2_REPO/foo1/bar1/0.1-SNAPSHOT/bar1-0.1-SNAPSHOT.jar
$M2_REPO/foo2/bar2/0.1-SNAPSHOT/bar2-0.1-SNAPSHOT.jar
$M2_REPO/foo3/bar3/0.1-JAVA-8-SNAPSHOT/bar3-0.1-JAVA-8-SNAPSHOT.jar
В качестве идеи у меня пока только использование maven-dependency-plugin, который бы собрал все три артефакта в $BUILD_DIRECTORY/classes для подальшей их обработки в retrolambda-maven-plugin. Скажем, нечто вроде этого:
ШАГ 1: Стянуть все зависимости<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
ШАГ 2: Обработать скопированные зависимости RetrolambdaПросто вызвать retrolambda-maven-pluginШАГ 3: Скомпилировать DEX-файлВызвать android-maven-plugin, но исключить те зависимости, которые попали в директорию target, потому как предполагается, что они все уже там
Но и эта идея неудачна, потому как я не вижу способа исключить артефакты от DEX-ификции с помощью android-maven-plugin. Можно ли как-то повлиять на плагин таким образом, чтобы артефакты не тянулись из репозитория, так как они там хранятся в неотинструментированном виде?
Мои плагины:
* org.apache.maven.plugins:maven-dependency-plugin:2.10
* net.orfjackal.retrolambda:retrolambda-maven-plugin:2.0.2
* com.jayway.maven.plugins.android.generation2:android-maven-plugin:3.9.0-rc.3