halogen
@halogen
Java developer

Retrolambda / retrolambda-maven: Можно ли обрабатывать класс-файлы зависимостей?

Написал для себя несколько библиотек на 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
  • Вопрос задан
  • 787 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы