aboutsummaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorÉamonn McManus <emcmanus@google.com>2023-05-16 11:34:16 -0700
committerGoogle Java Core Libraries <java-libraries-firehose+copybara@google.com>2023-05-16 11:35:35 -0700
commit591731c32a6b425a43023335fb062c247fd65e63 (patch)
tree9dea1056b9d8c2996e4044a4f5d3726fe20807f8 /service
parenta5c82e122f1e72b93b2244e767a69b5415c50d9a (diff)
downloadauto-591731c32a6b425a43023335fb062c247fd65e63.tar.gz
Reject an `@AutoService` type if it is an interface or abstract class.
RELNOTES=The `@AutoService` annotation can no longer be applied to an interface or abstract class. PiperOrigin-RevId: 532523629
Diffstat (limited to 'service')
-rw-r--r--service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java33
-rw-r--r--service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java35
-rw-r--r--service/processor/src/test/resources/test/AutoServiceOnAbstractClass.java21
-rw-r--r--service/processor/src/test/resources/test/AutoServiceOnInterface.java21
4 files changed, 106 insertions, 4 deletions
diff --git a/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java b/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java
index 06e391e9..26c1435d 100644
--- a/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java
+++ b/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java
@@ -46,6 +46,7 @@ import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
@@ -233,13 +234,18 @@ public class AutoServiceProcessor extends AbstractProcessor {
return true;
}
- // TODO: We're currently only enforcing the subtype relationship
- // constraint. It would be nice to enforce them all.
+ // We check that providerImplementer does indeed inherit from providerType, and that it is not
+ // abstract (an abstract class or interface). For ServiceLoader, we could also check that it has
+ // a public no-arg constructor. But it turns out that people also use AutoService in contexts
+ // where the META-INF/services entries are read by things other than ServiceLoader. Those things
+ // still require the class to exist and inherit from providerType, but they don't necessarily
+ // require a public no-arg constructor.
+ // More background: https://github.com/google/auto/issues/1505.
Types types = processingEnv.getTypeUtils();
if (types.isSubtype(providerImplementer.asType(), providerType.asType())) {
- return true;
+ return checkNotAbstract(providerImplementer, annotationMirror);
}
// Maybe the provider has generic type, but the argument to @AutoService can't be generic.
@@ -255,12 +261,31 @@ public class AutoServiceProcessor extends AbstractProcessor {
providerImplementer,
annotationMirror);
}
- return true;
+ return checkNotAbstract(providerImplementer, annotationMirror);
}
+ String message =
+ "ServiceProviders must implement their service provider interface. "
+ + providerImplementer.getQualifiedName()
+ + " does not implement "
+ + providerType.getQualifiedName();
+ error(message, providerImplementer, annotationMirror);
+
return false;
}
+ private boolean checkNotAbstract(
+ TypeElement providerImplementer, AnnotationMirror annotationMirror) {
+ if (providerImplementer.getModifiers().contains(Modifier.ABSTRACT)) {
+ error(
+ "@AutoService cannot be applied to an abstract class or an interface",
+ providerImplementer,
+ annotationMirror);
+ return false;
+ }
+ return true;
+ }
+
private static boolean suppresses(Element element, String warning) {
for (; element != null; element = element.getEnclosingElement()) {
SuppressWarnings suppress = element.getAnnotation(SuppressWarnings.class);
diff --git a/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java b/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java
index 560aa995..7f2bf026 100644
--- a/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java
+++ b/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java
@@ -23,6 +23,7 @@ import com.google.common.io.Resources;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.Compiler;
import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -218,4 +219,38 @@ public class AutoServiceProcessorTest {
assertThat(compilation).failed();
assertThat(processor.exceptionStacks()).isEmpty();
}
+
+ @Test
+ public void autoServiceOnInterface() {
+ AutoServiceProcessor processor = new AutoServiceProcessor();
+ JavaFileObject autoServiceOnInterface =
+ JavaFileObjects.forResource("test/AutoServiceOnInterface.java");
+ Compilation compilation =
+ Compiler.javac()
+ .withProcessors(processor)
+ .withOptions("-Averify=true")
+ .compile(autoServiceOnInterface);
+ assertThat(compilation)
+ .hadErrorContaining("@AutoService cannot be applied to an abstract class or an interface")
+ .inFile(autoServiceOnInterface)
+ .onLineContaining("@AutoService");
+ assertThat(processor.exceptionStacks()).isEmpty();
+ }
+
+ @Test
+ public void autoServiceOnAbstractClass() {
+ AutoServiceProcessor processor = new AutoServiceProcessor();
+ JavaFileObject autoServiceOnAbstractClass =
+ JavaFileObjects.forResource("test/AutoServiceOnAbstractClass.java");
+ Compilation compilation =
+ Compiler.javac()
+ .withProcessors(processor)
+ .withOptions("-Averify=true")
+ .compile(JavaFileObjects.forResource("test/AutoServiceOnAbstractClass.java"));
+ assertThat(compilation)
+ .hadErrorContaining("@AutoService cannot be applied to an abstract class or an interface")
+ .inFile(autoServiceOnAbstractClass)
+ .onLineContaining("@AutoService");
+ assertThat(processor.exceptionStacks()).isEmpty();
+ }
}
diff --git a/service/processor/src/test/resources/test/AutoServiceOnAbstractClass.java b/service/processor/src/test/resources/test/AutoServiceOnAbstractClass.java
new file mode 100644
index 00000000..1669ca29
--- /dev/null
+++ b/service/processor/src/test/resources/test/AutoServiceOnAbstractClass.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2023 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 test;
+
+import com.google.auto.service.AutoService;
+
+@AutoService(SomeService.class)
+public abstract class AutoServiceOnAbstractClass implements SomeService {}
diff --git a/service/processor/src/test/resources/test/AutoServiceOnInterface.java b/service/processor/src/test/resources/test/AutoServiceOnInterface.java
new file mode 100644
index 00000000..84fcf126
--- /dev/null
+++ b/service/processor/src/test/resources/test/AutoServiceOnInterface.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2023 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 test;
+
+import com.google.auto.service.AutoService;
+
+@AutoService(SomeService.class)
+public interface AutoServiceOnInterface extends SomeService {}