summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/AbstractTestTools.java31
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/IToolchain.java5
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/JackApiV01Toolchain.java15
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/JackBasedToolchain.java30
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/JackCliToolchain.java37
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/LegacyJillToolchain.java4
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/LegacyToolchain.java11
-rw-r--r--jack-tests/src/com/android/jack/test/toolchain/Toolchain.java9
-rw-r--r--jack-tests/tests/com/android/jack/annotation/processor/AnnotationProcessorTests.java292
-rw-r--r--jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated1.java24
-rw-r--r--jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated2.java24
-rw-r--r--jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated3.java21
-rw-r--r--jack-tests/tests/com/android/jack/annotation/processor/sample/annotations/ResourceAnnotationTest.java29
-rw-r--r--jack-tests/tests/com/android/jack/annotation/processor/sample/annotations/SourceAnnotationTest.java29
-rw-r--r--jack-tests/tests/com/android/jack/annotation/processor/sample/processors/ResourceAnnotationProcessor.java142
-rw-r--r--jack-tests/tests/com/android/jack/annotation/processor/sample/processors/SourceAnnotationProcessor.java110
-rw-r--r--jack-tests/tests/com/android/jack/annotation/processor/sample/processors/javax.annotation.processing.Processor2
-rw-r--r--jack-tests/tests/com/android/jack/classpath/ClasspathTests.java1
-rw-r--r--jack-tests/tests/com/android/jack/error/AnnotationProcessorErrorTest.java70
-rw-r--r--jack-tests/tests/com/android/jack/error/FileAccessErrorTest.java1
-rw-r--r--jack-tests/tests/com/android/jack/fileconflict/FileConflictTests.java84
-rw-r--r--jack/src/com/android/jack/Options.java143
-rw-r--r--jack/src/com/android/jack/api/v01/impl/Api01ConfigImpl.java9
-rw-r--r--jack/src/com/android/jack/frontend/java/EcjLogger.java18
-rw-r--r--jack/src/com/android/jack/frontend/java/JackBatchCompiler.java62
-rw-r--r--jack/src/com/android/jack/ir/ast/JSession.java1
-rw-r--r--jack/src/com/android/jack/reporting/CommonReporter.java3
-rw-r--r--jack/src/com/android/jack/resource/ResourceImporter.java5
-rw-r--r--jack/src/com/android/jack/util/ClassNameCodec.java79
-rw-r--r--jack/src/com/android/jack/util/NamingTools.java11
-rw-r--r--jack/tests/com/android/jack/TestTools.java12
-rw-r--r--jack/tests/com/android/jack/errorhandling/annotationprocessor/ResourceAnnotationProcessor.java6
-rw-r--r--sched/src/com/android/sched/util/RunnableHooks.java10
-rw-r--r--sched/src/com/android/sched/util/codec/InputFileOrDirectoryCodec.java84
-rw-r--r--sched/src/com/android/sched/util/codec/ListCodec.java7
-rw-r--r--sched/src/com/android/sched/util/codec/ListParsingException.java2
-rw-r--r--sched/src/com/android/sched/util/codec/PairCodec.java167
-rw-r--r--sched/src/com/android/sched/util/codec/PairListToMapCodecConverter.java60
-rw-r--r--sched/src/com/android/sched/util/codec/StringValueCodec.java69
-rw-r--r--sched/src/com/android/sched/util/config/id/EnumPropertyId.java8
-rw-r--r--sched/src/com/android/sched/util/config/id/ListPropertyId.java2
41 files changed, 1542 insertions, 187 deletions
diff --git a/jack-tests/src/com/android/jack/test/toolchain/AbstractTestTools.java b/jack-tests/src/com/android/jack/test/toolchain/AbstractTestTools.java
index be3414b..13fc5bf 100644
--- a/jack-tests/src/com/android/jack/test/toolchain/AbstractTestTools.java
+++ b/jack-tests/src/com/android/jack/test/toolchain/AbstractTestTools.java
@@ -27,10 +27,12 @@ import com.android.jack.test.runner.RuntimeRunnerFactory;
import com.android.jack.test.util.ExecFileException;
import com.android.jack.test.util.ExecuteFile;
import com.android.jack.util.NamingTools;
+import com.android.sched.util.stream.ByteStreamSucker;
import org.junit.Assume;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@@ -583,4 +585,33 @@ public abstract class AbstractTestTools {
return rtLocation;
}
+ public static void copyFileToDir(@Nonnull File fileToCopy, @Nonnull String relativePath,
+ @Nonnull File dest) throws IOException {
+ FileOutputStream fos = null;
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(fileToCopy);
+ File copiedFile = new File(dest, relativePath);
+ File parentDir = copiedFile.getParentFile();
+ if (!parentDir.exists()) {
+ boolean res = parentDir.mkdirs();
+ if (!res) {
+ throw new AssertionError();
+ }
+ }
+ try {
+ fos = new FileOutputStream(copiedFile);
+ ByteStreamSucker sucker = new ByteStreamSucker(fis, fos);
+ sucker.suck();
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } finally {
+ if (fis != null) {
+ fis.close();
+ }
+ }
+ }
}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/IToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/IToolchain.java
index 7fa2620..fb97ef6 100644
--- a/jack-tests/src/com/android/jack/test/toolchain/IToolchain.java
+++ b/jack-tests/src/com/android/jack/test/toolchain/IToolchain.java
@@ -23,7 +23,6 @@ import java.io.OutputStream;
import java.util.List;
import javax.annotation.Nonnull;
-import javax.annotation.processing.Processor;
/**
@@ -69,8 +68,8 @@ public interface IToolchain {
IToolchain setWithDebugInfos(boolean withDebugInfos);
@Nonnull
- IToolchain setAnnotationProcessorClass(
- @Nonnull Class<? extends Processor> annotationProcessorClass);
+ IToolchain setAnnotationProcessorClasses(
+ @Nonnull List<String> annotationProcessorClasses);
@Nonnull
IToolchain setSourceLevel(@Nonnull SourceLevel sourceLevel);
diff --git a/jack-tests/src/com/android/jack/test/toolchain/JackApiV01Toolchain.java b/jack-tests/src/com/android/jack/test/toolchain/JackApiV01Toolchain.java
index 2d7f6f2..52e4b3f 100644
--- a/jack-tests/src/com/android/jack/test/toolchain/JackApiV01Toolchain.java
+++ b/jack-tests/src/com/android/jack/test/toolchain/JackApiV01Toolchain.java
@@ -16,6 +16,7 @@
package com.android.jack.test.toolchain;
+import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.android.jack.Options;
@@ -194,6 +195,20 @@ public class JackApiV01Toolchain extends JackApiToolchainBase {
if (jarjarRules != null) {
apiV01Config.setJarJarConfigFile(jarjarRules);
}
+ apiV01Config.setProcessorOptions(annotationProcessorOptions);
+
+ if (annotationProcessorClasses != null) {
+ apiV01Config.setProcessorNames(annotationProcessorClasses);
+ }
+
+
+ if (processorPath != null) {
+ List<File> fileList = new ArrayList<File>();
+ for (String entry : Splitter.on(File.pathSeparatorChar).split(processorPath)) {
+ fileList.add(new File(entry));
+ }
+ apiV01Config.setProcessorPath(fileList);
+ }
}
private void libToCommon(@Nonnull File... in) throws Exception {
diff --git a/jack-tests/src/com/android/jack/test/toolchain/JackBasedToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/JackBasedToolchain.java
index 34610eb..a08fe71 100644
--- a/jack-tests/src/com/android/jack/test/toolchain/JackBasedToolchain.java
+++ b/jack-tests/src/com/android/jack/test/toolchain/JackBasedToolchain.java
@@ -23,7 +23,9 @@ import com.android.jack.test.TestsProperties;
import java.io.File;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -42,16 +44,31 @@ public abstract class JackBasedToolchain extends AndroidToolchain {
LEGACY
}
-
- @CheckForNull
- protected File annotationProcessorOutDir;
@Nonnull
protected List<File> resImport = new ArrayList<File>();
+ @Nonnull
+ protected final Map<String, String> annotationProcessorOptions = new HashMap<String, String>();
+ @CheckForNull
+ protected String processorPath;
@Nonnull
public abstract JackBasedToolchain addProperty(@Nonnull String propertyName,
@Nonnull String propertyValue);
+ @Nonnull
+ public final JackBasedToolchain addAnnotationProcessorOption(@Nonnull String propertyName,
+ @Nonnull String propertyValue) {
+ annotationProcessorOptions.put(propertyName, propertyValue);
+ return this;
+ }
+
+ @Nonnull
+ public final JackBasedToolchain setAnnotationProcessorPath(
+ @Nonnull String processorPath) {
+ this.processorPath = processorPath;
+ return this;
+ }
+
public final JackBasedToolchain setMultiDexKind(@Nonnull MultiDexKind kind) {
switch (kind) {
case NATIVE:
@@ -75,13 +92,6 @@ public abstract class JackBasedToolchain extends AndroidToolchain {
return this;
}
- @Nonnull
- public final JackBasedToolchain setAnnotationProcessorOutDir(
- @Nonnull File annotationProcessorOutDir) {
- this.annotationProcessorOutDir = annotationProcessorOutDir;
- return this;
- }
-
@Override
@Nonnull
public JackBasedToolchain setSourceLevel(@Nonnull SourceLevel sourceLevel) {
diff --git a/jack-tests/src/com/android/jack/test/toolchain/JackCliToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/JackCliToolchain.java
index 3542d03..c68edda 100644
--- a/jack-tests/src/com/android/jack/test/toolchain/JackCliToolchain.java
+++ b/jack-tests/src/com/android/jack/test/toolchain/JackCliToolchain.java
@@ -16,6 +16,8 @@
package com.android.jack.test.toolchain;
+import com.google.common.base.Joiner;
+
import com.android.jack.Options;
import com.android.jack.Options.VerbosityLevel;
import com.android.jack.util.ExecuteFile;
@@ -82,15 +84,6 @@ public class JackCliToolchain extends JackBasedToolchain {
args.add("-g");
}
- if (annotationProcessorClass != null) {
- args.add("-processor");
- args.add(annotationProcessorClass.getName());
- }
- if (annotationProcessorOutDir != null) {
- args.add("-d");
- args.add(annotationProcessorOutDir.getAbsolutePath());
- }
-
AbstractTestTools.addFile(args, /* mustExist = */ false, sources);
ExecuteFile exec = new ExecuteFile(args.toArray(new String[args.size()]));
@@ -178,14 +171,7 @@ public class JackCliToolchain extends JackBasedToolchain {
args.add("-g");
}
- if (annotationProcessorClass != null) {
- args.add("-processor");
- args.add(annotationProcessorClass.getName());
- }
- if (annotationProcessorOutDir != null) {
- args.add("-d");
- args.add(annotationProcessorOutDir.getAbsolutePath());
- }
+ addAnnotationProcessorArgs(args);
for (File staticLib : staticLibs) {
args.add("--import");
@@ -335,4 +321,21 @@ public class JackCliToolchain extends JackBasedToolchain {
return this;
}
+ private void addAnnotationProcessorArgs(@Nonnull List<String> args) {
+ for (Entry<String, String> entry : annotationProcessorOptions.entrySet()) {
+ args.add("-A");
+ args.add(entry.getKey() + "=" + entry.getValue());
+ }
+
+ if (annotationProcessorClasses != null) {
+ args.add("--processor");
+ args.add(Joiner.on(',').join(annotationProcessorClasses));
+ }
+
+ if (processorPath != null) {
+ args.add("--processorpath");
+ args.add(processorPath);
+ }
+ }
+
}
diff --git a/jack-tests/src/com/android/jack/test/toolchain/LegacyJillToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/LegacyJillToolchain.java
index f35e053..489ef52 100644
--- a/jack-tests/src/com/android/jack/test/toolchain/LegacyJillToolchain.java
+++ b/jack-tests/src/com/android/jack/test/toolchain/LegacyJillToolchain.java
@@ -307,9 +307,9 @@ public class LegacyJillToolchain extends JillBasedToolchain {
addSourceLevel(sourceLevel, arguments);
- if (annotationProcessorClass != null) {
+ if (annotationProcessorClasses != null) {
arguments.add("-processor");
- arguments.add(annotationProcessorClass.getName());
+ arguments.add(Joiner.on(',').join(annotationProcessorClasses));
}
arguments.add("-bootclasspath");
diff --git a/jack-tests/src/com/android/jack/test/toolchain/LegacyToolchain.java b/jack-tests/src/com/android/jack/test/toolchain/LegacyToolchain.java
index 809393f..7a94bd8 100644
--- a/jack-tests/src/com/android/jack/test/toolchain/LegacyToolchain.java
+++ b/jack-tests/src/com/android/jack/test/toolchain/LegacyToolchain.java
@@ -16,6 +16,8 @@
package com.android.jack.test.toolchain;
+import com.google.common.base.Joiner;
+
import com.android.dx.command.dexer.Main.Arguments;
import com.android.jack.test.TestsProperties;
import com.android.jack.test.util.ExecFileException;
@@ -228,6 +230,11 @@ public class LegacyToolchain extends AndroidToolchain {
}
addSourceLevel(sourceLevel, args);
+ if (annotationProcessorClasses != null) {
+ args.add("-processor");
+ args.add(Joiner.on(',').join(annotationProcessorClasses));
+ }
+
args.add("-encoding");
args.add("utf8");
@@ -283,9 +290,9 @@ public class LegacyToolchain extends AndroidToolchain {
arguments.add("-encoding");
arguments.add("utf8");
- if (annotationProcessorClass != null) {
+ if (annotationProcessorClasses != null) {
arguments.add("-processor");
- arguments.add(annotationProcessorClass.getName());
+ arguments.add(Joiner.on(',').join(annotationProcessorClasses));
}
arguments.add("-bootclasspath");
diff --git a/jack-tests/src/com/android/jack/test/toolchain/Toolchain.java b/jack-tests/src/com/android/jack/test/toolchain/Toolchain.java
index cf2ed55..131b055 100644
--- a/jack-tests/src/com/android/jack/test/toolchain/Toolchain.java
+++ b/jack-tests/src/com/android/jack/test/toolchain/Toolchain.java
@@ -27,7 +27,6 @@ import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
-import javax.annotation.processing.Processor;
/**
* A toolchain the ouptut of which can be redirected to user defined streams.
@@ -40,7 +39,7 @@ public abstract class Toolchain implements IToolchain {
protected List<File> classpath = new ArrayList<File>();
@CheckForNull
- protected Class<? extends Processor> annotationProcessorClass;
+ protected List<String> annotationProcessorClasses;
/**
* Java source level.
@@ -125,9 +124,9 @@ public abstract class Toolchain implements IToolchain {
@Override
@Nonnull
- public final Toolchain setAnnotationProcessorClass(
- @Nonnull Class<? extends Processor> annotationProcessorClass) {
- this.annotationProcessorClass = annotationProcessorClass;
+ public final Toolchain setAnnotationProcessorClasses(
+ @Nonnull List<String> annotationProcessorClasses) {
+ this.annotationProcessorClasses = annotationProcessorClasses;
return this;
}
diff --git a/jack-tests/tests/com/android/jack/annotation/processor/AnnotationProcessorTests.java b/jack-tests/tests/com/android/jack/annotation/processor/AnnotationProcessorTests.java
new file mode 100644
index 0000000..2d4be98
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/processor/AnnotationProcessorTests.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2014 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.jack.annotation.processor;
+
+import com.android.jack.annotation.processor.sample.processors.ResourceAnnotationProcessor;
+import com.android.jack.annotation.processor.sample.processors.SourceAnnotationProcessor;
+import com.android.jack.library.FileType;
+import com.android.jack.library.FileTypeDoesNotExistException;
+import com.android.jack.library.InputJackLibrary;
+import com.android.jack.library.JackLibraryFactory;
+import com.android.jack.test.toolchain.AbstractTestTools;
+import com.android.jack.test.toolchain.JackBasedToolchain;
+import com.android.jack.test.toolchain.LegacyToolchain;
+import com.android.jack.test.toolchain.Toolchain;
+import com.android.sched.util.config.ConfigurationException;
+import com.android.sched.util.config.GatherConfigBuilder;
+import com.android.sched.util.config.ThreadConfig;
+import com.android.sched.util.file.Directory;
+import com.android.sched.util.file.FileOrDirectory.ChangePermission;
+import com.android.sched.util.file.FileOrDirectory.Existence;
+import com.android.sched.util.file.FileOrDirectory.Permission;
+import com.android.sched.vfs.DirectFS;
+import com.android.sched.vfs.VPath;
+
+import junit.framework.Assert;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.Collections;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+public class AnnotationProcessorTests {
+
+ @Nonnull
+ private static final File ANNOTATED_DIR = AbstractTestTools.getTestRootDir(
+ "com.android.jack.annotation.processor.sample.annotated");
+ @Nonnull
+ private static final File ANNOTATIONS_DIR = AbstractTestTools.getTestRootDir(
+ "com.android.jack.annotation.processor.sample.annotations");
+
+ @CheckForNull
+ private static File noConfigProcessors;
+
+ @CheckForNull
+ private static File autoProcessors;
+
+ @BeforeClass
+ public static void setupClass() throws ConfigurationException {
+ // required for creating InputJackLibrary when running tests on cli
+ ThreadConfig.setConfig(new GatherConfigBuilder().build());
+ noConfigProcessors = null;
+ autoProcessors = null;
+ }
+
+ @Nonnull
+ private static File getNoConfigProcessors() throws Exception {
+ if (noConfigProcessors == null) {
+ Toolchain toolchain = AbstractTestTools.getReferenceToolchain();
+ File processorsDir = AbstractTestTools.createTempDir();
+ File processorsSrcDir = AbstractTestTools.getTestRootDir(
+ "com.android.jack.annotation.processor.sample.processors");
+ toolchain.srcToLib(processorsDir, /*zipFiles=*/ false,
+ ANNOTATIONS_DIR,
+ processorsSrcDir
+ );
+ noConfigProcessors = processorsDir;
+ }
+ return noConfigProcessors;
+ }
+
+ @Nonnull
+ private static File getAutoProcessors() throws Exception {
+ if (autoProcessors == null) {
+ Toolchain toolchain = AbstractTestTools.getReferenceToolchain();
+ File processorsDir = AbstractTestTools.createTempDir();
+ File processorsSrcDir = AbstractTestTools.getTestRootDir(
+ "com.android.jack.annotation.processor.sample.processors");
+ toolchain.srcToLib(processorsDir, /*zipFiles=*/ false,
+ ANNOTATIONS_DIR,
+ processorsSrcDir
+ );
+ AbstractTestTools.copyFileToDir(new File(processorsSrcDir,
+ "javax.annotation.processing.Processor"),
+ "META-INF/services/javax.annotation.processing.Processor", processorsDir);
+ autoProcessors = processorsDir;
+ }
+ return autoProcessors;
+ }
+
+ @Test
+ public void compileWithAnnotationProcessorAuto_classpath() throws Exception {
+ JackBasedToolchain jack = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ File jackOut = AbstractTestTools.createTempDir();
+ File processors = getAutoProcessors();
+ jack.addToClasspath(jack.getDefaultBootClasspath());
+ jack.addToClasspath(processors);
+ jack.srcToLib(jackOut, /*zipFiles=*/false,
+ ANNOTATIONS_DIR,
+ ANNOTATED_DIR
+ );
+ InputJackLibrary libOut =
+ JackLibraryFactory.getInputLibrary(
+ new DirectFS(new Directory(jackOut.getPath(), /* hooks = */ null,
+ Existence.MUST_EXIST, Permission.READ, ChangePermission.NOCHANGE),
+ Permission.READ));
+ libOut.getFile(FileType.RSC, new VPath("rscGeneratedFile0", '/'));
+ libOut.getFile(FileType.JAYCE, new VPath("Annotated2Duplicated", '/'));
+ }
+
+ @Test
+ public void compileWithAnnotationProcessorAuto_processorPath() throws Exception {
+ JackBasedToolchain jack = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ File jackOut = AbstractTestTools.createTempDir();
+ File processors = getAutoProcessors();
+ jack.setAnnotationProcessorPath(processors.getPath());
+ jack.addToClasspath(jack.getDefaultBootClasspath());
+ jack.srcToLib(jackOut,
+ /*zipFiles=*/false,
+ ANNOTATIONS_DIR,
+ ANNOTATED_DIR
+ );
+ InputJackLibrary libOut =
+ JackLibraryFactory.getInputLibrary(
+ new DirectFS(new Directory(jackOut.getPath(), /* hooks = */ null,
+ Existence.MUST_EXIST, Permission.READ, ChangePermission.NOCHANGE),
+ Permission.READ));
+ libOut.getFile(FileType.RSC, new VPath("rscGeneratedFile0", '/'));
+ libOut.getFile(FileType.JAYCE, new VPath("Annotated2Duplicated", '/'));
+ }
+
+ @Test
+ public void compileWithAnnotationProcessorNoAuto_processorPath() throws Exception {
+ JackBasedToolchain jack = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ File jackOut = AbstractTestTools.createTempDir();
+ File processors = getNoConfigProcessors();
+ jack.setAnnotationProcessorPath(processors.getPath());
+ jack.setAnnotationProcessorClasses(
+ Collections.singletonList(ResourceAnnotationProcessor.class.getName()));
+ jack.addToClasspath(jack.getDefaultBootClasspath());
+ jack.srcToLib(jackOut,
+ /*zipFiles=*/false,
+ ANNOTATIONS_DIR,
+ ANNOTATED_DIR
+ );
+ InputJackLibrary libOut =
+ JackLibraryFactory.getInputLibrary(
+ new DirectFS(new Directory(jackOut.getPath(), /* hooks = */ null,
+ Existence.MUST_EXIST, Permission.READ, ChangePermission.NOCHANGE),
+ Permission.READ));
+ libOut.getFile(FileType.RSC, new VPath("rscGeneratedFile0", '/'));
+ try {
+ libOut.getFile(FileType.JAYCE, new VPath("Annotated2Duplicated", '/'));
+ Assert.fail();
+ } catch (FileTypeDoesNotExistException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void compileWithAnnotationProcessorNoAutoNoClasses_processorPath() throws Exception {
+ JackBasedToolchain jack = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ File jackOut = AbstractTestTools.createTempDir();
+ File processors = getNoConfigProcessors();
+ jack.setAnnotationProcessorPath(processors.getPath());
+ jack.addToClasspath(jack.getDefaultBootClasspath());
+ jack.srcToLib(jackOut,
+ /*zipFiles=*/false,
+ ANNOTATIONS_DIR,
+ ANNOTATED_DIR
+ );
+ InputJackLibrary libOut =
+ JackLibraryFactory.getInputLibrary(
+ new DirectFS(new Directory(jackOut.getPath(), /* hooks = */ null,
+ Existence.MUST_EXIST, Permission.READ, ChangePermission.NOCHANGE),
+ Permission.READ));
+ try {
+ libOut.getFile(FileType.RSC, new VPath("rscGeneratedFile0", '/'));
+ Assert.fail();
+ } catch (FileTypeDoesNotExistException e) {
+ // expected
+ }
+ try {
+ libOut.getFile(FileType.JAYCE, new VPath("Annotated2Duplicated", '/'));
+ Assert.fail();
+ } catch (FileTypeDoesNotExistException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void compileWithAnnotationProcessorNoAuto_classpath() throws Exception {
+ JackBasedToolchain jack = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ File jackOut = AbstractTestTools.createTempDir();
+ File processors = getNoConfigProcessors();
+ jack.setAnnotationProcessorClasses(
+ Collections.singletonList(SourceAnnotationProcessor.class.getName()));
+ jack.addToClasspath(jack.getDefaultBootClasspath());
+ jack.addToClasspath(processors);
+ jack.srcToLib(jackOut, /*zipFiles=*/false,
+ ANNOTATIONS_DIR,
+ ANNOTATED_DIR
+ );
+ InputJackLibrary libOut =
+ JackLibraryFactory.getInputLibrary(
+ new DirectFS(new Directory(jackOut.getPath(), /* hooks = */ null,
+ Existence.MUST_EXIST, Permission.READ, ChangePermission.NOCHANGE),
+ Permission.READ));
+ try {
+ libOut.getFile(FileType.RSC, new VPath("rscGeneratedFile0", '/'));
+ Assert.fail();
+ } catch (FileTypeDoesNotExistException e) {
+ // expected
+ }
+ libOut.getFile(FileType.JAYCE, new VPath("Annotated2Duplicated", '/'));
+ }
+
+ @Test
+ public void compileWithAnnotationProcessorReuseClassOut() throws Exception {
+ File classesOut = AbstractTestTools.createTempDir();
+ File jackOut = AbstractTestTools.createTempDir();
+ File processors = getAutoProcessors();
+ {
+ JackBasedToolchain jack = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ jack.setAnnotationProcessorPath(processors.getPath());
+ jack.addResource(classesOut);
+ jack.addToClasspath(jack.getDefaultBootClasspath());
+ jack.srcToLib(jackOut,
+ /*zipFiles=*/false,
+ ANNOTATIONS_DIR,
+ ANNOTATED_DIR
+ );
+ }
+ {
+ JackBasedToolchain jack = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ jack.setAnnotationProcessorPath(processors.getPath());
+ jack.addResource(classesOut);
+ jack.addToClasspath(jack.getDefaultBootClasspath());
+ jack.srcToLib(jackOut,
+ /*zipFiles=*/false,
+ ANNOTATIONS_DIR,
+ ANNOTATED_DIR
+ );
+ }
+ InputJackLibrary libOut =
+ JackLibraryFactory.getInputLibrary(
+ new DirectFS(new Directory(jackOut.getPath(), /* hooks = */ null,
+ Existence.MUST_EXIST, Permission.READ, ChangePermission.NOCHANGE),
+ Permission.READ));
+ libOut.getFile(FileType.RSC, new VPath("rscGeneratedFile0", '/'));
+ libOut.getFile(FileType.RSC, new VPath("rscGeneratedFile1", '/'));
+ libOut.getFile(FileType.JAYCE, new VPath("Annotated2Duplicated", '/'));
+ }
+
+ @Test
+ public void compileWithAnnotationProcessorOption() throws Exception {
+ JackBasedToolchain jack = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
+ File jackOut = AbstractTestTools.createTempDir();
+ File processors = getAutoProcessors();
+ jack.addAnnotationProcessorOption(
+ SourceAnnotationProcessor.SOURCE_ANNOTATION_PROCESSOR_SUFFIX, "WithOption");
+ jack.addToClasspath(jack.getDefaultBootClasspath());
+ jack.addToClasspath(processors);
+ jack.srcToLib(jackOut, /*zipFiles=*/false,
+ ANNOTATIONS_DIR,
+ ANNOTATED_DIR
+ );
+ InputJackLibrary libOut =
+ JackLibraryFactory.getInputLibrary(
+ new DirectFS(new Directory(jackOut.getPath(), /* hooks = */ null,
+ Existence.MUST_EXIST, Permission.READ, ChangePermission.NOCHANGE),
+ Permission.READ));
+ libOut.getFile(FileType.JAYCE, new VPath("Annotated2WithOption", '/'));
+ }
+}
diff --git a/jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated1.java b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated1.java
new file mode 100644
index 0000000..1e5fed6
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated1.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 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.jack.annotation.processor.sample.annotated;
+
+import com.android.jack.annotation.processor.sample.annotations.ResourceAnnotationTest;
+
+@ResourceAnnotationTest
+public class Annotated1 {
+
+}
diff --git a/jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated2.java b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated2.java
new file mode 100644
index 0000000..c5c00aa
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated2.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 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.jack.annotation.processor.sample.annotated;
+
+import com.android.jack.annotation.processor.sample.annotations.SourceAnnotationTest;
+
+@SourceAnnotationTest
+public class Annotated2 {
+
+}
diff --git a/jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated3.java b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated3.java
new file mode 100644
index 0000000..bd47b55
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotated/Annotated3.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 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.jack.annotation.processor.sample.annotated;
+
+public class Annotated3 {
+
+}
diff --git a/jack-tests/tests/com/android/jack/annotation/processor/sample/annotations/ResourceAnnotationTest.java b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotations/ResourceAnnotationTest.java
new file mode 100644
index 0000000..48b88ef
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotations/ResourceAnnotationTest.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 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.jack.annotation.processor.sample.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a class or interface with an annotation used by tests.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ResourceAnnotationTest {}
diff --git a/jack-tests/tests/com/android/jack/annotation/processor/sample/annotations/SourceAnnotationTest.java b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotations/SourceAnnotationTest.java
new file mode 100644
index 0000000..54b6957
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/processor/sample/annotations/SourceAnnotationTest.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 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.jack.annotation.processor.sample.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a class or interface with an annotation used by tests to generate source code.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface SourceAnnotationTest {}
diff --git a/jack-tests/tests/com/android/jack/annotation/processor/sample/processors/ResourceAnnotationProcessor.java b/jack-tests/tests/com/android/jack/annotation/processor/sample/processors/ResourceAnnotationProcessor.java
new file mode 100644
index 0000000..d6c61d7
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/processor/sample/processors/ResourceAnnotationProcessor.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2014 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.jack.annotation.processor.sample.processors;
+
+import com.android.jack.annotation.processor.sample.annotations.ResourceAnnotationTest;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.FileObject;
+import javax.tools.StandardLocation;
+
+/**
+ * Annotation processor generating a dedicated resource file called {@code rscGeneratedFile}.
+ */
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+@SupportedAnnotationTypes("*")
+public class ResourceAnnotationProcessor extends AbstractProcessor {
+ @CheckForNull
+ private ProcessingEnvironment env;
+
+ @Nonnull
+ private final List<String> data = new ArrayList<String>();
+
+ @Nonnull
+ public final static String FILENAME = "rscGeneratedFile";
+
+ @Override
+ public synchronized void init(@Nonnull ProcessingEnvironment env) {
+ this.env = env;
+ try {
+ env.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", FILENAME);
+ } catch (IOException e) {
+ // Best effort
+ }
+ }
+
+ @Override
+ public boolean process(@Nonnull Set<? extends TypeElement> annotations,
+ @Nonnull RoundEnvironment roundEnv) {
+ assert env != null;
+ env.getMessager().printMessage(Kind.NOTE,
+ "ResourceAnnotationProcessor.process");
+ if (roundEnv.processingOver()) {
+ try {
+ assert env != null;
+
+ int count = 0;
+ while (true) {
+ try {
+ FileObject fo = env.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", FILENAME + count);
+ fo.openInputStream().close();
+ count ++;
+ } catch (IOException e) {
+ break;
+ }
+ }
+ OutputStream os = env.getFiler()
+ .createResource(StandardLocation.CLASS_OUTPUT, "", FILENAME + count)
+ .openOutputStream();
+ Writer writer = new OutputStreamWriter(os);
+ try {
+ for (String val : data) {
+ writer.write(val);
+ writer.write("\n");
+ }
+ } finally {
+ writer.close();
+ }
+ } catch (IOException e) {
+ env.getMessager().printMessage(Kind.ERROR,
+ "Can not write resource file for '" + FILENAME + "': " + e.getMessage());
+ }
+ } else {
+ //
+ // @ResourceAnnotationTest
+ //
+
+ for (Element element : getElementsAnnotatedWith(roundEnv, ResourceAnnotationTest.class)) {
+ assert data != null;
+
+ TypeMirror type = element.asType();
+
+ if (type.getKind() == TypeKind.DECLARED) {
+ data.add(ResourceAnnotationTest.class.getCanonicalName());
+ assert env != null;
+ data.add(env.getElementUtils().getBinaryName((TypeElement) element).toString());
+
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @Nonnull
+ private Set<? extends Element> getElementsAnnotatedWith(@Nonnull RoundEnvironment roundEnv,
+ @Nonnull Class<? extends Annotation> cls) {
+ assert env != null;
+
+ String name = cls.getCanonicalName();
+ assert name != null;
+
+ TypeElement element = env.getElementUtils().getTypeElement(name);
+ assert element != null;
+
+ return roundEnv.getElementsAnnotatedWith(element);
+ }
+}
diff --git a/jack-tests/tests/com/android/jack/annotation/processor/sample/processors/SourceAnnotationProcessor.java b/jack-tests/tests/com/android/jack/annotation/processor/sample/processors/SourceAnnotationProcessor.java
new file mode 100644
index 0000000..7ef7a7a
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/processor/sample/processors/SourceAnnotationProcessor.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014 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.jack.annotation.processor.sample.processors;
+
+import com.android.jack.annotation.processor.sample.annotations.SourceAnnotationTest;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.JavaFileObject;
+
+/**
+ * Annotation processor to generate a new source file.
+ */
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+@SupportedAnnotationTypes("*")
+public class SourceAnnotationProcessor extends AbstractProcessor {
+ @Nonnull
+ public static final String SOURCE_ANNOTATION_PROCESSOR_SUFFIX =
+ "SourceAnnotationProcessor.suffix";
+ @CheckForNull
+ private ProcessingEnvironment env;
+ @Nonnull
+ private String suffix;
+
+ @Override
+ public synchronized void init(@Nonnull ProcessingEnvironment env) {
+ this.env = env;
+ suffix = env.getOptions().get(SOURCE_ANNOTATION_PROCESSOR_SUFFIX);
+ if (suffix == null) {
+ suffix = "Duplicated";
+ }
+ }
+
+ @Override
+ public boolean process(@Nonnull Set<? extends TypeElement> annotations, @Nonnull RoundEnvironment roundEnv) {
+ assert env != null;
+ env.getMessager().printMessage(Kind.NOTE,
+ "SourceAnnotationProcessor.process");
+ if (!roundEnv.processingOver()) {
+
+ //
+ // @SourceAnnotationTest
+ //
+
+ for (Element element : getElementsAnnotatedWith(roundEnv, SourceAnnotationTest.class)) {
+ TypeMirror type = element.asType();
+
+ if (type.getKind() == TypeKind.DECLARED) {
+ TypeElement classElement = (TypeElement) element;
+ try {
+ assert env != null;
+ JavaFileObject jfo =
+ env.getFiler().createSourceFile(classElement.getQualifiedName() + suffix);
+ Writer writer = jfo.openWriter();
+ writer.write("public class " + classElement.getSimpleName() + suffix + " {}");
+ writer.close();
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @Nonnull
+ private Set<? extends Element> getElementsAnnotatedWith(@Nonnull RoundEnvironment roundEnv,
+ @Nonnull Class<? extends Annotation> cls) {
+ assert env != null;
+
+ String name = cls.getCanonicalName();
+ assert name != null;
+
+ TypeElement element = env.getElementUtils().getTypeElement(name);
+ assert element != null;
+
+ return roundEnv.getElementsAnnotatedWith(element);
+ }
+}
diff --git a/jack-tests/tests/com/android/jack/annotation/processor/sample/processors/javax.annotation.processing.Processor b/jack-tests/tests/com/android/jack/annotation/processor/sample/processors/javax.annotation.processing.Processor
new file mode 100644
index 0000000..975dacb
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/annotation/processor/sample/processors/javax.annotation.processing.Processor
@@ -0,0 +1,2 @@
+com.android.jack.annotation.processor.sample.processors.SourceAnnotationProcessor
+com.android.jack.annotation.processor.sample.processors.ResourceAnnotationProcessor
diff --git a/jack-tests/tests/com/android/jack/classpath/ClasspathTests.java b/jack-tests/tests/com/android/jack/classpath/ClasspathTests.java
index 3aaa72d..9fb98b6 100644
--- a/jack-tests/tests/com/android/jack/classpath/ClasspathTests.java
+++ b/jack-tests/tests/com/android/jack/classpath/ClasspathTests.java
@@ -52,6 +52,7 @@ public class ClasspathTests {
.srcToLib(libOut, false,
new File(AbstractTestTools.getTestRootDir("com.android.jack.classpath.test001"), "lib"));
+ toolchain = AbstractTestTools.getCandidateToolchain();
File testOut = AbstractTestTools.createTempDir();
toolchain.addToClasspath(toolchain.getDefaultBootClasspath())
.addToClasspath(libOut)
diff --git a/jack-tests/tests/com/android/jack/error/AnnotationProcessorErrorTest.java b/jack-tests/tests/com/android/jack/error/AnnotationProcessorErrorTest.java
index a5e310c..99b58f2 100644
--- a/jack-tests/tests/com/android/jack/error/AnnotationProcessorErrorTest.java
+++ b/jack-tests/tests/com/android/jack/error/AnnotationProcessorErrorTest.java
@@ -18,14 +18,17 @@ package com.android.jack.error;
import com.google.common.io.Files;
-import com.android.jack.JackUserException;
+import com.android.jack.JackAbortException;
import com.android.jack.Main;
+import com.android.jack.backend.jayce.JayceFileImporter.CollisionPolicy;
import com.android.jack.errorhandling.annotationprocessor.ResourceAnnotationProcessor;
import com.android.jack.errorhandling.annotationprocessor.ResourceAnnotationTest;
import com.android.jack.errorhandling.annotationprocessor.SourceAnnotationProcessor;
import com.android.jack.errorhandling.annotationprocessor.SourceAnnotationTest;
import com.android.jack.errorhandling.annotationprocessor.SourceErrorAnnotationTest;
import com.android.jack.frontend.FrontendCompilationException;
+import com.android.jack.resource.ResourceImporter;
+import com.android.jack.resource.ResourceReadingException;
import com.android.jack.test.TestsProperties;
import com.android.jack.test.helper.ErrorTestHelper;
import com.android.jack.test.toolchain.AbstractTestTools;
@@ -43,6 +46,7 @@ import java.io.File;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
@@ -58,32 +62,6 @@ public class AnnotationProcessorErrorTest {
}
/**
- * Checks that compilation fails correctly when annotation processor is called without specifying
- * output folder.
- */
- @Test
- public void testAnnotationProcessorError001() throws Exception {
- ErrorTestHelper te = new ErrorTestHelper();
-
- AbstractTestTools.createFile(te.getSourceFolder(),"jack.incremental", "A.java",
- "package jack.incremental; \n"+
- "public class A {} \n");
-
- JackApiToolchainBase jackApiToolchain =
- AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
- jackApiToolchain.setAnnotationProcessorClass(ResourceAnnotationProcessor.class);
-
- try {
- jackApiToolchain.addToClasspath(jackApiToolchain.getDefaultBootClasspath())
- .srcToExe(te.getOutputDexFolder(), /* zipFile = */ false, te.getSourceFolder());
- Assert.fail();
- } catch (JackUserException e) {
- // Failure is ok since output for annotation processor is not specify.
- Assert.assertTrue(e.getMessage().contains("Unknown location"));
- }
- }
-
- /**
* Checks that compilation succeed when running annotation processor to generate resource file.
*/
@Test
@@ -101,12 +79,14 @@ public class AnnotationProcessorErrorTest {
runAnnotProcBuildingResource(te);
- JackApiToolchainBase jackApiToolchain =
- AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
- jackApiToolchain.setAnnotationProcessorClass(ResourceAnnotationProcessor.class);
- jackApiToolchain.setAnnotationProcessorOutDir(te.getTestingFolder());
+ JackApiToolchainBase jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
+ jackApiToolchain.setAnnotationProcessorClasses(
+ Collections.singletonList(ResourceAnnotationProcessor.class.getName()));
ByteArrayOutputStream errOut = new ByteArrayOutputStream();
jackApiToolchain.setErrorStream(errOut);
+ jackApiToolchain.addResource(te.getOutputDexFolder());
+ jackApiToolchain.addProperty(ResourceImporter.RESOURCE_COLLISION_POLICY.getName(),
+ CollisionPolicy.FAIL.name());
try {
@@ -115,10 +95,9 @@ public class AnnotationProcessorErrorTest {
.srcToExe(te.getOutputDexFolder(), /* zipFile = */ false, te.getSourceFolder());
Assert.fail();
- } catch (FrontendCompilationException e) {
+ } catch (JackAbortException e) {
+ Assert.assertTrue(e.getCause() instanceof ResourceReadingException);
// Failure is ok since created file already exists
- } finally {
- Assert.assertTrue(errOut.toString().contains("Resource already created"));
}
}
@@ -139,10 +118,9 @@ public class AnnotationProcessorErrorTest {
+ "public class A {}\n");
- JackApiToolchainBase jackApiToolchain =
- AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
- jackApiToolchain.setAnnotationProcessorClass(SourceAnnotationProcessor.class);
- jackApiToolchain.setAnnotationProcessorOutDir(te.getTestingFolder());
+ JackApiToolchainBase jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
+ jackApiToolchain.setAnnotationProcessorClasses(
+ Collections.singletonList(SourceAnnotationProcessor.class.getName()));
ByteArrayOutputStream errOut = new ByteArrayOutputStream();
jackApiToolchain.setErrorStream(errOut);
@@ -173,10 +151,9 @@ public class AnnotationProcessorErrorTest {
+ "@" + SourceAnnotationTest.class.getSimpleName() + "\n"
+ "public class A {}\n");
- JackApiToolchainBase jackApiToolchain =
- AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
- jackApiToolchain.setAnnotationProcessorClass(SourceAnnotationProcessor.class);
- jackApiToolchain.setAnnotationProcessorOutDir(te.getTestingFolder());
+ JackApiToolchainBase jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
+ jackApiToolchain.setAnnotationProcessorClasses(
+ Collections.singletonList(SourceAnnotationProcessor.class.getName()));
File dexOutput = te.getOutputDexFolder();
jackApiToolchain.addToClasspath(jackApiToolchain.getDefaultBootClasspath())
@@ -202,16 +179,15 @@ public class AnnotationProcessorErrorTest {
+ "@" + ResourceAnnotationTest.class.getSimpleName() + "\n"
+ "public class A {}\n");
- JackApiToolchainBase jackApiToolchain =
- AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
- jackApiToolchain.setAnnotationProcessorClass(ResourceAnnotationProcessor.class);
- jackApiToolchain.setAnnotationProcessorOutDir(te.getTestingFolder());
+ JackApiToolchainBase jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
+ jackApiToolchain.setAnnotationProcessorClasses(
+ Collections.singletonList(ResourceAnnotationProcessor.class.getName()));
jackApiToolchain.addToClasspath(jackApiToolchain.getDefaultBootClasspath())
.addToClasspath(te.getJackFolder())
.srcToExe(te.getOutputDexFolder(), /* zipFile = */ false, te.getSourceFolder());
- File discoverFile = new File(te.getTestingFolder(), ResourceAnnotationProcessor.FILENAME);
+ File discoverFile = new File(te.getOutputDexFolder(), ResourceAnnotationProcessor.FILENAME);
Assert.assertTrue(discoverFile.exists());
LineNumberReader lnr = new LineNumberReader(new FileReader(discoverFile));
Assert.assertEquals(ResourceAnnotationTest.class.getName(), lnr.readLine());
diff --git a/jack-tests/tests/com/android/jack/error/FileAccessErrorTest.java b/jack-tests/tests/com/android/jack/error/FileAccessErrorTest.java
index ff2cef2..259bf6a 100644
--- a/jack-tests/tests/com/android/jack/error/FileAccessErrorTest.java
+++ b/jack-tests/tests/com/android/jack/error/FileAccessErrorTest.java
@@ -184,6 +184,7 @@ public class FileAccessErrorTest {
"package jack.incremental; \n"+
"public class B extends A {} \n");
+ jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
ByteArrayOutputStream errOut = new ByteArrayOutputStream();
try {
for (File jackFile : AbstractTestTools.getFiles(te.getJackFolder(), JayceFileImporter.JAYCE_FILE_EXTENSION)) {
diff --git a/jack-tests/tests/com/android/jack/fileconflict/FileConflictTests.java b/jack-tests/tests/com/android/jack/fileconflict/FileConflictTests.java
index 61be8c2..1725143 100644
--- a/jack-tests/tests/com/android/jack/fileconflict/FileConflictTests.java
+++ b/jack-tests/tests/com/android/jack/fileconflict/FileConflictTests.java
@@ -36,6 +36,7 @@ import com.android.jack.test.toolchain.JackCliToolchain;
import com.android.jack.test.toolchain.LegacyJillToolchain;
import com.android.sched.util.stream.ByteStreamSucker;
+
import junit.framework.Assert;
import org.junit.BeforeClass;
@@ -407,14 +408,14 @@ public class FileConflictTests {
// create Jack dirs to import
File jackImport1 = AbstractTestTools.createTempDir();
- copyFileToDir(libProperties, libPropName, jackImport1);
- copyFileToDir(myClass1, jackFilePath, jackImport1);
- copyFileToDir(myClass1Dex, dexFilePath, jackImport1);
- copyFileToDir(digestFile, FileType.DEX.getPrefix() + "/digest", jackImport1);
+ AbstractTestTools.copyFileToDir(libProperties, libPropName, jackImport1);
+ AbstractTestTools.copyFileToDir(myClass1, jackFilePath, jackImport1);
+ AbstractTestTools.copyFileToDir(myClass1Dex, dexFilePath, jackImport1);
+ AbstractTestTools.copyFileToDir(digestFile, FileType.DEX.getPrefix() + "/digest", jackImport1);
// copy Jack file to output dir
- copyFileToDir(myClass1, jackFilePath, jackOutput);
- copyFileToDir(myClass1Dex, dexFilePath, jackOutput);
+ AbstractTestTools.copyFileToDir(myClass1, jackFilePath, jackOutput);
+ AbstractTestTools.copyFileToDir(myClass1Dex, dexFilePath, jackOutput);
toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class, exclude);
toolchain.addProguardFlags(new File(testSrcDir, "proguard.flags"));
@@ -454,13 +455,13 @@ public class FileConflictTests {
File jackImport1 = AbstractTestTools.createTempDir();
String resourcePath = "com/android/jack/fileconflict/test003/jack/Resource";
File resource = new File(testSrcDir, "Resource");
- copyFileToDir(libProperties, libPropName, jackImport1);
- copyFileToDir(myClass1, jackFilePath, jackImport1);
- copyFileToDir(resource, resourcePath, jackImport1);
+ AbstractTestTools.copyFileToDir(libProperties, libPropName, jackImport1);
+ AbstractTestTools.copyFileToDir(myClass1, jackFilePath, jackImport1);
+ AbstractTestTools.copyFileToDir(resource, resourcePath, jackImport1);
// copy a different resource to output dir with the same name
File resource2 = new File(testSrcDir, "Resource2");
- copyFileToDir(resource2, resourcePath, jackOutput);
+ AbstractTestTools.copyFileToDir(resource2, resourcePath, jackOutput);
// run Jack on Jack dir
toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class);
@@ -503,13 +504,13 @@ public class FileConflictTests {
// create Jack dirs to import
File jackImport1 = AbstractTestTools.createTempDir();
File resource = new File(testSrcDir, "MyClass.txt");
- copyFileToDir(libProperties, libPropName, jackImport1);
- copyFileToDir(myClass1, jackFilePath, jackImport1);
- copyFileToDir(resource, "com/android/jack/fileconflict/test004/jack/MyClass.txt", jackImport1);
+ AbstractTestTools.copyFileToDir(libProperties, libPropName, jackImport1);
+ AbstractTestTools.copyFileToDir(myClass1, jackFilePath, jackImport1);
+ AbstractTestTools.copyFileToDir(resource, "com/android/jack/fileconflict/test004/jack/MyClass.txt", jackImport1);
// copy a different resource to output dir with the same name
File resource2 = new File(testSrcDir, "a.txt");
- copyFileToDir(resource2, "pcz/nbqfcvq/wnpx/svyrpcbsyvph/hrgh004/wnpx/ZmPyngg.txt", jackOutput);
+ AbstractTestTools.copyFileToDir(resource2, "pcz/nbqfcvq/wnpx/svyrpcbsyvph/hrgh004/wnpx/ZmPyngg.txt", jackOutput);
// run Jack on Jack dir
toolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class);
@@ -564,18 +565,18 @@ public class FileConflictTests {
// create Jack dirs to import
File jackImport1 = AbstractTestTools.createTempDir();
File jackImport2 = AbstractTestTools.createTempDir();
- copyFileToDir(digestFile, FileType.DEX.getPrefix() + "/digest", jackImport1);
- copyFileToDir(digestFile, FileType.DEX.getPrefix() + "/digest", jackImport2);
- copyFileToDir(libProperties, libPropName, jackImport1);
- copyFileToDir(myClass1, JACK_FILE_PATH_1, jackImport1);
- copyFileToDir(myClass1Dex, DEX_FILE_PATH_1, jackImport1);
- copyFileToDir(myClass2, JACK_FILE_PATH_2, jackImport1);
- copyFileToDir(myClass2Dex, DEX_FILE_PATH_2, jackImport1);
- copyFileToDir(libProperties, libPropName, jackImport2);
- copyFileToDir(myClass1, JACK_FILE_PATH_1, jackImport2);
- copyFileToDir(myClass1Dex, DEX_FILE_PATH_1, jackImport2);
- copyFileToDir(myClass3, JACK_FILE_PATH_3, jackImport2);
- copyFileToDir(myClass3Dex, DEX_FILE_PATH_3, jackImport2);
+ AbstractTestTools.copyFileToDir(digestFile, FileType.DEX.getPrefix() + "/digest", jackImport1);
+ AbstractTestTools.copyFileToDir(digestFile, FileType.DEX.getPrefix() + "/digest", jackImport2);
+ AbstractTestTools.copyFileToDir(libProperties, libPropName, jackImport1);
+ AbstractTestTools.copyFileToDir(myClass1, JACK_FILE_PATH_1, jackImport1);
+ AbstractTestTools.copyFileToDir(myClass1Dex, DEX_FILE_PATH_1, jackImport1);
+ AbstractTestTools.copyFileToDir(myClass2, JACK_FILE_PATH_2, jackImport1);
+ AbstractTestTools.copyFileToDir(myClass2Dex, DEX_FILE_PATH_2, jackImport1);
+ AbstractTestTools.copyFileToDir(libProperties, libPropName, jackImport2);
+ AbstractTestTools.copyFileToDir(myClass1, JACK_FILE_PATH_1, jackImport2);
+ AbstractTestTools.copyFileToDir(myClass1Dex, DEX_FILE_PATH_1, jackImport2);
+ AbstractTestTools.copyFileToDir(myClass3, JACK_FILE_PATH_3, jackImport2);
+ AbstractTestTools.copyFileToDir(myClass3Dex, DEX_FILE_PATH_3, jackImport2);
// run Jack on Jack dirs
toolchain = getToolchain(isApiTest);
@@ -608,6 +609,7 @@ public class FileConflictTests {
/* zipFiles = */ false,
lib1);
+ toolchain = getToolchain(isApiTest);
File jackImport2 = AbstractTestTools.createTempDir();
File lib2 = new File(TEST002_DIR, "lib2");
toolchain = getToolchain(isApiTest);
@@ -640,36 +642,6 @@ public class FileConflictTests {
return jackOutput;
}
- private void copyFileToDir(@Nonnull File fileToCopy, @Nonnull String relativePath,
- @Nonnull File dir) throws IOException {
- FileOutputStream fos = null;
- FileInputStream fis = null;
- try {
- fis = new FileInputStream(fileToCopy);
- File copiedFile = new File(dir, relativePath);
- File parentDir = copiedFile.getParentFile();
- if (!parentDir.exists()) {
- boolean res = parentDir.mkdirs();
- if (!res) {
- throw new AssertionError();
- }
- }
- try {
- fos = new FileOutputStream(copiedFile);
- ByteStreamSucker sucker = new ByteStreamSucker(fis, fos);
- sucker.suck();
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
- } finally {
- if (fis != null) {
- fis.close();
- }
- }
- }
-
private void checkResourceContent(@Nonnull File dir, @Nonnull String path,
@Nonnull String expectedContent) throws IOException {
assert dir.isDirectory();
diff --git a/jack/src/com/android/jack/Options.java b/jack/src/com/android/jack/Options.java
index 7f4e268..af8597e 100644
--- a/jack/src/com/android/jack/Options.java
+++ b/jack/src/com/android/jack/Options.java
@@ -42,11 +42,18 @@ import com.android.jack.shrob.obfuscation.annotation.ParameterAnnotationRemover;
import com.android.jack.shrob.seed.SeedPrinter;
import com.android.jack.shrob.spec.Flags;
import com.android.jack.transformations.renamepackage.PackageRenamer;
+import com.android.jack.util.ClassNameCodec;
import com.android.jack.util.filter.Filter;
import com.android.sched.util.RunnableHooks;
import com.android.sched.util.codec.DirectDirOutputVFSCodec;
import com.android.sched.util.codec.DirectFSCodec;
+import com.android.sched.util.codec.DirectoryCodec;
+import com.android.sched.util.codec.InputFileOrDirectoryCodec;
import com.android.sched.util.codec.InputStreamOrDirectoryCodec;
+import com.android.sched.util.codec.ListCodec;
+import com.android.sched.util.codec.PairCodec;
+import com.android.sched.util.codec.PairListToMapCodecConverter;
+import com.android.sched.util.codec.StringValueCodec;
import com.android.sched.util.codec.ZipFSCodec;
import com.android.sched.util.codec.ZipOutputVFSCodec;
import com.android.sched.util.config.Config;
@@ -193,6 +200,12 @@ public class Options {
"jack.statistic.source", "Enable compiled files statistics").addDefaultValue(
Boolean.FALSE);
+ @Nonnull
+ public static final BooleanPropertyId ANNOTATION_PROCESSOR_ENABLED =
+ BooleanPropertyId.create(
+ "jack.annotation-processor", "Enable annotation processors")
+ .addDefaultValue(true);
+
@Option(name = "--version", usage = "display version")
private boolean version;
@@ -210,6 +223,23 @@ public class Options {
@Nonnull
private final Map<String, String> properties = new HashMap<String, String>();
+ @Option(name = "-A", metaVar = "<option>=<value>",
+ usage = "set option for annotation processors (repeatable)",
+ handler = MapOptionHandler.class)
+ @Nonnull
+ public final Map<String, String> annotationProcessorOption = new HashMap<String, String>();
+
+ @Nonnull
+ public static final PropertyId<Map<String, String>> ANNOTATION_PROCESSOR_OPTIONS =
+ PropertyId.create(
+ "jack.annotation-processor.properties", "Options for annotation processors",
+ new PairListToMapCodecConverter<String, String>(new ListCodec<Entry<String, String>>("pair",
+ new PairCodec<String, String>(
+ new StringValueCodec("annotation processor option name"),
+ new StringValueCodec("annotation processor option value")))))
+ .addDefaultValue("");
+
+ @CheckForNull
private final File propertiesFile = null;
/**
@@ -309,8 +339,70 @@ public class Options {
metaVar = "<DIRECTORY>")
private File tracerDir;
+ @Option(name = "--processor", usage = "annotation processor class names",
+ metaVar = "<NAME>[,<NAME>...]")
+ @CheckForNull
+ public String processor;
+
+ @Nonnull
+ public static final BooleanPropertyId ANNOTATION_PROCESSOR_MANUAL =
+ BooleanPropertyId.create(
+ "jack.annotation-processor.manual", "run only specified annotation processors")
+ .addDefaultValue(false);
+
+ @Nonnull
+ public static final ListPropertyId<String> ANNOTATION_PROCESSOR_MANUAL_LIST =
+ ListPropertyId.create(
+ "jack.annotation-processor.manual.list",
+ "Annotation processor class names",
+ "class",
+ new ClassNameCodec()).requiredIf(ANNOTATION_PROCESSOR_MANUAL
+ .getValue().isTrue());
+
+ @Nonnull
+ public static final PropertyId<Directory> ANNOTATION_PROCESSOR_SOURCE_OUTPUT_DIR =
+ PropertyId.create(
+ "jack.annotation-processor.source.output",
+ "Output folder for sources generated by annotation processors",
+ new DirectoryCodec(Existence.MUST_EXIST, Permission.WRITE | Permission.READ));
+
+ @Nonnull
+ public static final PropertyId<Directory> ANNOTATION_PROCESSOR_CLASS_OUTPUT_DIR =
+ PropertyId.create(
+ "jack.annotation-processor.class.output",
+ "Output folder for classes generated by annotation processors",
+ new DirectoryCodec(Existence.MUST_EXIST, Permission.WRITE | Permission.READ));
+
+ @Option(name = "--processorpath", usage = "annotation processor classpath", metaVar = "<PATH>")
+ @CheckForNull
+ public String processorPath;
+
+ @Nonnull
+ public static final BooleanPropertyId ANNOTATION_PROCESSOR_PATH =
+ BooleanPropertyId.create(
+ "jack.annotation-processor.path",
+ "Use annotation processor classpath for annotation processor loading")
+ .addDefaultValue(false);
+
+ @Nonnull
+ public static final ListPropertyId<FileOrDirectory> ANNOTATION_PROCESSOR_PATH_LIST =
+ ListPropertyId.create(
+ "jack.annotation-processor.path.list",
+ "Annotation processor classpath",
+ "entry",
+ new InputFileOrDirectoryCodec())
+ .on(File.pathSeparator)
+ .requiredIf(ANNOTATION_PROCESSOR_PATH.getValue().isTrue());
+
+ @Nonnull
@Option(name = "-cp", aliases = "--classpath", usage = "set classpath", metaVar = "<PATH>")
- protected String classpath = null;
+ protected String classpath = "";
+
+ @Nonnull
+ public static final PropertyId<String> CLASSPATH =
+ PropertyId.create(
+ "jack.classpath",
+ "Compilation classpath", new StringValueCodec(""));
// This is a trick to document @<FILE>, but it has no real link to ecjArguments
@Argument(usage = "read command line from file", metaVar = "@<FILE>")
@@ -324,7 +416,7 @@ public class Options {
.addDefaultValue(Collections.<FileOrDirectory>emptyList());
@Nonnull
- private List<String> ecjExtraArguments = new ArrayList<String>();
+ private final List<String> ecjExtraArguments = new ArrayList<String>();
@Option(name = "-g", usage = "emit debug infos")
private Boolean emitLocalDebugInfo;
@@ -534,6 +626,21 @@ public class Options {
configBuilder.setString(PackageRenamer.JARJAR_FILE, jarjarRulesFile.getPath());
}
+ if (processor != null) {
+ configBuilder.set(ANNOTATION_PROCESSOR_MANUAL, true);
+ configBuilder.setString(ANNOTATION_PROCESSOR_MANUAL_LIST, processor);
+ }
+ configBuilder.set(ANNOTATION_PROCESSOR_SOURCE_OUTPUT_DIR, createTempDir(hooks));
+ Directory annotationProcessorOutputClasses = createTempDir(hooks);
+ configBuilder.set(ANNOTATION_PROCESSOR_CLASS_OUTPUT_DIR, annotationProcessorOutputClasses);
+ addResource(annotationProcessorOutputClasses.getFile());
+ if (processorPath != null) {
+ configBuilder.set(ANNOTATION_PROCESSOR_PATH, true);
+ configBuilder.setString(ANNOTATION_PROCESSOR_PATH_LIST, processorPath);
+ }
+
+ configBuilder.set(ANNOTATION_PROCESSOR_OPTIONS, annotationProcessorOption);
+
if (!resImport.isEmpty()) {
configBuilder.setString(ResourceImporter.IMPORTED_RESOURCES,
Joiner.on(File.pathSeparator).join(resImport));
@@ -672,7 +779,7 @@ public class Options {
configBuilder.set(GENERATE_JACK_LIBRARY, true);
configBuilder.set(LIBRARY_OUTPUT_CONTAINER_TYPE, Container.DIR);
configBuilder.set(Options.LIBRARY_OUTPUT_DIR, new CachedDirectFS(
- createTempDirForTypeDexFiles(hooks), Permission.READ | Permission.WRITE));
+ annotationProcessorOutputClasses, Permission.READ | Permission.WRITE));
}
switch (multiDexKind) {
@@ -735,6 +842,8 @@ public class Options {
configBuilder.popDefaultLocation();
+ configBuilder.setString(CLASSPATH, classpath);
+
for (Entry<String, String> entry : properties.entrySet()) {
configBuilder.setString(entry.getKey(), entry.getValue(), new StringLocation("-D option"));
}
@@ -767,6 +876,10 @@ public class Options {
}
ecjExtraArguments.add("-source");
ecjExtraArguments.add(config.get(Options.JAVA_SOURCE_VERSION).toString());
+
+ if (!config.get(Options.ANNOTATION_PROCESSOR_ENABLED).booleanValue()) {
+ ecjExtraArguments.add("-proc:none");
+ }
}
// Check Jack arguments
@@ -817,7 +930,7 @@ public class Options {
}
String libraryJars = flags.getLibraryJars();
if (libraryJars != null) {
- if (classpath == null) {
+ if (classpath.isEmpty()) {
classpath = libraryJars;
} else {
classpath += File.pathSeparatorChar + libraryJars;
@@ -825,8 +938,12 @@ public class Options {
}
}
- public void setClasspath(String classpath) {
- this.classpath = classpath;
+ public void setClasspath(@CheckForNull String classpath) {
+ if (classpath == null) {
+ this.classpath = "";
+ } else {
+ this.classpath = classpath;
+ }
}
public void setMultiDexKind(@Nonnull MultiDexKind multiDexKind) {
@@ -844,9 +961,9 @@ public class Options {
properties.put(propertyName, propertyValue);
}
- // TODO(yroussel) remove when annotation processor is implemented
- public void setEcjExtraArguments(@Nonnull List<String> ecjArguments) {
- this.ecjExtraArguments = ecjArguments;
+ public void addAnnotationProcessorOption(@Nonnull String propertyName,
+ @Nonnull String propertyValue) {
+ annotationProcessorOption.put(propertyName, propertyValue);
}
@Nonnull
@@ -891,25 +1008,25 @@ public class Options {
}
@Nonnull
- private static Directory createTempDirForTypeDexFiles(
+ private static Directory createTempDir(
@Nonnull RunnableHooks hooks) {
try {
File tmp = Files.createTempDir();
Directory dir = new Directory(tmp.getPath(), hooks, Existence.MUST_EXIST, Permission.WRITE,
ChangePermission.NOCHANGE);
- hooks.addHook(new TypeDexDirDeleter(dir));
+ hooks.addHook(new TempDirDeleter(dir));
return dir;
} catch (IOException e) {
throw new JackUserException(e);
}
}
- private static class TypeDexDirDeleter extends Thread {
+ private static class TempDirDeleter implements Runnable {
@Nonnull
private final Directory dir;
- public TypeDexDirDeleter(@Nonnull Directory dir) {
+ public TempDirDeleter(@Nonnull Directory dir) {
this.dir = dir;
}
diff --git a/jack/src/com/android/jack/api/v01/impl/Api01ConfigImpl.java b/jack/src/com/android/jack/api/v01/impl/Api01ConfigImpl.java
index 0aa5d0e..c98622b 100644
--- a/jack/src/com/android/jack/api/v01/impl/Api01ConfigImpl.java
+++ b/jack/src/com/android/jack/api/v01/impl/Api01ConfigImpl.java
@@ -46,6 +46,7 @@ import java.io.File;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import javax.annotation.Nonnull;
@@ -251,17 +252,19 @@ public class Api01ConfigImpl implements Api01Config {
@Override
public void setProcessorNames(@Nonnull List<String> processorNames) {
- throw new AssertionError();
+ options.processor = Joiner.on(',').join(processorNames);
}
@Override
public void setProcessorOptions(@Nonnull Map<String, String> processorOptions) {
- throw new AssertionError();
+ for (Entry<String, String> entry : processorOptions.entrySet()) {
+ options.addAnnotationProcessorOption(entry.getKey(), entry.getValue());
+ }
}
@Override
public void setProcessorPath(@Nonnull List<File> processorPath) {
- throw new AssertionError();
+ options.processorPath = Joiner.on(File.pathSeparatorChar).join(processorPath);
}
@Override
diff --git a/jack/src/com/android/jack/frontend/java/EcjLogger.java b/jack/src/com/android/jack/frontend/java/EcjLogger.java
index 11fe2fb..03a133b 100644
--- a/jack/src/com/android/jack/frontend/java/EcjLogger.java
+++ b/jack/src/com/android/jack/frontend/java/EcjLogger.java
@@ -24,6 +24,7 @@ import org.eclipse.jdt.internal.compiler.batch.Main;
import org.eclipse.jdt.internal.compiler.batch.Main.Logger;
import java.io.PrintWriter;
+import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -39,14 +40,19 @@ public class EcjLogger extends Logger {
@CheckForNull
private Reporter reporter;
- public EcjLogger(Main main, PrintWriter out, PrintWriter err,
+ public EcjLogger(@Nonnull Main main, @Nonnull PrintWriter out, @Nonnull PrintWriter err,
@Nonnull JackBatchCompiler jackBatchCompiler) {
super(main, out, err);
this.jackBatchCompiler = jackBatchCompiler;
}
@Override
- public int logProblems(CategorizedProblem[] problems, char[] unitSource, Main currentMain) {
+ public int logProblems(@Nonnull CategorizedProblem[] problems, @Nonnull char[] unitSource,
+ @Nonnull Main currentMain) {
+ return report(problems, currentMain);
+ }
+
+ private int report(@Nonnull CategorizedProblem[] problems, @Nonnull Main currentMain) {
if (reporter == null) {
// lazy because the Reporter is not yet available when the EcjLogger is instantiated.
reporter = jackBatchCompiler.getReporter();
@@ -73,4 +79,12 @@ public class EcjLogger extends Logger {
int globalWarningsCount, int globalTasksCount) {
// Do nothing
}
+
+ @Override
+ public void loggingExtraProblems(@Nonnull Main currentMain) {
+ List<CategorizedProblem> extras = jackBatchCompiler.getExtraProblems();
+ if (extras != null) {
+ report(extras.toArray(new CategorizedProblem[extras.size()]), currentMain);
+ }
+ }
} \ No newline at end of file
diff --git a/jack/src/com/android/jack/frontend/java/JackBatchCompiler.java b/jack/src/com/android/jack/frontend/java/JackBatchCompiler.java
index 424a7c3..32e1081 100644
--- a/jack/src/com/android/jack/frontend/java/JackBatchCompiler.java
+++ b/jack/src/com/android/jack/frontend/java/JackBatchCompiler.java
@@ -16,17 +16,25 @@
package com.android.jack.frontend.java;
+import com.google.common.base.Joiner;
+
import com.android.jack.JackUserException;
+import com.android.jack.Options;
import com.android.jack.ecj.loader.jast.JAstClasspath;
import com.android.jack.ir.ast.JSession;
import com.android.jack.reporting.Reporter;
+import com.android.sched.util.config.Config;
+import com.android.sched.util.config.ThreadConfig;
+import com.android.sched.util.file.FileOrDirectory;
import com.android.sched.util.file.InputStreamFile;
import com.android.sched.util.file.NoSuchFileException;
import com.android.sched.util.file.NotFileException;
import com.android.sched.util.file.WrongPermissionException;
import com.android.sched.util.log.LoggerFactory;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CompilationProgress;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BatchAnnotationProcessorManager;
import org.eclipse.jdt.internal.compiler.batch.ClasspathDirectory;
import org.eclipse.jdt.internal.compiler.batch.ClasspathJar;
import org.eclipse.jdt.internal.compiler.batch.ClasspathLocation;
@@ -39,9 +47,12 @@ import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.logging.Level;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
@@ -230,6 +241,12 @@ public class JackBatchCompiler extends Main {
logger.printStats();
}
+ @SuppressWarnings("unchecked")
+ @CheckForNull
+ public List<CategorizedProblem> getExtraProblems() {
+ return extraProblems;
+ }
+
@Override
public void configure(String[] argv) {
super.configure(argv);
@@ -264,4 +281,49 @@ public class JackBatchCompiler extends Main {
}
return cu;
}
+
+ @Override
+ protected void initializeAnnotationProcessorManager() {
+ List<String> processorArgs = new ArrayList<String>();
+ Config config = ThreadConfig.getConfig();
+ for (Map.Entry<String, String> entry :
+ config.get(Options.ANNOTATION_PROCESSOR_OPTIONS).entrySet()) {
+ processorArgs.add("-A" + entry.getKey() + "=" + entry.getValue());
+ }
+ if (config.get(Options.ANNOTATION_PROCESSOR_MANUAL).booleanValue()) {
+ processorArgs.add("-processor");
+ processorArgs.add(Joiner.on(',').join(config.get(Options.ANNOTATION_PROCESSOR_MANUAL_LIST)));
+ }
+ if (config.get(Options.ANNOTATION_PROCESSOR_PATH).booleanValue()) {
+ processorArgs.add("-processorpath");
+ processorArgs.add(getPathString(config.get(Options.ANNOTATION_PROCESSOR_PATH_LIST)));
+ }
+ processorArgs.add("-s");
+ processorArgs.add(config.get(Options.ANNOTATION_PROCESSOR_SOURCE_OUTPUT_DIR).getPath());
+ processorArgs.add("-d");
+ processorArgs.add(config.get(Options.ANNOTATION_PROCESSOR_CLASS_OUTPUT_DIR).getPath());
+ {
+ processorArgs.add("-classpath");
+ processorArgs.add(config.get(Options.CLASSPATH));
+ }
+ String[] args = processorArgs.toArray(new String[processorArgs.size()]);
+
+ BatchAnnotationProcessorManager manager = new BatchAnnotationProcessorManager();
+ manager.configure(this, args);
+ manager.setOut(out);
+ this.batchCompiler.annotationProcessorManager = manager;
+ }
+
+ @Nonnull
+ private static String getPathString(@Nonnull List<FileOrDirectory> pathList) {
+ StringBuilder path = new StringBuilder();
+ for (Iterator<FileOrDirectory> iter = pathList.iterator();
+ iter.hasNext();) {
+ path.append(iter.next().getPath());
+ if (iter.hasNext()) {
+ path.append(File.pathSeparatorChar);
+ }
+ }
+ return path.toString();
+ }
}
diff --git a/jack/src/com/android/jack/ir/ast/JSession.java b/jack/src/com/android/jack/ir/ast/JSession.java
index 1b31fd8..ccbf4b3 100644
--- a/jack/src/com/android/jack/ir/ast/JSession.java
+++ b/jack/src/com/android/jack/ir/ast/JSession.java
@@ -131,7 +131,6 @@ public class JSession extends JNode {
this.inputFilter = inputFilter;
}
-
@Nonnull
public JNodeLookup getLookup() {
return lookup;
diff --git a/jack/src/com/android/jack/reporting/CommonReporter.java b/jack/src/com/android/jack/reporting/CommonReporter.java
index 428e2d0..d7b8f2e 100644
--- a/jack/src/com/android/jack/reporting/CommonReporter.java
+++ b/jack/src/com/android/jack/reporting/CommonReporter.java
@@ -49,7 +49,8 @@ abstract class CommonReporter implements Reporter {
CategorizedProblem problem = ((EcjProblem) reportable).getProblem();
printProblem(reportable.getDefaultProblemLevel(),
reportable.getMessage(),
- String.valueOf(problem.getOriginatingFileName()),
+ problem.getOriginatingFileName() != null ?
+ String.valueOf(problem.getOriginatingFileName()) : null,
problem.getSourceLineNumber(),
-1 /* endLine */,
problem.getSourceEnd(),
diff --git a/jack/src/com/android/jack/resource/ResourceImporter.java b/jack/src/com/android/jack/resource/ResourceImporter.java
index a44efb7..0b6556c 100644
--- a/jack/src/com/android/jack/resource/ResourceImporter.java
+++ b/jack/src/com/android/jack/resource/ResourceImporter.java
@@ -30,6 +30,7 @@ import com.android.sched.vfs.InputVFS;
import com.android.sched.vfs.InputVFile;
import com.android.sched.vfs.VPath;
+import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
@@ -52,7 +53,9 @@ public class ResourceImporter extends ResourceOrMetaImporter {
@Nonnull
public static final ListPropertyId<InputVFS> IMPORTED_RESOURCES = ListPropertyId.create(
"jack.import.resource", "Resources to import", "dir",
- new DirectoryInputVFSCodec()).addDefaultValue(Collections.<InputVFS>emptyList());
+ new DirectoryInputVFSCodec())
+ .on(File.pathSeparator)
+ .addDefaultValue(Collections.<InputVFS>emptyList());
@Nonnull
private final CollisionPolicy resourceCollisionPolicy =
diff --git a/jack/src/com/android/jack/util/ClassNameCodec.java b/jack/src/com/android/jack/util/ClassNameCodec.java
new file mode 100644
index 0000000..16d91eb
--- /dev/null
+++ b/jack/src/com/android/jack/util/ClassNameCodec.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014 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.jack.util;
+
+import com.android.sched.util.codec.CheckingException;
+import com.android.sched.util.codec.CodecContext;
+import com.android.sched.util.codec.ParsingException;
+import com.android.sched.util.codec.StringCodec;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+
+/**
+ * This {@link StringCodec} is used to check that the string is a valid class name
+ */
+public class ClassNameCodec implements StringCodec<String>{
+
+ @Override
+ @Nonnull
+ public String getUsage() {
+ return "a java class name (e.g. java.lang.Object)";
+ }
+
+ @Override
+ @Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return Collections.<ValueDescription> emptyList();
+ }
+
+ @Override
+ @Nonnull
+ public String parseString(@Nonnull CodecContext context, @Nonnull String string) {
+ return string;
+ }
+
+ @Override
+ @CheckForNull
+ public String checkString(@Nonnull CodecContext context, @Nonnull String string)
+ throws ParsingException {
+ if (!NamingTools.isClassSourceName(string)) {
+ throw new ParsingException(
+ "The value must be " + getUsage() + " but is '" + string + "'");
+ }
+ return string;
+ }
+
+ @Override
+ public void checkValue(@Nonnull CodecContext context, @Nonnull String data)
+ throws CheckingException {
+ if (!NamingTools.isClassSourceName(data)) {
+ throw new CheckingException(
+ "The value must be " + getUsage() + " but is '" + data + "'");
+ }
+ }
+
+ @Override
+ @Nonnull
+ public String formatValue(@Nonnull String name) {
+ return name;
+ }
+}
diff --git a/jack/src/com/android/jack/util/NamingTools.java b/jack/src/com/android/jack/util/NamingTools.java
index 381c6b8..b2cf05c 100644
--- a/jack/src/com/android/jack/util/NamingTools.java
+++ b/jack/src/com/android/jack/util/NamingTools.java
@@ -120,16 +120,21 @@ public class NamingTools {
}
public static boolean isPackageBinaryName(@Nonnull String name) {
- return isPackageName(name.toCharArray(), 0, name.length(), JLookup.PACKAGE_SEPARATOR,
+ return isClassOrPackageName(name.toCharArray(), 0, name.length(), JLookup.PACKAGE_SEPARATOR,
PACKAGE_SOURCE_SEPARATOR);
}
public static boolean isPackageSourceName(@Nonnull String name) {
- return isPackageName(name.toCharArray(), 0, name.length(), PACKAGE_SOURCE_SEPARATOR,
+ return isClassOrPackageName(name.toCharArray(), 0, name.length(), PACKAGE_SOURCE_SEPARATOR,
JLookup.PACKAGE_SEPARATOR);
}
- private static boolean isPackageName(
+ public static boolean isClassSourceName(@Nonnull String name) {
+ return isClassOrPackageName(name.toCharArray(), 0, name.length(), PACKAGE_SOURCE_SEPARATOR,
+ JLookup.PACKAGE_SEPARATOR);
+ }
+
+ private static boolean isClassOrPackageName(
@Nonnull char[] buffer, @Nonnegative int pos, @Nonnegative int length, char usedSeparator,
char forbiddenSeparator) {
while (pos < length) {
diff --git a/jack/tests/com/android/jack/TestTools.java b/jack/tests/com/android/jack/TestTools.java
index 99aec20..cfc9dc8 100644
--- a/jack/tests/com/android/jack/TestTools.java
+++ b/jack/tests/com/android/jack/TestTools.java
@@ -194,10 +194,10 @@ public class TestTools {
"jack-tests/prebuilts/core-stubs-mini.jack").getAbsolutePath();
}
- @CheckForNull
+ @Nonnull
public static String getClasspathAsString(@CheckForNull File[] files) {
if (files == null || files.length == 0) {
- return null;
+ return "";
}
StringBuilder classpathStr = new StringBuilder();
for (int i = 0; i < files.length; i++) {
@@ -209,7 +209,7 @@ public class TestTools {
return classpathStr.toString();
}
- @CheckForNull
+ @Nonnull
public static String getClasspathsAsString(
@CheckForNull File[] bootClasspath, @CheckForNull File[] classpath) {
if (bootClasspath == null) {
@@ -222,12 +222,12 @@ public class TestTools {
}
}
- @CheckForNull
+ @Nonnull
private static String concatClasspathStrings(
- @CheckForNull String bootclasspath, @CheckForNull String classpath) {
+ @Nonnull String bootclasspath, @Nonnull String classpath) {
if (bootclasspath == null || bootclasspath.isEmpty()) {
return classpath;
- } else if (classpath == null || classpath.isEmpty()) {
+ } else if (classpath.isEmpty()) {
return bootclasspath;
} else {
StringBuilder classpathStr = new StringBuilder(bootclasspath);
diff --git a/jack/tests/com/android/jack/errorhandling/annotationprocessor/ResourceAnnotationProcessor.java b/jack/tests/com/android/jack/errorhandling/annotationprocessor/ResourceAnnotationProcessor.java
index 2aca1bb..ae2eba0 100644
--- a/jack/tests/com/android/jack/errorhandling/annotationprocessor/ResourceAnnotationProcessor.java
+++ b/jack/tests/com/android/jack/errorhandling/annotationprocessor/ResourceAnnotationProcessor.java
@@ -38,6 +38,7 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic.Kind;
+import javax.tools.FileObject;
import javax.tools.StandardLocation;
/**
@@ -71,8 +72,9 @@ public class ResourceAnnotationProcessor extends AbstractProcessor {
try {
assert env != null;
- OutputStream os = env.getFiler()
- .createResource(StandardLocation.CLASS_OUTPUT, "", FILENAME)
+ FileObject resource = env.getFiler()
+ .createResource(StandardLocation.CLASS_OUTPUT, "", FILENAME);
+ OutputStream os = resource
.openOutputStream();
Writer writer = new OutputStreamWriter(os);
try {
diff --git a/sched/src/com/android/sched/util/RunnableHooks.java b/sched/src/com/android/sched/util/RunnableHooks.java
index c7143ab..07430fc 100644
--- a/sched/src/com/android/sched/util/RunnableHooks.java
+++ b/sched/src/com/android/sched/util/RunnableHooks.java
@@ -43,15 +43,6 @@ public class RunnableHooks {
@Nonnull
private final List<Runnable> hooks = new ArrayList<Runnable>();
- public RunnableHooks() {
- Runtime.getRuntime().addShutdownHook(new Thread(){
- @Override
- public void run() {
- runHooks();
- }
- });
- }
-
public synchronized void addHook(@Nonnull Runnable hook) {
assert !hooks.contains(hook);
@@ -65,7 +56,6 @@ public class RunnableHooks {
}
public synchronized void runHooks() {
-
for (Runnable hook : Lists.reverse(hooks)) {
hook.run();
}
diff --git a/sched/src/com/android/sched/util/codec/InputFileOrDirectoryCodec.java b/sched/src/com/android/sched/util/codec/InputFileOrDirectoryCodec.java
new file mode 100644
index 0000000..b735e50
--- /dev/null
+++ b/sched/src/com/android/sched/util/codec/InputFileOrDirectoryCodec.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 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.sched.util.codec;
+
+import com.android.sched.util.config.ConfigurationError;
+import com.android.sched.util.file.Directory;
+import com.android.sched.util.file.FileOrDirectory;
+import com.android.sched.util.file.FileOrDirectory.Existence;
+import com.android.sched.util.file.FileOrDirectory.Permission;
+import com.android.sched.util.file.InputStreamFile;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link StringCodec} is used to create an instance of {@link FileOrDirectory}.
+ */
+public class InputFileOrDirectoryCodec extends FileOrDirCodec<FileOrDirectory> {
+
+ public InputFileOrDirectoryCodec() {
+ super(Existence.MUST_EXIST, Permission.READ);
+ }
+
+ @Override
+ @Nonnull
+ public FileOrDirectory parseString(@Nonnull CodecContext context, @Nonnull String string) {
+ try {
+ return checkString(context, string);
+ } catch (ParsingException e) {
+ throw new ConfigurationError(e);
+ }
+ }
+
+ @Override
+ @CheckForNull
+ public FileOrDirectory checkString(@Nonnull CodecContext context, @Nonnull String string)
+ throws ParsingException {
+ File file = new File(string);
+ try {
+ if (file.isFile()) {
+ return new InputStreamFile(string);
+ } else {
+ return new Directory(string, context.getRunnableHooks(), existence, permissions, change);
+ }
+ } catch (IOException e) {
+ throw new ParsingException(e.getMessage(), e);
+ }
+
+ }
+
+ @Override
+ @Nonnull
+ public String getUsage() {
+ return "a path to a file or directory (" + getUsageDetails() + ")";
+ }
+
+ @Override
+ @Nonnull
+ public String formatValue(@Nonnull FileOrDirectory data) {
+ return data.getPath();
+ }
+
+ @Override
+ public void checkValue(@Nonnull CodecContext context, @Nonnull FileOrDirectory data) {
+ }
+
+}
diff --git a/sched/src/com/android/sched/util/codec/ListCodec.java b/sched/src/com/android/sched/util/codec/ListCodec.java
index 25f5c75..4544573 100644
--- a/sched/src/com/android/sched/util/codec/ListCodec.java
+++ b/sched/src/com/android/sched/util/codec/ListCodec.java
@@ -56,13 +56,18 @@ public class ListCodec<T> implements StringCodec<List<T>> {
this.var = var;
}
- public ListCodec<T> setSeperator(@Nonnull String separator) {
+ public ListCodec<T> setSeparator(@Nonnull String separator) {
this.separator = separator;
this.regexp = Pattern.quote(separator);
return this;
}
+ @Nonnull
+ public String getSeparator() {
+ return separator;
+ }
+
public ListCodec<T> setMin(@Nonnegative int min) {
assert min < max;
assert min >= 0;
diff --git a/sched/src/com/android/sched/util/codec/ListParsingException.java b/sched/src/com/android/sched/util/codec/ListParsingException.java
index 83d988d..048b07b 100644
--- a/sched/src/com/android/sched/util/codec/ListParsingException.java
+++ b/sched/src/com/android/sched/util/codec/ListParsingException.java
@@ -30,7 +30,7 @@ public class ListParsingException extends ParsingException {
private final int index;
public ListParsingException(@Nonnegative int index, @Nonnull String message) {
- super(message);
+ super("element #" + (index + 1) + ": " + message);
this.index = index;
}
diff --git a/sched/src/com/android/sched/util/codec/PairCodec.java b/sched/src/com/android/sched/util/codec/PairCodec.java
new file mode 100644
index 0000000..4032bf8
--- /dev/null
+++ b/sched/src/com/android/sched/util/codec/PairCodec.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2014 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.sched.util.codec;
+
+import com.android.sched.util.config.ChainedException.ChainedExceptionBuilder;
+import com.android.sched.util.config.ConfigurationError;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * This {@link StringCodec} is used to create an instance of {@link Entry}
+ */
+// STOPSHIP see https://android-review.googlesource.com/#/c/120553/17
+public class PairCodec<T, U> implements StringCodec<Entry<T, U>>{
+ @Nonnull
+ private final StringCodec<T> keyParser;
+ @Nonnull
+ private final StringCodec<U> valueParser;
+
+ @Nonnull
+ private String separator = "=";
+
+ public PairCodec(@Nonnull StringCodec<T> keyParser, @Nonnull StringCodec<U> valueParser) {
+ this.keyParser = keyParser;
+ this.valueParser = valueParser;
+ }
+
+ @Nonnull
+ public PairCodec<T, U> on(@Nonnull String separator) {
+ this.separator = separator;
+
+ return this;
+ }
+
+ @Nonnull
+ public String getSeparator() {
+ return separator;
+ }
+
+ @Override
+ @Nonnull
+ public Entry<T, U> parseString(@Nonnull CodecContext context,
+ @Nonnull String string) {
+ int endKey = string.indexOf(separator);
+ if (endKey == -1) {
+ throw new ConfigurationError("Missing '"
+ + separator + "' in '" + string + "'");
+ }
+ String key = string.substring(0, endKey);
+ String valueString = string.substring(endKey + separator.length());
+ return new AbstractMap.SimpleEntry<T, U>(keyParser.parseString(context, key),
+ valueParser.parseString(context, valueString));
+ }
+
+ @Override
+ @CheckForNull
+ public Entry<T, U> checkString(@Nonnull CodecContext context,
+ @Nonnull String string)
+ throws ParsingException {
+
+ ChainedExceptionBuilder<ParsingException> exceptions =
+ new ChainedExceptionBuilder<ParsingException>();
+
+ T keyElement = null;
+ U valueElement = null;
+ int endKey = string.indexOf(separator);
+ if (endKey == -1) {
+ exceptions.appendException(new ParsingException("Missing '"
+ + separator + "' in '" + string + "'"));
+ } else {
+ String key = string.substring(0, endKey);
+ String valueString = string.substring(endKey + separator.length());
+ try {
+ keyElement = keyParser.checkString(context, key);
+ } catch (ParsingException e) {
+ exceptions.appendException(e);
+ }
+ try {
+ valueElement = valueParser.checkString(context, valueString);
+ } catch (ParsingException e) {
+ exceptions.appendException(e);
+ }
+ }
+
+ exceptions.throwIfNecessary();
+ // If one element is null, do not compute the pair
+ if (keyElement == null || valueElement == null) {
+ return null;
+ } else {
+ return new AbstractMap.SimpleEntry<T, U>(keyElement, valueElement);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public String getUsage() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<key>" + separator + "<value>");
+ sb.append(" where <key> is ");
+ sb.append(keyParser.getUsage());
+ sb.append(" and where <value> is ");
+ sb.append(valueParser.getUsage());
+
+ return sb.toString();
+ }
+
+ @Override
+ @Nonnull
+ public List<com.android.sched.util.codec.Parser.ValueDescription> getValueDescriptions() {
+ List<com.android.sched.util.codec.Parser.ValueDescription> list =
+ new ArrayList<Parser.ValueDescription>();
+ list.addAll(keyParser.getValueDescriptions());
+ list.addAll(valueParser.getValueDescriptions());
+ return list;
+ }
+
+ @Override
+ @Nonnull
+ public String formatValue(@Nonnull Entry<T, U> data) {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(keyParser.formatValue(data.getKey()));
+ sb.append(separator);
+ sb.append(valueParser.formatValue(data.getValue()));
+ return sb.toString();
+ }
+
+ @Override
+ public void checkValue(@Nonnull CodecContext context, @Nonnull Entry<T, U> data)
+ throws CheckingException {
+ ChainedExceptionBuilder<CheckingException> exceptions =
+ new ChainedExceptionBuilder<CheckingException>();
+ try {
+ keyParser.checkValue(context, data.getKey());
+ } catch (CheckingException e) {
+ exceptions.appendException(e);
+ }
+ try {
+ valueParser.checkValue(context, data.getValue());
+ } catch (CheckingException e) {
+ exceptions.appendException(e);
+ }
+
+ exceptions.throwIfNecessary();
+ }
+
+}
diff --git a/sched/src/com/android/sched/util/codec/PairListToMapCodecConverter.java b/sched/src/com/android/sched/util/codec/PairListToMapCodecConverter.java
new file mode 100644
index 0000000..b9c9e86
--- /dev/null
+++ b/sched/src/com/android/sched/util/codec/PairListToMapCodecConverter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 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.sched.util.codec;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link ConvertCodec} allowing to convert list of {@link Entry} into a map.
+ */
+public class PairListToMapCodecConverter<T, U> extends
+ ConvertCodec<List<Entry<T, U>>, Map<T, U>> {
+ public PairListToMapCodecConverter(StringCodec<List<Entry<T, U>>> codec) {
+ super(codec);
+ }
+
+ @Override
+ @Nonnull
+ public Map<T, U> parseString(@Nonnull CodecContext context,
+ @Nonnull String string) {
+ List<Entry<T, U>> list = codec.parseString(context, string);
+ Map<T, U> map = new HashMap<T, U>(Math.round(list.size() / 0.75f),
+ 0.75f);
+ for (Entry<T, U> entry : list) {
+ map.put(entry.getKey(), entry.getValue());
+ }
+ return map;
+ }
+
+ @Override
+ @Nonnull
+ public String formatValue(@Nonnull Map<T, U> data) {
+ return codec.formatValue(new ArrayList<Map.Entry<T, U>>(data.entrySet()));
+ }
+
+ @Override
+ public void checkValue(@Nonnull CodecContext context, @Nonnull Map<T, U> data)
+ throws CheckingException {
+ codec.checkValue(context, new ArrayList<Map.Entry<T, U>>(data.entrySet()));
+ }
+} \ No newline at end of file
diff --git a/sched/src/com/android/sched/util/codec/StringValueCodec.java b/sched/src/com/android/sched/util/codec/StringValueCodec.java
new file mode 100644
index 0000000..19e13be
--- /dev/null
+++ b/sched/src/com/android/sched/util/codec/StringValueCodec.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 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.sched.util.codec;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link StringCodec} performing no check nor conversion, just providing a usage.
+ */
+public class StringValueCodec implements StringCodec<String> {
+ @Nonnull
+ private final String usage;
+
+ public StringValueCodec(@Nonnull String usage) {
+ this.usage = usage;
+ }
+
+ @Override
+ @Nonnull
+ public String parseString(@Nonnull CodecContext context, @Nonnull String string) {
+ return string;
+ }
+
+ @Override
+ @CheckForNull
+ public String checkString(@Nonnull CodecContext context, @Nonnull String string) {
+ return string;
+ }
+
+ @Override
+ @Nonnull
+ public String getUsage() {
+ return usage;
+ }
+
+ @Override
+ @Nonnull
+ public List<ValueDescription> getValueDescriptions() {
+ return Collections.<ValueDescription> emptyList();
+ }
+
+ @Override
+ @Nonnull
+ public String formatValue(@Nonnull String data) {
+ return data;
+ }
+
+ @Override
+ public void checkValue(@Nonnull CodecContext context, @Nonnull String data) {
+ }
+} \ No newline at end of file
diff --git a/sched/src/com/android/sched/util/config/id/EnumPropertyId.java b/sched/src/com/android/sched/util/config/id/EnumPropertyId.java
index c209e3c..d98baef 100644
--- a/sched/src/com/android/sched/util/config/id/EnumPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/EnumPropertyId.java
@@ -20,6 +20,7 @@ import com.android.sched.util.codec.EnumCodec;
import com.android.sched.util.config.ConfigChecker;
import com.android.sched.util.config.MissingPropertyException;
import com.android.sched.util.config.PropertyIdException;
+import com.android.sched.util.config.category.Category;
import com.android.sched.util.config.expression.BooleanExpression;
import javax.annotation.Nonnull;
@@ -85,6 +86,13 @@ public class EnumPropertyId<T extends Enum<T>> extends PropertyId<T> {
return this;
}
+ @Override
+ @Nonnull
+ public EnumPropertyId<T> withCategory(@Nonnull Category category) {
+ super.withCategory(category);
+ return this;
+ }
+
@Nonnull
public BooleanExpression is(@Nonnull final T enumValue) {
return new BooleanExpression() {
diff --git a/sched/src/com/android/sched/util/config/id/ListPropertyId.java b/sched/src/com/android/sched/util/config/id/ListPropertyId.java
index 075fa00..fe4e032 100644
--- a/sched/src/com/android/sched/util/config/id/ListPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/ListPropertyId.java
@@ -80,7 +80,7 @@ public class ListPropertyId<T> extends PropertyId<List<T>> {
@Nonnull
public ListPropertyId<T> on(@Nonnull String separator) {
- getCodec().setSeperator(separator);
+ getCodec().setSeparator(separator);
return this;
}