H
H
halogen2015-05-17 16:01:15
Android
halogen, 2015-05-17 16:01:15

Retrolambda / retrolambda-maven: Can dependency class-files be handled?

Wrote several Java libraries for myself for my small internal projects. Target platforms: "regular" Java, GWT and Android. Assembly of all modules on Maven. Unfortunately, due to the lack of support for Java 8 in GWT and Android, some of the libraries are written in older Java 6 if those libraries were intended to be used on those platforms. I plan to completely switch to the "eight", so in test mode I translated the source code of these libraries into Java 8 language constructs (lambdas, default methods, etc.).
Apparently, there are no problems with GWT, although this business has only worked under GWT 2.8.0 so far, the release of which has not yet taken place. But I can't seem to get it to work on Android. The problem is that when building a Maven project (retrolambda-maven-plugin), Retrolambda does not see the dependency class files, but converts only the class files of the current module, which breaks the assembly:

[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

The Maven plugin itself is configured as follows:
<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>

Is it possible to force Retrolambda and its Maven plugin in particular to handle dependency classfiles, and if so, how? Or maybe we should abandon Retrolambda in favor of another tool, if one exists? And in general, how are things in the Android world using libraries in Java 8?
Thank you!
PS I was thinking that it would be possible to run all my libraries through Retrolambda even before they get into the Android project assembly. But there is one minus: it is then always-Java-8-like -projects (and in fact Java 6) + it is impossible for external dependencies.
-------------------
UPDATE #1
Looks like I was wrong about Retrolambda. After a little digging around, I realized that you can "blame" android-maven-plugin, because this plugin pulls uninstrumented JARs directly from the Maven repository, and not from the target directory. By including a more detailed log, I got the command that the android-maven-plugin generates.
$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

As an idea, for now I only have the use of the maven-dependency-plugin, which would collect all three artifacts in $BUILD_DIRECTORY/classes for further processing in the retrolambda-maven-plugin. Let's say something like this:
STEP 1: Pull all dependencies
<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>

STEP 2: Process copied Retrolambda dependencies
Simply call retrolambda-maven-plugin
STEP 3: Compile DEX file
Call android-maven-plugin, but exclude those dependencies that ended up in the target directory, because it is assumed that they are all already there
But also this idea fails because I don't see a way to exclude artifacts from DEXification using android-maven-plugin. Is it possible to somehow influence the plugin so that the artifacts are not pulled from the repository, since they are stored there in a non-instrumented form?
My plugins:
* 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

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question