Skip to content

Commit

Permalink
Make it a Javac plugin (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
bsideup authored Sep 8, 2020
1 parent ed36f18 commit c3d9df7
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 103 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 13
java-version: 14
- name: Build with Gradle
run: ./gradlew build
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
.gradle

build/
target/

.idea/
out/
*.iml
*.ipr
*.iws


.project
Expand Down
73 changes: 42 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Jabel - use Javac 12+ syntax when targeting Java 8
# Jabel - use modern Java 9-14 syntax when targeting Java 8

> Because life is too short to wait for your users to upgrade their Java!
Expand All @@ -13,7 +13,7 @@ But, since most of features after Java 8 did not require a change in the bytecod

## How Jabel works

Although Jabel is an annotation processor, it does not run any processing,
Although Jabel is a javac compiler plugin, it does not run any processing,
but instruments the java compiler classes and makes it treat some new Java 9+ languages features
as they were supported in Java 8.

Expand All @@ -32,7 +32,7 @@ require the same target as the JVM because they get released altogether.
As was previously described, Jabel makes the compiler think that certain features were developed
for Java 8, and removes the checks that otherwise will report them as invalid for the target.

It is important to understand that it will use the same code as for Java 12 and won't change
It is important to understand that it will use the same desugaring code as for Java 9+ but won't change
the result's classfile version, because the compilation phase will be done with Java 8 target.

## How to use
Expand Down Expand Up @@ -66,7 +66,7 @@ Jabel has to be added as an annotation processor to your maven-compiler-plugin:
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>13</release>
<release>14</release>
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
Expand All @@ -77,29 +77,33 @@ Jabel has to be added as an annotation processor to your maven-compiler-plugin:
</profile>
</profiles>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<!-- Make sure we're not using Java 9+ APIs -->
<release>8</release>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>com.github.bsideup.jabel</groupId>
<artifactId>jabel-javac-plugin</artifactId>
<version>0.2.0</version>
</annotationProcessorPath>
</annotationProcessorPaths>
<annotationProcessors>
<annotationProcessor>com.github.bsideup.jabel.JabelJavacProcessor</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<!-- Make sure we're not using Java 9+ APIs -->
<release>8</release>
<source>14</source>
<target>14</target>
<compilerArgs>
<arg>-Xplugin:jabel</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>com.github.bsideup.jabel</groupId>
<artifactId>jabel-javac-plugin</artifactId>
<version>0.3.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
```

Compile your project and verify that Jabel is installed and successfully reports:
Expand Down Expand Up @@ -129,19 +133,26 @@ repositories {
Then, add Jabel as any other annotation processor:
```groovy
dependencies {
annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:0.2.0'
annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:0.3.0'
}
```

Now, even if you set source/target/release to 8, the compiler will let you use some new language features.
The full list of features will be printed during the compilation.
```groovy
sourceCompatibility = 12 // for the IDE support
sourceCompatibility = 14 // for the IDE support
compileJava {
tasks.withType(JavaCompile).all {
options.compilerArgs = [
"--release", "8" // Avoid using Java 12 APIs
"--release", "8", // Avoid using Java 9+ APIs
'--enable-preview',
]
doFirst {
options.compilerArgs = options.compilerArgs.findAll {
it != '--enable-preview'
}
}
}
```

Expand Down
15 changes: 8 additions & 7 deletions example/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@ plugins {
id "java"
}

sourceCompatibility = 13
sourceCompatibility = 14
targetCompatibility = 8

compileJava {
tasks.withType(JavaCompile).all {
options.compilerArgs = [
"--release", "8",
'--enable-preview',
]
}

compileTestJava {
options.compilerArgs = [
"--release", "8",
]
doFirst {
options.compilerArgs = options.compilerArgs.findAll {
it != '--enable-preview'
}
}
}

test {
Expand Down
15 changes: 12 additions & 3 deletions example/src/main/java/com/example/JabelExample.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ public String run(String[] args) {
// https://openjdk.java.net/jeps/325
var result = switch (args.length) {
case 1 -> {
yield "one";
yield """
one...
yet pretty long!
""";
}
case 2, 3 -> "two or three";
default -> new JabelExample().new Inner().innerPublic();
Expand All @@ -33,8 +36,14 @@ private String outerPrivate(List<String>... args) {
@Override
public String call() {
// Var in lambda parameter
Function<String, String> function = (var prefix) -> {
return prefix + Integer.toString(0);
Function<Object, String> function = (var prefix) -> {
// Pattern Matching in instanceof
// https://openjdk.java.net/jeps/305
if (prefix instanceof String s) {
return s + Integer.toString(0);
} else {
throw new IllegalArgumentException("Expected string!");
}
};
// Test indy strings
return function.apply("idk ");
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
35 changes: 15 additions & 20 deletions gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
Expand Down Expand Up @@ -125,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
Expand Down Expand Up @@ -154,19 +154,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi

Expand All @@ -175,14 +175,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi

exec "$JAVACMD" "$@"
5 changes: 4 additions & 1 deletion gradlew.bat
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

Expand Down
4 changes: 2 additions & 2 deletions jabel-javac-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ plugins {
sourceCompatibility = targetCompatibility = 8

dependencies {
compile 'net.bytebuddy:byte-buddy:1.10.8'
compile 'net.bytebuddy:byte-buddy-agent:1.10.8'
compile 'net.bytebuddy:byte-buddy:1.10.14'
compile 'net.bytebuddy:byte-buddy-agent:1.10.14'
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.github.bsideup.jabel;

import com.sun.source.util.JavacTask;
import com.sun.source.util.Plugin;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.parser.JavaTokenizer;
import com.sun.tools.javac.parser.JavacParser;
Expand All @@ -8,29 +10,19 @@
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;

import javax.annotation.processing.Completion;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Collections.emptySet;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;

public class JabelJavacProcessor implements Processor {
public class JabelCompilerPlugin implements Plugin {

private static final Set<Source.Feature> ENABLED_FEATURES = Stream
static final Set<Source.Feature> ENABLED_FEATURES = Stream
.of(
"PRIVATE_SAFE_VARARGS",

Expand Down Expand Up @@ -60,7 +52,8 @@ public class JabelJavacProcessor implements Processor {
.filter(Objects::nonNull)
.collect(Collectors.toSet());

static {
@Override
public void init(JavacTask task, String... args) {
ByteBuddyAgent.install();

ByteBuddy byteBuddy = new ByteBuddy();
Expand Down Expand Up @@ -89,15 +82,7 @@ public class JabelJavacProcessor implements Processor {
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.RELEASE_8;
}

@Override
public void init(ProcessingEnvironment processingEnv) {
System.out.println(
ENABLED_FEATURES.stream()
.map(Enum::name)
Expand All @@ -110,22 +95,12 @@ public void init(ProcessingEnvironment processingEnv) {
}

@Override
public Set<String> getSupportedOptions() {
return emptySet();
public String getName() {
return "jabel";
}

@Override
public Set<String> getSupportedAnnotationTypes() {
return emptySet();
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}

@Override
public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) {
return emptySet();
// Make it auto start on Java 14+
public boolean autoStart() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.github.bsideup.jabel.JabelCompilerPlugin
Loading

0 comments on commit c3d9df7

Please sign in to comment.