diff options
author | Mathew Inwood <mathewi@google.com> | 2018-07-26 14:57:08 +0100 |
---|---|---|
committer | Mathew Inwood <mathewi@google.com> | 2018-07-26 15:57:05 +0100 |
commit | f364aedecb6a182d4673dd61f157459cc4d3c1fa (patch) | |
tree | 3049cf661c9957e1d7b6d01e1850db1b9830fca9 | |
parent | 716c04b29a0bd117aab33d8b81621a3fff0af7a7 (diff) |
Remove class2greylist from frameworks/base.
It's moving to a new home under art/tools, since it is needed by
branches which don't include frameworks/base.
Bug: 110868826
Test: Build master-art branch
Change-Id: Ice8324db52ae1e7e2ac6734e45874a66de935c9a
10 files changed, 0 insertions, 732 deletions
diff --git a/tools/hiddenapi/class2greylist/Android.bp b/tools/hiddenapi/class2greylist/Android.bp deleted file mode 100644 index 7b1233bb8535..000000000000 --- a/tools/hiddenapi/class2greylist/Android.bp +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright (C) 2018 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// 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 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -java_library_host { - name: "class2greylistlib", - srcs: ["src/**/*.java"], - static_libs: [ - "commons-cli-1.2", - "apache-bcel", - ], -} - -java_binary_host { - name: "class2greylist", - manifest: "src/class2greylist.mf", - static_libs: [ - "class2greylistlib", - ], -} - diff --git a/tools/hiddenapi/class2greylist/src/class2greylist.mf b/tools/hiddenapi/class2greylist/src/class2greylist.mf deleted file mode 100644 index ea3a3d9153a3..000000000000 --- a/tools/hiddenapi/class2greylist/src/class2greylist.mf +++ /dev/null @@ -1 +0,0 @@ -Main-Class: com.android.class2greylist.Class2Greylist diff --git a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java deleted file mode 100644 index 66857525aa0c..000000000000 --- a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.class2greylist; - -import org.apache.bcel.Const; -import org.apache.bcel.classfile.AnnotationEntry; -import org.apache.bcel.classfile.DescendingVisitor; -import org.apache.bcel.classfile.ElementValuePair; -import org.apache.bcel.classfile.EmptyVisitor; -import org.apache.bcel.classfile.Field; -import org.apache.bcel.classfile.FieldOrMethod; -import org.apache.bcel.classfile.JavaClass; -import org.apache.bcel.classfile.Method; - -import java.util.Locale; - -/** - * Visits a JavaClass instance and pulls out all members annotated with a - * specific annotation. The signatures of such members are passed to {@link - * Status#greylistEntry(String)}. Any errors result in a call to {@link - * Status#error(String)}. - * - * If the annotation has a property "expectedSignature" the generated signature - * will be verified against the one specified there. If it differs, an error - * will be generated. - */ -public class AnnotationVisitor extends EmptyVisitor { - - private static final String EXPECTED_SIGNATURE = "expectedSignature"; - - private final JavaClass mClass; - private final String mAnnotationType; - private final Status mStatus; - private final DescendingVisitor mDescendingVisitor; - - public AnnotationVisitor(JavaClass clazz, String annotation, Status d) { - mClass = clazz; - mAnnotationType = annotation; - mStatus = d; - mDescendingVisitor = new DescendingVisitor(clazz, this); - } - - public void visit() { - mStatus.debug("Visit class %s", mClass.getClassName()); - mDescendingVisitor.visit(); - } - - private static String getClassDescriptor(JavaClass clazz) { - // JavaClass.getName() returns the Java-style name (with . not /), so we must fetch - // the original class name from the constant pool. - return clazz.getConstantPool().getConstantString( - clazz.getClassNameIndex(), Const.CONSTANT_Class); - } - - @Override - public void visitMethod(Method method) { - visitMember(method, "L%s;->%s%s"); - } - - @Override - public void visitField(Field field) { - visitMember(field, "L%s;->%s:%s"); - } - - private void visitMember(FieldOrMethod member, String signatureFormatString) { - JavaClass definingClass = (JavaClass) mDescendingVisitor.predecessor(); - mStatus.debug("Visit member %s : %s", member.getName(), member.getSignature()); - for (AnnotationEntry a : member.getAnnotationEntries()) { - if (mAnnotationType.equals(a.getAnnotationType())) { - mStatus.debug("Method has annotation %s", mAnnotationType); - String signature = String.format(Locale.US, signatureFormatString, - getClassDescriptor(definingClass), member.getName(), member.getSignature()); - for (ElementValuePair property : a.getElementValuePairs()) { - switch (property.getNameString()) { - case EXPECTED_SIGNATURE: - String expected = property.getValue().stringifyValue(); - if (!signature.equals(expected)) { - error(definingClass, member, - "Expected signature does not match generated:\n" - + "Expected: %s\n" - + "Generated: %s", expected, signature); - } - break; - } - } - mStatus.greylistEntry(signature); - } - } - } - - private void error(JavaClass clazz, FieldOrMethod member, String message, Object... args) { - StringBuilder error = new StringBuilder(); - error.append(clazz.getSourceFileName()) - .append(": ") - .append(clazz.getClassName()) - .append(".") - .append(member.getName()) - .append(": ") - .append(String.format(Locale.US, message, args)); - - mStatus.error(error.toString()); - } - -} diff --git a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Class2Greylist.java b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Class2Greylist.java deleted file mode 100644 index 008bf70a2595..000000000000 --- a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Class2Greylist.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.class2greylist; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.GnuParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.cli.PatternOptionBuilder; - -import java.io.IOException; - -/** - * Build time tool for extracting a list of members from jar files that have the @UsedByApps - * annotation, for building the greylist. - */ -public class Class2Greylist { - - private static final String ANNOTATION_TYPE = "Landroid/annotation/UnsupportedAppUsage ;"; - - public static void main(String[] args) { - Options options = new Options(); - options.addOption(OptionBuilder - .withLongOpt("debug") - .hasArgs(0) - .withDescription("Enable debug") - .create("d")); - options.addOption(OptionBuilder - .withLongOpt("help") - .hasArgs(0) - .withDescription("Show this help") - .create("h")); - - CommandLineParser parser = new GnuParser(); - CommandLine cmd; - - try { - cmd = parser.parse(options, args); - } catch (ParseException e) { - System.err.println(e.getMessage()); - help(options); - return; - } - if (cmd.hasOption('h')) { - help(options); - } - - String[] jarFiles = cmd.getArgs(); - if (jarFiles.length == 0) { - System.err.println("Error: no jar files specified."); - help(options); - } - - Status status = new Status(cmd.hasOption('d')); - - for (String jarFile : jarFiles) { - status.debug("Processing jar file %s", jarFile); - try { - JarReader reader = new JarReader(status, jarFile); - reader.stream().forEach(clazz -> new AnnotationVisitor( - clazz, ANNOTATION_TYPE, status).visit()); - reader.close(); - } catch (IOException e) { - status.error(e); - } - } - if (status.ok()) { - System.exit(0); - } else { - System.exit(1); - } - - } - - private static void help(Options options) { - new HelpFormatter().printHelp( - "class2greylist path/to/classes.jar [classes2.jar ...]", - "Extracts greylist entries from classes jar files given", - options, null, true); - System.exit(1); - } -} diff --git a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/JarReader.java b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/JarReader.java deleted file mode 100644 index f3a9d0b92e6c..000000000000 --- a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/JarReader.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.class2greylist; - -import org.apache.bcel.classfile.ClassParser; -import org.apache.bcel.classfile.JavaClass; - -import java.io.IOException; -import java.util.Objects; -import java.util.stream.Stream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * Reads {@link JavaClass} members from a zip/jar file, providing a stream of them for processing. - * Any errors are reported via {@link Status#error(Throwable)}. - */ -public class JarReader { - - private final Status mStatus; - private final String mFileName; - private final ZipFile mZipFile; - - public JarReader(Status s, String filename) throws IOException { - mStatus = s; - mFileName = filename; - mZipFile = new ZipFile(mFileName); - } - - private JavaClass openZipEntry(ZipEntry e) { - try { - mStatus.debug("Reading %s from %s", e.getName(), mFileName); - return new ClassParser(mZipFile.getInputStream(e), e.getName()).parse(); - } catch (IOException ioe) { - mStatus.error(ioe); - return null; - } - } - - - public Stream<JavaClass> stream() { - return mZipFile.stream() - .filter(zipEntry -> zipEntry.getName().endsWith(".class")) - .map(zipEntry -> openZipEntry(zipEntry)) - .filter(Objects::nonNull); - } - - public void close() throws IOException { - mZipFile.close(); - } -} diff --git a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Status.java b/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Status.java deleted file mode 100644 index d7078986d9cd..000000000000 --- a/tools/hiddenapi/class2greylist/src/com/android/class2greylist/Status.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.class2greylist; - -import java.util.Locale; - -public class Status { - - // Highlight "Error:" in red. - private static final String ERROR = "\u001B[31mError: \u001B[0m"; - - private final boolean mDebug; - private boolean mHasErrors; - - public Status(boolean debug) { - mDebug = debug; - } - - public void debug(String msg, Object... args) { - if (mDebug) { - System.err.println(String.format(Locale.US, msg, args)); - } - } - - public void error(Throwable t) { - System.err.print(ERROR); - t.printStackTrace(System.err); - mHasErrors = true; - } - - public void error(String message) { - System.err.print(ERROR); - System.err.println(message); - mHasErrors = true; - } - - public void greylistEntry(String signature) { - System.out.println(signature); - } - - public boolean ok() { - return !mHasErrors; - } -} diff --git a/tools/hiddenapi/class2greylist/test/Android.mk b/tools/hiddenapi/class2greylist/test/Android.mk deleted file mode 100644 index 23f4156f6d03..000000000000 --- a/tools/hiddenapi/class2greylist/test/Android.mk +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2018 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -# Only compile source java files in this apk. -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_MODULE := class2greylisttest - -LOCAL_STATIC_JAVA_LIBRARIES := class2greylistlib truth-host-prebuilt mockito-host junit-host - -# tag this module as a cts test artifact -LOCAL_COMPATIBILITY_SUITE := general-tests - -include $(BUILD_HOST_JAVA_LIBRARY) - -# Build the test APKs using their own makefiles -include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file diff --git a/tools/hiddenapi/class2greylist/test/AndroidTest.xml b/tools/hiddenapi/class2greylist/test/AndroidTest.xml deleted file mode 100644 index 66bb63446f71..000000000000 --- a/tools/hiddenapi/class2greylist/test/AndroidTest.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - 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 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<configuration description="class2greylist tests"> - <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > - <option name="jar" value="class2greylisttest.jar" /> - <option name="runtime-hint" value="1m" /> - </test> -</configuration>
\ No newline at end of file diff --git a/tools/hiddenapi/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java b/tools/hiddenapi/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java deleted file mode 100644 index 2d9721803cac..000000000000 --- a/tools/hiddenapi/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javac; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.android.class2greylist.Status; -import com.android.class2greylist.AnnotationVisitor; - -import com.google.common.base.Joiner; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; - -import java.io.IOException; - -public class AnnotationVisitorTest { - - private static final String ANNOTATION = "Lannotation/Anno;"; - - private Javac mJavac; - @Mock - private Status mStatus; - - @Before - public void setup() throws IOException { - initMocks(this); - mJavac = new Javac(); - mJavac.addSource("annotation.Anno", Joiner.on('\n').join( - "package annotation;", - "import static java.lang.annotation.RetentionPolicy.CLASS;", - "import java.lang.annotation.Retention;", - "import java.lang.annotation.Target;", - "@Retention(CLASS)", - "public @interface Anno {", - " String expectedSignature() default \"\";", - "}")); - } - - private void assertNoErrors() { - verify(mStatus, never()).error(any(Throwable.class)); - verify(mStatus, never()).error(any(String.class)); - } - - @Test - public void testGreylistMethod() throws IOException { - mJavac.addSource("a.b.Class", Joiner.on('\n').join( - "package a.b;", - "import annotation.Anno;", - "public class Class {", - " @Anno", - " public void method() {}", - "}")); - assertThat(mJavac.compile()).isTrue(); - - new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus) - .visit(); - - assertNoErrors(); - ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mStatus, times(1)).greylistEntry(greylist.capture()); - assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method()V"); - } - - @Test - public void testGreylistConstructor() throws IOException { - mJavac.addSource("a.b.Class", Joiner.on('\n').join( - "package a.b;", - "import annotation.Anno;", - "public class Class {", - " @Anno", - " public Class() {}", - "}")); - assertThat(mJavac.compile()).isTrue(); - - new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus) - .visit(); - - assertNoErrors(); - ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mStatus, times(1)).greylistEntry(greylist.capture()); - assertThat(greylist.getValue()).isEqualTo("La/b/Class;-><init>()V"); - } - - @Test - public void testGreylistField() throws IOException { - mJavac.addSource("a.b.Class", Joiner.on('\n').join( - "package a.b;", - "import annotation.Anno;", - "public class Class {", - " @Anno", - " public int i;", - "}")); - assertThat(mJavac.compile()).isTrue(); - - new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus) - .visit(); - - assertNoErrors(); - ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mStatus, times(1)).greylistEntry(greylist.capture()); - assertThat(greylist.getValue()).isEqualTo("La/b/Class;->i:I"); - } - - @Test - public void testGreylistMethodExpectedSignature() throws IOException { - mJavac.addSource("a.b.Class", Joiner.on('\n').join( - "package a.b;", - "import annotation.Anno;", - "public class Class {", - " @Anno(expectedSignature=\"La/b/Class;->method()V\")", - " public void method() {}", - "}")); - assertThat(mJavac.compile()).isTrue(); - - new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus) - .visit(); - - assertNoErrors(); - ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mStatus, times(1)).greylistEntry(greylist.capture()); - assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method()V"); - } - - @Test - public void testGreylistMethodExpectedSignatureWrong() throws IOException { - mJavac.addSource("a.b.Class", Joiner.on('\n').join( - "package a.b;", - "import annotation.Anno;", - "public class Class {", - " @Anno(expectedSignature=\"La/b/Class;->nomethod()V\")", - " public void method() {}", - "}")); - assertThat(mJavac.compile()).isTrue(); - - new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus) - .visit(); - - verify(mStatus, times(1)).error(any(String.class)); - } - - @Test - public void testGreylistInnerClassMethod() throws IOException { - mJavac.addSource("a.b.Class", Joiner.on('\n').join( - "package a.b;", - "import annotation.Anno;", - "public class Class {", - " public class Inner {", - " @Anno", - " public void method() {}", - " }", - "}")); - assertThat(mJavac.compile()).isTrue(); - - new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class$Inner"), ANNOTATION, - mStatus).visit(); - - assertNoErrors(); - ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class); - verify(mStatus, times(1)).greylistEntry(greylist.capture()); - assertThat(greylist.getValue()).isEqualTo("La/b/Class$Inner;->method()V"); - } - - @Test - public void testMethodNotGreylisted() throws IOException { - mJavac.addSource("a.b.Class", Joiner.on('\n').join( - "package a.b;", - "public class Class {", - " public void method() {}", - "}")); - assertThat(mJavac.compile()).isTrue(); - - new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus) - .visit(); - - assertNoErrors(); - verify(mStatus, never()).greylistEntry(any(String.class)); - } - -} diff --git a/tools/hiddenapi/class2greylist/test/src/com/android/javac/Javac.java b/tools/hiddenapi/class2greylist/test/src/com/android/javac/Javac.java deleted file mode 100644 index 202f4121fc60..000000000000 --- a/tools/hiddenapi/class2greylist/test/src/com/android/javac/Javac.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javac; - -import com.google.common.io.Files; - -import org.apache.bcel.classfile.ClassParser; -import org.apache.bcel.classfile.JavaClass; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - -import javax.tools.DiagnosticCollector; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.StandardLocation; -import javax.tools.ToolProvider; - -/** - * Helper class for compiling snippets of Java source and providing access to the resulting class - * files. - */ -public class Javac { - - private final JavaCompiler mJavac; - private final StandardJavaFileManager mFileMan; - private final List<JavaFileObject> mCompilationUnits; - private final File mClassOutDir; - - public Javac() throws IOException { - mJavac = ToolProvider.getSystemJavaCompiler(); - mFileMan = mJavac.getStandardFileManager(null, Locale.US, null); - mClassOutDir = Files.createTempDir(); - mFileMan.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(mClassOutDir)); - mFileMan.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(mClassOutDir)); - mCompilationUnits = new ArrayList<>(); - } - - private String classToFileName(String classname) { - return classname.replace('.', '/'); - } - - public Javac addSource(String classname, String contents) { - JavaFileObject java = new SimpleJavaFileObject(URI.create( - String.format("string:///%s.java", classToFileName(classname))), - JavaFileObject.Kind.SOURCE - ){ - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - return contents; - } - }; - mCompilationUnits.add(java); - return this; - } - - public boolean compile() { - JavaCompiler.CompilationTask task = mJavac.getTask( - null, - mFileMan, - null, - null, - null, - mCompilationUnits); - return task.call(); - } - - public InputStream getClassFile(String classname) throws IOException { - Iterable<? extends JavaFileObject> objs = mFileMan.getJavaFileObjects( - new File(mClassOutDir, String.format("%s.class", classToFileName(classname)))); - if (!objs.iterator().hasNext()) { - return null; - } - return objs.iterator().next().openInputStream(); - } - - public JavaClass getCompiledClass(String classname) throws IOException { - return new ClassParser(getClassFile(classname), - String.format("%s.class", classToFileName(classname))).parse(); - } -} |