aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-10-14 05:06:17 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-10-14 05:06:17 +0000
commita8ee2dcb9099ae9913b26ec2541aadb88917a598 (patch)
tree6715a6599253a4d8e5a2e111c8e230acd5a5eddd
parentf05c36be101d60aa13d46baab35e98389c1ef5ba (diff)
parent003cdc417e0e1be68beee239c629f4e58d3aa7b4 (diff)
downloadauto-android14-qpr2-release.tar.gz
Change-Id: I35d9bb6ba3723d34def324d98db29ad0ad0d93d0
-rw-r--r--.github/workflows/ci.yml18
-rw-r--r--METADATA6
-rw-r--r--common/pom.xml2
-rw-r--r--factory/pom.xml4
-rw-r--r--factory/src/it/functional/pom.xml2
-rw-r--r--service/pom.xml6
-rw-r--r--value/pom.xml2
-rw-r--r--value/processor/pom.xml15
-rw-r--r--value/src/it/functional/pom.xml4
-rw-r--r--value/src/main/java/com/google/auto/value/processor/AutoValueishProcessor.java23
-rw-r--r--value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java7
-rw-r--r--value/src/main/java/com/google/auto/value/processor/TemplateVars.java91
-rw-r--r--value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java32
-rw-r--r--value/src/test/java/com/google/auto/value/processor/TemplateVarsTest.java146
14 files changed, 120 insertions, 238 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9880de9b..9f385485 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -22,16 +22,16 @@ jobs:
with:
access_token: ${{ github.token }}
- name: 'Check out repository'
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+ uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- name: 'Cache local Maven repository'
- uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+ uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84
with:
path: ~/.m2/repository
key: maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
maven-
- name: 'Set up JDK ${{ matrix.java }}'
- uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2
+ uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2
with:
java-version: ${{ matrix.java }}
distribution: 'zulu'
@@ -49,16 +49,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Check out repository'
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+ uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- name: 'Cache local Maven repository'
- uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+ uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84
with:
path: ~/.m2/repository
key: maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
maven-
- name: 'Set up JDK 11'
- uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2
+ uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2
with:
java-version: 11
distribution: 'zulu'
@@ -78,16 +78,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Check out repository'
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+ uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- name: 'Cache local Maven repository'
- uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
+ uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84
with:
path: ~/.m2/repository
key: maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
maven-
- name: 'Set up JDK 11'
- uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2
+ uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2
with:
java-version: 11
distribution: 'zulu'
diff --git a/METADATA b/METADATA
index 3fabcf89..cb4cce79 100644
--- a/METADATA
+++ b/METADATA
@@ -13,11 +13,11 @@ third_party {
type: GIT
value: "https://github.com/google/auto"
}
- version: "auto-value-1.10.2"
+ version: "auto-value-1.10.4"
license_type: NOTICE
last_upgrade_date {
year: 2023
- month: 8
- day: 2
+ month: 10
+ day: 12
}
}
diff --git a/common/pom.xml b/common/pom.xml
index 63cf9427..f4fe00e4 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -36,7 +36,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
- <guava.version>32.0.1-jre</guava.version>
+ <guava.version>32.1.2-jre</guava.version>
<truth.version>1.1.3</truth.version>
</properties>
diff --git a/factory/pom.xml b/factory/pom.xml
index 0e1bdd22..ee914489 100644
--- a/factory/pom.xml
+++ b/factory/pom.xml
@@ -31,9 +31,9 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<auto-service.version>1.1.1</auto-service.version>
- <auto-value.version>1.10.1</auto-value.version>
+ <auto-value.version>1.10.3</auto-value.version>
<java.version>1.8</java.version>
- <guava.version>32.0.1-jre</guava.version>
+ <guava.version>32.1.2-jre</guava.version>
<truth.version>1.1.5</truth.version>
</properties>
diff --git a/factory/src/it/functional/pom.xml b/factory/src/it/functional/pom.xml
index 8a87a10f..7359ec1a 100644
--- a/factory/src/it/functional/pom.xml
+++ b/factory/src/it/functional/pom.xml
@@ -45,7 +45,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
- <version>31.1-jre</version>
+ <version>32.1.2-jre</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
diff --git a/service/pom.xml b/service/pom.xml
index e29cc06c..a6e0d071 100644
--- a/service/pom.xml
+++ b/service/pom.xml
@@ -37,8 +37,8 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
- <guava.version>32.0.1-jre</guava.version>
- <truth.version>1.1.3</truth.version>
+ <guava.version>32.1.2-jre</guava.version>
+ <truth.version>1.1.5</truth.version>
</properties>
<scm>
@@ -90,7 +90,7 @@
<dependency>
<groupId>com.google.testing.compile</groupId>
<artifactId>compile-testing</artifactId>
- <version>0.19</version>
+ <version>0.21.0</version>
</dependency>
<dependency>
<groupId>com.google.truth</groupId>
diff --git a/value/pom.xml b/value/pom.xml
index a1fb0ffd..f44edd6b 100644
--- a/value/pom.xml
+++ b/value/pom.xml
@@ -31,7 +31,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
- <guava.version>32.0.1-jre</guava.version>
+ <guava.version>32.1.2-jre</guava.version>
<truth.version>1.1.5</truth.version>
</properties>
diff --git a/value/processor/pom.xml b/value/processor/pom.xml
index 6999c477..a93c7765 100644
--- a/value/processor/pom.xml
+++ b/value/processor/pom.xml
@@ -41,7 +41,7 @@
<properties>
<auto-service.version>1.1.1</auto-service.version>
- <errorprone.version>2.20.0</errorprone.version>
+ <errorprone.version>2.21.1</errorprone.version>
</properties>
<dependencies>
@@ -81,7 +81,7 @@
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-metadata-jvm</artifactId>
- <version>0.6.2</version>
+ <version>0.7.0</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
@@ -230,6 +230,17 @@
<exclude>com.google.code.findbugs:jsr305</exclude>
</excludes>
</artifactSet>
+ <filters>
+ <filter>
+ <artifact>*:*</artifact>
+ <excludes>
+ <!-- Don't include kotlinx-metadata.kotlin_module, etc. We're shading those
+ libaries and they're only used from Java. Leaving them in the jar creates
+ "incompatible version" errors from the Kotlin compiler. -->
+ <exclude>META-INF/*.kotlin_module</exclude>
+ </excludes>
+ </filter>
+ </filters>
<transformers>
<!-- Needed to avoid "No MetadataExtensions instances found in the classpath" from Kotlin reflection. -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
diff --git a/value/src/it/functional/pom.xml b/value/src/it/functional/pom.xml
index 414d6c59..bf92f4a1 100644
--- a/value/src/it/functional/pom.xml
+++ b/value/src/it/functional/pom.xml
@@ -32,7 +32,7 @@
<version>HEAD-SNAPSHOT</version>
<name>Auto-Value Functional Integration Test</name>
<properties>
- <kotlin.version>1.8.22</kotlin.version>
+ <kotlin.version>1.9.10</kotlin.version>
</properties>
<dependencies>
<dependency>
@@ -92,7 +92,7 @@
<dependency>
<groupId>dev.gradleplugins</groupId>
<artifactId>gradle-test-kit</artifactId>
- <version>8.1</version>
+ <version>8.3</version>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/value/src/main/java/com/google/auto/value/processor/AutoValueishProcessor.java b/value/src/main/java/com/google/auto/value/processor/AutoValueishProcessor.java
index b7bee429..82d31bf8 100644
--- a/value/src/main/java/com/google/auto/value/processor/AutoValueishProcessor.java
+++ b/value/src/main/java/com/google/auto/value/processor/AutoValueishProcessor.java
@@ -17,6 +17,7 @@ package com.google.auto.value.processor;
import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
import static com.google.auto.common.GeneratedAnnotations.generatedAnnotation;
+import static com.google.auto.common.MoreElements.asType;
import static com.google.auto.common.MoreElements.getPackage;
import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.auto.common.MoreStreams.toImmutableList;
@@ -1215,8 +1216,24 @@ abstract class AutoValueishProcessor extends AbstractProcessor {
private ImmutableList<AnnotationMirror> propertyFieldAnnotations(
TypeElement type, ExecutableElement method) {
+ // We need to exclude type annotations from the ones being output on the method, since
+ // they will be output as part of the field's type.
+ Set<String> returnTypeAnnotations =
+ getReturnTypeAnnotations(method, this::annotationAppliesToFields);
if (!hasAnnotationMirror(method, COPY_ANNOTATIONS_NAME)) {
- return ImmutableList.of();
+ // If there's no @CopyAnnotations, we will still copy a @Nullable annotation, if (1) it is not
+ // a TYPE_USE annotation (those appear as part of the type in the generated code) and (2) it
+ // applies to fields. All known non-TYPE_USE @Nullable annotations do apply to fields, but we
+ // check just in case.
+ return method.getAnnotationMirrors().stream()
+ .filter(
+ a -> {
+ TypeElement annotationType = asType(a.getAnnotationType().asElement());
+ return isNullable(a)
+ && !returnTypeAnnotations.contains(annotationType.getQualifiedName().toString())
+ && annotationAppliesToFields(annotationType);
+ })
+ .collect(toImmutableList());
}
ImmutableSet<String> excludedAnnotations =
ImmutableSet.<String>builder()
@@ -1224,10 +1241,6 @@ abstract class AutoValueishProcessor extends AbstractProcessor {
.add(Override.class.getCanonicalName())
.build();
- // We need to exclude type annotations from the ones being output on the method, since
- // they will be output as part of the field's type.
- Set<String> returnTypeAnnotations =
- getReturnTypeAnnotations(method, this::annotationAppliesToFields);
Set<String> nonFieldAnnotations =
method.getAnnotationMirrors().stream()
.map(a -> a.getAnnotationType().asElement())
diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java
index b0872009..591b0cc8 100644
--- a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java
+++ b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java
@@ -403,6 +403,13 @@ abstract class BuilderMethodClassifier<E extends Element> {
TypeMirror returnType = methodMirror.getReturnType();
if (typeUtils.isSubtype(builderType.asType(), returnType)
&& !MoreTypes.isTypeOf(Object.class, returnType)) {
+ if (nullableAnnotationFor(method, returnType).isPresent()) {
+ errorReporter.
+ reportWarning(
+ method,
+ "[%sBuilderSetterNullable] Setter methods always return the Builder so @Nullable"
+ + " is not appropriate", autoWhat());
+ }
// We allow the return type to be a supertype (other than Object), to support step builders.
TypeMirror parameterType = Iterables.getOnlyElement(methodMirror.getParameterTypes());
propertyNameToSetters.put(
diff --git a/value/src/main/java/com/google/auto/value/processor/TemplateVars.java b/value/src/main/java/com/google/auto/value/processor/TemplateVars.java
index d9e3337b..73253629 100644
--- a/value/src/main/java/com/google/auto/value/processor/TemplateVars.java
+++ b/value/src/main/java/com/google/auto/value/processor/TemplateVars.java
@@ -15,27 +15,28 @@
*/
package com.google.auto.value.processor;
-import com.google.common.base.Throwables;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.io.ByteStreams;
import com.google.escapevelocity.Template;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
-import java.io.UnsupportedEncodingException;
+import java.io.StringReader;
+import java.io.UncheckedIOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
-import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.TreeMap;
-import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
@@ -95,7 +96,7 @@ abstract class TemplateVars {
* concrete subclass of TemplateVars) into the template returned by {@link #parsedTemplate()}.
*/
String toText() {
- Map<String, Object> vars = toVars();
+ ImmutableMap<String, Object> vars = toVars();
return parsedTemplate().evaluate(vars);
}
@@ -121,69 +122,42 @@ abstract class TemplateVars {
static Template parsedTemplateForResource(String resourceName) {
try {
- return Template.parseFrom(resourceName, TemplateVars::readerFromResource);
- } catch (UnsupportedEncodingException e) {
- throw new AssertionError(e);
- } catch (IOException | NullPointerException | IllegalStateException e) {
- // https://github.com/google/auto/pull/439 says that we can get NullPointerException.
- // https://github.com/google/auto/issues/715 says that we can get IllegalStateException
- return retryParseAfterException(resourceName, e);
- }
- }
-
- private static Template retryParseAfterException(String resourceName, Exception exception) {
- try {
return Template.parseFrom(resourceName, TemplateVars::readerFromUrl);
- } catch (IOException t) {
- // Chain the original exception so we can see both problems.
- Throwables.getRootCause(exception).initCause(t);
- throw new AssertionError(exception);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
}
}
- private static Reader readerFromResource(String resourceName) {
- InputStream in = TemplateVars.class.getResourceAsStream(resourceName);
- if (in == null) {
- throw new IllegalArgumentException("Could not find resource: " + resourceName);
- }
- return new InputStreamReader(in, StandardCharsets.UTF_8);
- }
-
// This is an ugly workaround for https://bugs.openjdk.java.net/browse/JDK-6947916, as
// reported in https://github.com/google/auto/issues/365.
// The issue is that sometimes the InputStream returned by JarURLCollection.getInputStream()
// can be closed prematurely, which leads to an IOException saying "Stream closed".
- // We catch all IOExceptions, and fall back on logic that opens the jar file directly and
- // loads the resource from it. Since that doesn't use JarURLConnection, it shouldn't be
- // susceptible to the same bug. We only use this as fallback logic rather than doing it always,
- // because jars are memory-mapped by URLClassLoader, so loading a resource in the usual way
- // through the getResourceAsStream should be a lot more efficient than reopening the jar.
+ // To avoid that issue, we open the jar file directly and load the resource from it. Since that
+ // doesn't use JarURLConnection, it shouldn't be susceptible to the same bug.
private static Reader readerFromUrl(String resourceName) throws IOException {
URL resourceUrl = TemplateVars.class.getResource(resourceName);
if (resourceUrl == null) {
- // This is unlikely, since getResourceAsStream has already succeeded for the same resource.
throw new IllegalArgumentException("Could not find resource: " + resourceName);
}
- InputStream in;
try {
- if (resourceUrl.getProtocol().equalsIgnoreCase("file")) {
- in = inputStreamFromFile(resourceUrl);
- } else if (resourceUrl.getProtocol().equalsIgnoreCase("jar")) {
- in = inputStreamFromJar(resourceUrl);
+ if (Ascii.equalsIgnoreCase(resourceUrl.getProtocol(), "file")) {
+ return readerFromFile(resourceUrl);
+ } else if (Ascii.equalsIgnoreCase(resourceUrl.getProtocol(), "jar")) {
+ return readerFromJar(resourceUrl);
} else {
- throw new AssertionError("Template fallback logic fails for: " + resourceUrl);
+ throw new AssertionError("Template search logic fails for: " + resourceUrl);
}
} catch (URISyntaxException e) {
throw new IOException(e);
}
- return new InputStreamReader(in, StandardCharsets.UTF_8);
}
- private static InputStream inputStreamFromJar(URL resourceUrl)
- throws URISyntaxException, IOException {
+ private static Reader readerFromJar(URL resourceUrl) throws URISyntaxException, IOException {
// Jar URLs look like this: jar:file:/path/to/file.jar!/entry/within/jar
// So take apart the URL to open the jar /path/to/file.jar and read the entry
// entry/within/jar from it.
+ // We could use the methods from JarURLConnection here, but that would risk provoking the same
+ // problem that prompted this workaround in the first place.
String resourceUrlString = resourceUrl.toString().substring("jar:".length());
int bang = resourceUrlString.lastIndexOf('!');
String entryName = resourceUrlString.substring(bang + 1);
@@ -191,28 +165,19 @@ abstract class TemplateVars {
entryName = entryName.substring(1);
}
URI jarUri = new URI(resourceUrlString.substring(0, bang));
- JarFile jar = new JarFile(new File(jarUri));
- JarEntry entry = jar.getJarEntry(entryName);
- InputStream in = jar.getInputStream(entry);
- // We have to be careful not to close the JarFile before the stream has been read, because
- // that would also close the stream. So we defer closing the JarFile until the stream is closed.
- return new FilterInputStream(in) {
- @Override
- public void close() throws IOException {
- super.close();
- jar.close();
- }
- };
+ try (JarFile jar = new JarFile(new File(jarUri));
+ InputStream in = jar.getInputStream(jar.getJarEntry(entryName))) {
+ String contents = new String(ByteStreams.toByteArray(in), UTF_8);
+ return new StringReader(contents);
+ }
}
- // We don't really expect this case to arise, since the bug we're working around concerns jars
- // not individual files. However, when running the test for this workaround from Maven, we do
- // have files. That does mean the test is basically useless there, but Google's internal build
- // system does run it using a jar, so we do have coverage.
- private static InputStream inputStreamFromFile(URL resourceUrl)
+ // In most execution environments, we'll be dealing with a jar, but we handle individual files
+ // just for cases like running our tests with Maven.
+ private static Reader readerFromFile(URL resourceUrl)
throws IOException, URISyntaxException {
File resourceFile = new File(resourceUrl.toURI());
- return new FileInputStream(resourceFile);
+ return new InputStreamReader(new FileInputStream(resourceFile), UTF_8);
}
private static Object fieldValue(Field field, Object container) {
diff --git a/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java
index 01ec81fe..d30198cf 100644
--- a/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java
@@ -1163,6 +1163,7 @@ public class AutoValueCompilationTest {
"final class AutoValue_Baz<T extends Number> extends Baz<T> {",
" private final int anInt;",
" private final byte[] aByteArray;",
+ " @Nullable",
" private final int[] aNullableIntArray;",
" private final List<T> aList;",
" private final ImmutableMap<T, String> anImmutableMap;",
@@ -2038,6 +2039,37 @@ public class AutoValueCompilationTest {
}
@Test
+ public void autoValueBuilderSetterReturnsNullable() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoValue;",
+ "import javax.annotation.Nullable;",
+ "",
+ "@AutoValue",
+ "public abstract class Baz {",
+ " abstract String blam();",
+ "",
+ " @AutoValue.Builder",
+ " public interface Builder {",
+ " @Nullable Builder blam(String x);",
+ " Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
+ .compile(javaFileObject);
+ assertThat(compilation)
+ .hadWarningContaining(
+ "Setter methods always return the Builder so @Nullable is not appropriate")
+ .inFile(javaFileObject)
+ .onLineContaining("Builder blam(String x)");
+ }
+
+ @Test
public void autoValueBuilderWrongTypeSetterWithCopyOf() {
JavaFileObject javaFileObject =
JavaFileObjects.forSourceLines(
diff --git a/value/src/test/java/com/google/auto/value/processor/TemplateVarsTest.java b/value/src/test/java/com/google/auto/value/processor/TemplateVarsTest.java
index bca7bcab..621a4122 100644
--- a/value/src/test/java/com/google/auto/value/processor/TemplateVarsTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/TemplateVarsTest.java
@@ -15,29 +15,15 @@
*/
package com.google.auto.value.processor;
-import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH;
-import static com.google.common.base.StandardSystemProperty.PATH_SEPARATOR;
import static com.google.common.truth.Truth.assertThat;
-import static java.util.logging.Level.WARNING;
import static org.junit.Assert.fail;
-import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
-import com.google.common.reflect.Reflection;
import com.google.escapevelocity.Template;
-import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.Callable;
-import java.util.logging.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -172,136 +158,4 @@ public class TemplateVarsTest {
} catch (IllegalArgumentException expected) {
}
}
-
- @Test
- public void testBrokenInputStream_IOException() throws Exception {
- doTestBrokenInputStream(new IOException("BrokenInputStream"));
- }
-
- @Test
- public void testBrokenInputStream_NullPointerException() throws Exception {
- doTestBrokenInputStream(new NullPointerException("BrokenInputStream"));
- }
-
- @Test
- public void testBrokenInputStream_IllegalStateException() throws Exception {
- doTestBrokenInputStream(new IllegalStateException("BrokenInputStream"));
- }
-
- // This is a complicated test that tries to simulates the failures that are worked around in
- // Template.parsedTemplateForResource. Those failures means that the InputStream returned by
- // ClassLoader.getResourceAsStream sometimes throws IOException or NullPointerException or
- // IllegalStateException while it is being read. To simulate that, we make a second ClassLoader
- // with the same configuration as the one that runs this test, and we override getResourceAsStream
- // so that it wraps the returned InputStream in a BrokenInputStream, which throws an exception
- // after a certain number of characters. We check that that exception was indeed seen, and that
- // we did indeed try to read the resource we're interested in, and that we succeeded in loading a
- // Template nevertheless.
- private void doTestBrokenInputStream(Exception exception) throws Exception {
- URLClassLoader shadowLoader = new ShadowLoader(getClass().getClassLoader(), exception);
- Runnable brokenInputStreamTest =
- (Runnable)
- shadowLoader
- .loadClass(BrokenInputStreamTest.class.getName())
- .getConstructor()
- .newInstance();
- brokenInputStreamTest.run();
- }
-
- private static class ShadowLoader extends URLClassLoader implements Callable<Set<String>> {
-
- private static final Logger logger = Logger.getLogger(ShadowLoader.class.getName());
-
- private final Exception exception;
- private final Set<String> result = new TreeSet<String>();
-
- ShadowLoader(ClassLoader original, Exception exception) {
- super(getClassPathUrls(original), original.getParent());
- this.exception = exception;
- }
-
- private static URL[] getClassPathUrls(ClassLoader original) {
- return original instanceof URLClassLoader
- ? ((URLClassLoader) original).getURLs()
- : parseJavaClassPath();
- }
-
- /**
- * Returns the URLs in the class path specified by the {@code java.class.path} {@linkplain
- * System#getProperty system property}.
- */
- // TODO(b/65488446): Use a new public API.
- private static URL[] parseJavaClassPath() {
- ImmutableList.Builder<URL> urls = ImmutableList.builder();
- for (String entry : Splitter.on(PATH_SEPARATOR.value()).split(JAVA_CLASS_PATH.value())) {
- try {
- try {
- urls.add(new File(entry).toURI().toURL());
- } catch (SecurityException e) { // File.toURI checks to see if the file is a directory
- urls.add(new URL("file", null, new File(entry).getAbsolutePath()));
- }
- } catch (MalformedURLException e) {
- logger.log(WARNING, "malformed classpath entry: " + entry, e);
- }
- }
- return urls.build().toArray(new URL[0]);
- }
-
- @Override
- public Set<String> call() throws Exception {
- return result;
- }
-
- @Override
- public InputStream getResourceAsStream(String resource) {
- // Make sure this is actually the resource we are expecting. If we're using JaCoCo or the
- // like, we might end up reading some other resource, and we don't want to break that.
- if (resource.startsWith("com/google/auto")) {
- result.add(resource);
- return new BrokenInputStream(super.getResourceAsStream(resource));
- } else {
- return super.getResourceAsStream(resource);
- }
- }
-
- private class BrokenInputStream extends InputStream {
- private final InputStream original;
- private int count = 0;
-
- BrokenInputStream(InputStream original) {
- this.original = original;
- }
-
- @Override
- public int read() throws IOException {
- if (++count > 10) {
- result.add("threw");
- if (exception instanceof IOException) {
- throw (IOException) exception;
- }
- throw (RuntimeException) exception;
- }
- return original.read();
- }
- }
- }
-
- public static class BrokenInputStreamTest implements Runnable {
- @Override
- public void run() {
- Template template = TemplateVars.parsedTemplateForResource("autovalue.vm");
- assertThat(template).isNotNull();
- String resourceName =
- Reflection.getPackageName(getClass()).replace('.', '/') + "/autovalue.vm";
- @SuppressWarnings("unchecked")
- Callable<Set<String>> myLoader = (Callable<Set<String>>) getClass().getClassLoader();
- try {
- Set<String> result = myLoader.call();
- assertThat(result).contains(resourceName);
- assertThat(result).contains("threw");
- } catch (Exception e) {
- throw new AssertionError(e);
- }
- }
- }
}