diff options
author | Éamonn McManus <emcmanus@google.com> | 2020-12-15 11:35:31 -0800 |
---|---|---|
committer | Google Java Core Libraries <java-core-libraries-team+copybara@google.com> | 2020-12-15 11:36:12 -0800 |
commit | 3141e796b907acaec6d88c0affeffea2d9a37cdb (patch) | |
tree | da06878417bf9d637bafb20eadf47020fb8dba29 /factory | |
parent | 9cc29ca31a07cc94d205b306b5c8d8ec2314658b (diff) | |
download | auto-3141e796b907acaec6d88c0affeffea2d9a37cdb.tar.gz |
Handle `@AutoFactory` constructors that throw checked exceptions.
The generated `create` method needs to declare the same exceptions.
Fixes https://github.com/google/auto/issues/90.
RELNOTES=`@AutoFactory` constructors can now declare checked exceptions. The same exceptions will be declared on the generated `create` method.
PiperOrigin-RevId: 347657308
Diffstat (limited to 'factory')
13 files changed, 262 insertions, 12 deletions
diff --git a/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryProcessor.java b/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryProcessor.java index b07786a5..91ad9462 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryProcessor.java +++ b/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryProcessor.java @@ -192,6 +192,7 @@ public final class AutoFactoryProcessor extends AbstractProcessor { .publicMethod() .passedParameters(passedParameters) .isVarArgs(implementationMethod.isVarArgs()) + .exceptions(implementationMethod.getThrownTypes()) .build()); } } diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptor.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptor.java index 090ac27a..670d8fba 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptor.java +++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptor.java @@ -194,12 +194,12 @@ abstract class FactoryDescriptor { duplicateMethodDescriptors.get(methodDescriptor); FactoryMethodDescriptor newMethodDescriptor = - (duplicateMethodDescriptor != null) - ? methodDescriptor - .toBuilder() + (duplicateMethodDescriptor != null) + ? methodDescriptor.toBuilder() .overridingMethod(true) .publicMethod(duplicateMethodDescriptor.publicMethod()) .returnType(duplicateMethodDescriptor.returnType()) + .exceptions(duplicateMethodDescriptor.exceptions()) .build() : methodDescriptor; deduplicatedMethodDescriptors.add(newMethodDescriptor); diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptorGenerator.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptorGenerator.java index 4faa6e7a..0816aef4 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptorGenerator.java +++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptorGenerator.java @@ -134,6 +134,8 @@ final class FactoryDescriptorGenerator { .passedParameters(passedParameters) .creationParameters(Parameter.forParameterList(constructor.getParameters(), types)) .isVarArgs(constructor.isVarArgs()) + .exceptions(constructor.getThrownTypes()) + .overridingMethod(false) .build(); } @@ -144,9 +146,12 @@ final class FactoryDescriptorGenerator { .name("create") .returnType(type.asType()) .publicMethod(type.getModifiers().contains(PUBLIC)) + .providedParameters(ImmutableSet.of()) .passedParameters(ImmutableSet.of()) .creationParameters(ImmutableSet.of()) - .providedParameters(ImmutableSet.of()) + .isVarArgs(false) + .exceptions(ImmutableSet.of()) + .overridingMethod(false) .build()); } } diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryMethodDescriptor.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryMethodDescriptor.java index 43e5097d..5f4ad294 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/FactoryMethodDescriptor.java +++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryMethodDescriptor.java @@ -38,8 +38,9 @@ abstract class FactoryMethodDescriptor { abstract ImmutableSet<Parameter> passedParameters(); abstract ImmutableSet<Parameter> providedParameters(); abstract ImmutableSet<Parameter> creationParameters(); - abstract Builder toBuilder(); abstract boolean isVarArgs(); + abstract ImmutableSet<TypeMirror> exceptions(); + abstract Builder toBuilder(); final PackageAndClass factoryName() { return declaration().getFactoryName(); @@ -47,10 +48,7 @@ abstract class FactoryMethodDescriptor { static Builder builder(AutoFactoryDeclaration declaration) { return new AutoValue_FactoryMethodDescriptor.Builder() - .declaration(checkNotNull(declaration)) - .publicMethod(false) - .overridingMethod(false) - .isVarArgs(false); + .declaration(checkNotNull(declaration)); } @AutoValue.Builder @@ -64,6 +62,7 @@ abstract class FactoryMethodDescriptor { abstract Builder providedParameters(Iterable<Parameter> providedParameters); abstract Builder creationParameters(Iterable<Parameter> creationParameters); abstract Builder isVarArgs(boolean isVarargs); + abstract Builder exceptions(Iterable<? extends TypeMirror> exceptions); abstract FactoryMethodDescriptor buildImpl(); FactoryMethodDescriptor build() { diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java index b1ba2f18..3dbcf41c 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java +++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java @@ -20,6 +20,7 @@ import static com.squareup.javapoet.MethodSpec.constructorBuilder; import static com.squareup.javapoet.MethodSpec.methodBuilder; import static com.squareup.javapoet.TypeSpec.classBuilder; import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PRIVATE; import static javax.lang.model.element.Modifier.PUBLIC; @@ -152,6 +153,8 @@ final class FactoryWriter { if (methodDescriptor.publicMethod()) { method.addModifiers(PUBLIC); } + method.addExceptions( + methodDescriptor.exceptions().stream().map(TypeName::get).collect(toList())); CodeBlock.Builder args = CodeBlock.builder(); method.addParameters(parameters(methodDescriptor.passedParameters())); Iterator<Parameter> parameters = methodDescriptor.creationParameters().iterator(); @@ -199,6 +202,8 @@ final class FactoryWriter { if (methodDescriptor.publicMethod()) { implementationMethod.addModifiers(PUBLIC); } + implementationMethod.addExceptions( + methodDescriptor.exceptions().stream().map(TypeName::get).collect(toList())); implementationMethod.addParameters(parameters(methodDescriptor.passedParameters())); implementationMethod.addStatement( "return create($L)", diff --git a/factory/src/main/java/com/google/auto/factory/processor/ImplementationMethodDescriptor.java b/factory/src/main/java/com/google/auto/factory/processor/ImplementationMethodDescriptor.java index b7367a6c..b5faa272 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/ImplementationMethodDescriptor.java +++ b/factory/src/main/java/com/google/auto/factory/processor/ImplementationMethodDescriptor.java @@ -26,11 +26,10 @@ abstract class ImplementationMethodDescriptor { abstract boolean publicMethod(); abstract ImmutableSet<Parameter> passedParameters(); abstract boolean isVarArgs(); + abstract ImmutableSet<TypeMirror> exceptions(); static Builder builder() { - return new AutoValue_ImplementationMethodDescriptor.Builder() - .publicMethod(true) - .isVarArgs(false); + return new AutoValue_ImplementationMethodDescriptor.Builder(); } @AutoValue.Builder @@ -49,6 +48,8 @@ abstract class ImplementationMethodDescriptor { abstract Builder isVarArgs(boolean isVarargs); + abstract Builder exceptions(Iterable<? extends TypeMirror> exceptions); + abstract ImplementationMethodDescriptor build(); } } diff --git a/factory/src/test/java/com/google/auto/factory/processor/AutoFactoryProcessorTest.java b/factory/src/test/java/com/google/auto/factory/processor/AutoFactoryProcessorTest.java index de3af5fb..9593139a 100644 --- a/factory/src/test/java/com/google/auto/factory/processor/AutoFactoryProcessorTest.java +++ b/factory/src/test/java/com/google/auto/factory/processor/AutoFactoryProcessorTest.java @@ -49,6 +49,16 @@ public class AutoFactoryProcessorTest { } @Test + public void simpleClassWithConstructorThrowsClause() { + Compilation compilation = + javac.compile(JavaFileObjects.forResource("good/SimpleClassThrows.java")); + assertThat(compilation).succeededWithoutWarnings(); + assertThat(compilation) + .generatedSourceFile("tests.SimpleClassThrowsFactory") + .hasSourceEquivalentTo(loadExpectedFile("expected/SimpleClassThrowsFactory.java")); + } + + @Test public void nestedClasses() { Compilation compilation = javac.compile(JavaFileObjects.forResource("good/NestedClasses.java")); assertThat(compilation).succeededWithoutWarnings(); @@ -150,6 +160,15 @@ public class AutoFactoryProcessorTest { } @Test + public void constructorWithThrowsClauseAnnotated() { + Compilation compilation = + javac.compile(JavaFileObjects.forResource("good/ConstructorAnnotatedThrows.java")); + assertThat(compilation).succeededWithoutWarnings(); + assertThat(compilation) + .generatedSourceFile("tests.ConstructorAnnotatedThrowsFactory") + .hasSourceEquivalentTo(loadExpectedFile("expected/ConstructorAnnotatedThrowsFactory.java")); + } + @Test public void constructorAnnotatedNonFinal() { Compilation compilation = javac.compile(JavaFileObjects.forResource("good/ConstructorAnnotatedNonFinal.java")); @@ -257,6 +276,17 @@ public class AutoFactoryProcessorTest { } @Test + public void factoryWithConstructorThrowsClauseExtendingAbstractClass() { + Compilation compilation = + javac.compile(JavaFileObjects.forResource("good/FactoryExtendingAbstractClassThrows.java")); + assertThat(compilation).succeededWithoutWarnings(); + assertThat(compilation) + .generatedSourceFile("tests.FactoryExtendingAbstractClassThrowsFactory") + .hasSourceEquivalentTo( + loadExpectedFile("expected/FactoryExtendingAbstractClassThrowsFactory.java")); + } + + @Test public void factoryExtendingAbstractClass_withConstructorParams() { JavaFileObject file = JavaFileObjects.forResource("bad/FactoryExtendingAbstractClassWithConstructorParams.java"); diff --git a/factory/src/test/resources/expected/ConstructorAnnotatedThrowsFactory.java b/factory/src/test/resources/expected/ConstructorAnnotatedThrowsFactory.java new file mode 100644 index 00000000..13f9e994 --- /dev/null +++ b/factory/src/test/resources/expected/ConstructorAnnotatedThrowsFactory.java @@ -0,0 +1,58 @@ +/* + * Copyright 2020 Google LLC + * + * 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 tests; + +import java.io.IOException; +import javax.annotation.processing.Generated; +import javax.inject.Inject; +import javax.inject.Provider; + +@Generated( + value = "com.google.auto.factory.processor.AutoFactoryProcessor", + comments = "https://github.com/google/auto/tree/master/factory" + ) +final class ConstructorAnnotatedThrowsFactory { + private final Provider<Object> objProvider; + + @Inject ConstructorAnnotatedThrowsFactory(Provider<Object> objProvider) { + this.objProvider = checkNotNull(objProvider, 1); + } + + ConstructorAnnotatedThrows create() throws IOException, InterruptedException { + return new ConstructorAnnotatedThrows(); + } + + ConstructorAnnotatedThrows create(String s) { + return new ConstructorAnnotatedThrows(checkNotNull(s, 1)); + } + + ConstructorAnnotatedThrows create(int i) throws IOException { + return new ConstructorAnnotatedThrows(checkNotNull(objProvider.get(), 1), i); + } + + ConstructorAnnotatedThrows create(char c) throws InterruptedException { + return new ConstructorAnnotatedThrows(checkNotNull(objProvider.get(), 1), c); + } + + private static <T> T checkNotNull(T reference, int argumentIndex) { + if (reference == null) { + throw new NullPointerException( + "@AutoFactory method argument is null but is not marked @Nullable. Argument index: " + + argumentIndex); + } + return reference; + } +} diff --git a/factory/src/test/resources/expected/FactoryExtendingAbstractClassThrowsFactory.java b/factory/src/test/resources/expected/FactoryExtendingAbstractClassThrowsFactory.java new file mode 100644 index 00000000..c2640f54 --- /dev/null +++ b/factory/src/test/resources/expected/FactoryExtendingAbstractClassThrowsFactory.java @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Google LLC + * + * 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 tests; + +import java.io.IOException; +import javax.annotation.processing.Generated; +import javax.inject.Inject; + +@Generated( + value = "com.google.auto.factory.processor.AutoFactoryProcessor", + comments = "https://github.com/google/auto/tree/master/factory" + ) +final class FactoryExtendingAbstractClassThrowsFactory + extends FactoryExtendingAbstractClassThrows.AbstractFactory { + @Inject FactoryExtendingAbstractClassThrowsFactory() {} + + FactoryExtendingAbstractClassThrows create() throws IOException, InterruptedException { + return new FactoryExtendingAbstractClassThrows(); + } + + @Override public FactoryExtendingAbstractClassThrows newInstance() throws Exception { + return create(); + } +} diff --git a/factory/src/test/resources/expected/SimpleClassThrowsFactory.java b/factory/src/test/resources/expected/SimpleClassThrowsFactory.java new file mode 100644 index 00000000..d54dd528 --- /dev/null +++ b/factory/src/test/resources/expected/SimpleClassThrowsFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Google LLC + * + * 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 tests; + +import java.io.IOException; +import javax.annotation.processing.Generated; +import javax.inject.Inject; + +@Generated( + value = "com.google.auto.factory.processor.AutoFactoryProcessor", + comments = "https://github.com/google/auto/tree/master/factory" + ) +final class SimpleClassThrowsFactory { + @Inject SimpleClassThrowsFactory() {} + + SimpleClassThrows create() throws IOException, InterruptedException { + return new SimpleClassThrows(); + } +} diff --git a/factory/src/test/resources/good/ConstructorAnnotatedThrows.java b/factory/src/test/resources/good/ConstructorAnnotatedThrows.java new file mode 100644 index 00000000..1a22f562 --- /dev/null +++ b/factory/src/test/resources/good/ConstructorAnnotatedThrows.java @@ -0,0 +1,29 @@ +/* + * Copyright 2020 Google LLC + * + * 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 tests; + +import com.google.auto.factory.AutoFactory; +import com.google.auto.factory.Provided; +import java.io.IOException; + +final class ConstructorAnnotatedThrows { + @AutoFactory ConstructorAnnotatedThrows() throws IOException, InterruptedException {} + ConstructorAnnotatedThrows(Object obj) {} + @AutoFactory ConstructorAnnotatedThrows(String s) {} + @AutoFactory ConstructorAnnotatedThrows(@Provided Object obj, int i) throws IOException {} + @AutoFactory ConstructorAnnotatedThrows(@Provided Object obj, char c) + throws InterruptedException {} +} diff --git a/factory/src/test/resources/good/FactoryExtendingAbstractClassThrows.java b/factory/src/test/resources/good/FactoryExtendingAbstractClassThrows.java new file mode 100644 index 00000000..52ce2aaa --- /dev/null +++ b/factory/src/test/resources/good/FactoryExtendingAbstractClassThrows.java @@ -0,0 +1,29 @@ +/* + * Copyright 2020 Google LLC + * + * 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 tests; + +import com.google.auto.factory.AutoFactory; +import java.io.IOException; +import tests.FactoryExtendingAbstractClassThrows.AbstractFactory; + +@AutoFactory(extending = AbstractFactory.class) +final class FactoryExtendingAbstractClassThrows { + FactoryExtendingAbstractClassThrows() throws IOException, InterruptedException {} + + static abstract class AbstractFactory { + abstract FactoryExtendingAbstractClassThrows newInstance() throws Exception; + } +} diff --git a/factory/src/test/resources/good/SimpleClassThrows.java b/factory/src/test/resources/good/SimpleClassThrows.java new file mode 100644 index 00000000..67155952 --- /dev/null +++ b/factory/src/test/resources/good/SimpleClassThrows.java @@ -0,0 +1,24 @@ +/* + * Copyright 2020 Google LLC + * + * 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 tests; + +import com.google.auto.factory.AutoFactory; +import java.io.IOException; + +@AutoFactory +final class SimpleClassThrows { + SimpleClassThrows() throws IOException, InterruptedException {} +} |