diff --git a/core/processor/pom.xml b/core/processor/pom.xml
index 8427a552eb841..aee2ce4090171 100644
--- a/core/processor/pom.xml
+++ b/core/processor/pom.xml
@@ -59,6 +59,17 @@
jboss-logmanager
test
+
+ com.karuslabs
+ elementary
+ 2.0.1
+ test
+
+
+ io.quarkus
+ quarkus-builder
+ test
+
diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java b/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java
index c660290a11c37..3d978555bbecc 100644
--- a/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java
+++ b/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java
@@ -183,7 +183,7 @@ void doFinish() {
Properties javaDocProperties = new Properties();
try {
- Files.walkFileTree(path, new FileVisitor() {
+ Files.walkFileTree(path, new FileVisitor<>() {
public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) {
return FileVisitResult.CONTINUE;
}
@@ -282,8 +282,6 @@ public FileVisitResult postVisitDirectory(final Path dir, final IOException exc)
} catch (IOException e) {
processingEnv.getMessager()
.printMessage(Diagnostic.Kind.ERROR, "Failed to generate extension doc: " + e);
- return;
-
}
}
@@ -368,8 +366,7 @@ private void processBuildStep(RoundEnvironment roundEnv, TypeElement annotation)
StandardLocation.SOURCE_OUTPUT,
pkg.getQualifiedName()
.toString(),
- rbn.toString() + ".bsc",
- clazz);
+ rbn + ".bsc", clazz);
writeResourceFile(binaryName, itemResource);
} catch (IOException e1) {
processingEnv.getMessager()
@@ -618,7 +615,7 @@ private void processMethodConfigMapping(ExecutableElement method, Properties jav
if (method.getSimpleName()
.contentEquals("toString")
&& method.getParameters()
- .size() == 0) {
+ .isEmpty()) {
return;
}
@@ -650,7 +647,7 @@ private TypeElement unwrapConfigGroup(TypeMirror typeMirror) {
String name = declaredType.asElement()
.toString();
List extends TypeMirror> typeArguments = declaredType.getTypeArguments();
- if (typeArguments.size() == 0) {
+ if (typeArguments.isEmpty()) {
if (!name.startsWith("java.")) {
return (TypeElement) declaredType.asElement();
}
diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessorTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessorTest.java
new file mode 100644
index 0000000000000..d9d85a19ab53a
--- /dev/null
+++ b/core/processor/src/test/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessorTest.java
@@ -0,0 +1,76 @@
+package io.quarkus.annotation.processor;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import javax.tools.JavaFileObject;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import com.karuslabs.elementary.Results;
+import com.karuslabs.elementary.junit.JavacExtension;
+import com.karuslabs.elementary.junit.annotations.Classpath;
+import com.karuslabs.elementary.junit.annotations.Processors;
+
+import io.quarkus.annotation.processor.fs.CustomMemoryFileSystemProvider;
+
+@ExtendWith(JavacExtension.class)
+@Processors({ ExtensionAnnotationProcessor.class })
+class ExtensionAnnotationProcessorTest {
+
+ @BeforeEach
+ void beforeEach() {
+ // This is of limited use, since the filesystem doesn't seem to directly generate files, in the current usage
+ CustomMemoryFileSystemProvider.reset();
+ }
+
+ @Test
+ @Classpath("org.acme.examples.ClassWithBuildStep")
+ void shouldProcessClassWithBuildStepWithoutErrors(Results results) throws IOException {
+ assertNoErrrors(results);
+ }
+
+ @Test
+ @Classpath("org.acme.examples.ClassWithBuildStep")
+ void shouldGenerateABscFile(Results results) throws IOException {
+ assertNoErrrors(results);
+ List sources = results.sources;
+ JavaFileObject bscFile = sources.stream()
+ .filter(source -> source.getName()
+ .endsWith(".bsc"))
+ .findAny()
+ .orElse(null);
+ assertNotNull(bscFile);
+
+ String contents = removeLineBreaks(new String(bscFile
+ .openInputStream()
+ .readAllBytes(), StandardCharsets.UTF_8));
+ assertEquals("org.acme.examples.ClassWithBuildStep", contents);
+ }
+
+ private String removeLineBreaks(String s) {
+ return s.replace(System.getProperty("line.separator"), "")
+ .replace("\n", "");
+ }
+
+ @Test
+ @Classpath("org.acme.examples.ClassWithoutBuildStep")
+ void shouldProcessEmptyClassWithoutErrors(Results results) {
+ assertNoErrrors(results);
+ }
+
+ private static void assertNoErrrors(Results results) {
+ assertEquals(0, results.find()
+ .errors()
+ .count(),
+ "Errors were: " + results.find()
+ .errors()
+ .diagnostics());
+ }
+}
diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/fs/CustomMemoryFileSystem.java b/core/processor/src/test/java/io/quarkus/annotation/processor/fs/CustomMemoryFileSystem.java
new file mode 100644
index 0000000000000..432bd86b334e9
--- /dev/null
+++ b/core/processor/src/test/java/io/quarkus/annotation/processor/fs/CustomMemoryFileSystem.java
@@ -0,0 +1,158 @@
+package io.quarkus.annotation.processor.fs;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.Paths;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.UserPrincipalLookupService;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class CustomMemoryFileSystem extends FileSystem {
+
+ private final Map fileContents = new HashMap<>();
+ private final CustomMemoryFileSystemProvider provider;
+
+ public CustomMemoryFileSystem(CustomMemoryFileSystemProvider provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public FileSystemProvider provider() {
+ return provider;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // No resources to close
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true; // Always open
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return false; // This filesystem is writable
+ }
+
+ @Override
+ public String getSeparator() {
+ return "/"; // Unix-style separator
+ }
+
+ @Override
+ public Iterable getRootDirectories() {
+ return Collections.singleton(Paths.get("/")); // Single root directory
+ }
+
+ @Override
+ public Iterable getFileStores() {
+ return Collections.emptyList(); // No file stores
+ }
+
+ @Override
+ public Set supportedFileAttributeViews() {
+ return Collections.emptySet(); // No supported file attribute views
+ }
+
+ @Override
+ public Path getPath(String first, String... more) {
+ String path = first;
+ for (String segment : more) {
+ path += "/" + segment;
+ }
+ return Paths.get(path);
+ }
+
+ @Override
+ public PathMatcher getPathMatcher(String syntaxAndPattern) {
+ return null;
+ }
+
+ @Override
+ public UserPrincipalLookupService getUserPrincipalLookupService() {
+ return null;
+ }
+
+ @Override
+ public WatchService newWatchService() throws IOException {
+ return null;
+ }
+
+ public void addFile(URI uri, byte[] content) {
+ fileContents.put(uri, ByteBuffer.wrap(content));
+ }
+
+ static class CustomMemorySeekableByteChannel implements SeekableByteChannel {
+
+ private final ByteBuffer buffer;
+
+ CustomMemorySeekableByteChannel(ByteBuffer buffer) {
+ this.buffer = buffer;
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ int remaining = buffer.remaining();
+ int count = Math.min(remaining, dst.remaining());
+ if (count > 0) {
+ ByteBuffer slice = buffer.slice();
+ slice.limit(count);
+ dst.put(slice);
+ buffer.position(buffer.position() + count);
+ }
+ return count;
+ }
+
+ @Override
+ public int write(ByteBuffer src) throws IOException {
+ int count = src.remaining();
+ buffer.put(src);
+ return count;
+ }
+
+ @Override
+ public long position() throws IOException {
+ return buffer.position();
+ }
+
+ @Override
+ public SeekableByteChannel position(long newPosition) throws IOException {
+ buffer.position((int) newPosition);
+ return this;
+ }
+
+ @Override
+ public long size() throws IOException {
+ return buffer.limit();
+ }
+
+ @Override
+ public SeekableByteChannel truncate(long size) throws IOException {
+ buffer.limit((int) size);
+ return this;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return true; // Always open
+ }
+
+ @Override
+ public void close() throws IOException {
+ // No resources to close
+ }
+ }
+
+}
diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/fs/CustomMemoryFileSystemProvider.java b/core/processor/src/test/java/io/quarkus/annotation/processor/fs/CustomMemoryFileSystemProvider.java
new file mode 100644
index 0000000000000..8d28a7ae672a6
--- /dev/null
+++ b/core/processor/src/test/java/io/quarkus/annotation/processor/fs/CustomMemoryFileSystemProvider.java
@@ -0,0 +1,152 @@
+package io.quarkus.annotation.processor.fs;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.AccessMode;
+import java.nio.file.CopyOption;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class CustomMemoryFileSystemProvider extends FileSystemProvider {
+
+ private static final String MEM = "mem";
+
+ private static Map fileContents = new HashMap();
+
+ public static void reset() {
+ fileContents = new HashMap();
+ }
+
+ public static Set getCreatedFiles() {
+ return fileContents.keySet();
+ }
+
+ @Override
+ public String getScheme() {
+ return MEM;
+ }
+
+ @Override
+ public FileSystem newFileSystem(URI uri, Map env) throws IOException {
+ // There's a bit of a disconnect here between the Elementary JavaFileManager and the memory filesystem,
+ // even though both are in-memory filesystems
+ return new CustomMemoryFileSystem(this);
+ }
+
+ @Override
+ public FileSystem getFileSystem(URI uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Path getPath(URI uri) {
+
+ if (uri.getScheme() == null || !uri.getScheme()
+ .equalsIgnoreCase(MEM)) {
+ throw new IllegalArgumentException("For URI " + uri + ", URI scheme is not '" + MEM + "'");
+
+ }
+
+ // TODO what should we do here? Can we use the java file manager used by Elementary?
+ try {
+ return Path.of(File.createTempFile("mem-fs", "adhoc")
+ .toURI());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public SeekableByteChannel newByteChannel(Path path, Set extends OpenOption> options, FileAttribute>... attrs)
+ throws IOException {
+ if (fileContents.containsKey(path.toUri())) {
+ ByteBuffer buffer = fileContents.get(path.toUri());
+ return new CustomMemoryFileSystem.CustomMemorySeekableByteChannel(buffer);
+ } else {
+ throw new NoSuchFileException(path.toString());
+ }
+ }
+
+ @Override
+ public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter super Path> filter) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createDirectory(Path dir, FileAttribute>... attrs) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void delete(Path path) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void copy(Path source, Path target, CopyOption... options) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void move(Path source, Path target, CopyOption... options) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isSameFile(Path path1, Path path2) throws IOException {
+ return path1.equals(path2);
+ }
+
+ @Override
+ public boolean isHidden(Path path) throws IOException {
+ return false;
+ }
+
+ @Override
+ public FileStore getFileStore(Path path) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void checkAccess(Path path, AccessMode... modes) throws IOException {
+ if (!fileContents.containsKey(path.toUri())) {
+ throw new NoSuchFileException(path.toString());
+ }
+ }
+
+ @Override
+ public V getFileAttributeView(Path path, Class type,
+ LinkOption... options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public A readAttributes(Path path, Class type, LinkOption... options)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map readAttributes(Path path, String attributes, LinkOption... options) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/core/processor/src/test/resources/META-INF/services/java.nio.file.spi.FileSystemProvider b/core/processor/src/test/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
new file mode 100644
index 0000000000000..9582882517a77
--- /dev/null
+++ b/core/processor/src/test/resources/META-INF/services/java.nio.file.spi.FileSystemProvider
@@ -0,0 +1 @@
+io.quarkus.annotation.processor.fs.CustomMemoryFileSystemProvider
\ No newline at end of file
diff --git a/core/processor/src/test/resources/io/quarkus/deployment/annotations/BuildStep.java b/core/processor/src/test/resources/io/quarkus/deployment/annotations/BuildStep.java
new file mode 100644
index 0000000000000..944813a9d720a
--- /dev/null
+++ b/core/processor/src/test/resources/io/quarkus/deployment/annotations/BuildStep.java
@@ -0,0 +1,13 @@
+package io.quarkus.deployment.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface BuildStep {
+ // FAKE! FAKE! This is only here so we can test without introducing a circular dependency
+
+}
\ No newline at end of file
diff --git a/core/processor/src/test/resources/org/acme/examples/ArbitraryBuildItem.java b/core/processor/src/test/resources/org/acme/examples/ArbitraryBuildItem.java
new file mode 100644
index 0000000000000..ecb7fb4ee6ee6
--- /dev/null
+++ b/core/processor/src/test/resources/org/acme/examples/ArbitraryBuildItem.java
@@ -0,0 +1,6 @@
+package org.acme.examples;
+
+import io.quarkus.builder.item.MultiBuildItem;
+
+public final class ArbitraryBuildItem extends MultiBuildItem {
+}
\ No newline at end of file
diff --git a/core/processor/src/test/resources/org/acme/examples/ClassWithBuildStep.java b/core/processor/src/test/resources/org/acme/examples/ClassWithBuildStep.java
new file mode 100644
index 0000000000000..8dbecc4bff2bc
--- /dev/null
+++ b/core/processor/src/test/resources/org/acme/examples/ClassWithBuildStep.java
@@ -0,0 +1,10 @@
+package org.acme.examples;
+
+import io.quarkus.deployment.annotations.BuildStep;
+
+public class ClassWithBuildStep {
+ @BuildStep
+ ArbitraryBuildItem feature() {
+ return new ArbitraryBuildItem();
+ }
+}
diff --git a/core/processor/src/test/resources/org/acme/examples/ClassWithoutBuildStep.java b/core/processor/src/test/resources/org/acme/examples/ClassWithoutBuildStep.java
new file mode 100644
index 0000000000000..b40b6d25d2059
--- /dev/null
+++ b/core/processor/src/test/resources/org/acme/examples/ClassWithoutBuildStep.java
@@ -0,0 +1,6 @@
+package org.acme.examples;
+
+public class ClassWithoutBuildStep {
+
+
+}