quarkus: Can't load static resource created by extension

Describe the bug

In my extension, I created a static resource with:

    @BuildStep
    public void processModel(BuildProducer<GeneratedResourceBuildItem> output,
            BuildProducer<AdditionalStaticResourceBuildItem> staticResources) {

        String path = "/routes.js";
        output.produce(new GeneratedResourceBuildItem("META-INF/resources" + path,
                "//hello".getBytes(StandardCharsets.UTF_8)));
        staticResources.produce(new AdditionalStaticResourceBuildItem(path, false));
}

When I try to test this:

@QuarkusTest
public class MyTest {
    @Test
    public void testJsRouting() {
        given()
                .when().get("/routes.js")
                .then()
                .statusCode(200)
                .body(is("//hello"));
    }
}

I’m getting the following exception:

ERROR: HTTP Request to /routes.js failed, error id: 0c1267fb-df47-4c0c-b97f-f7943ca4ef19-1
java.lang.IllegalStateException: Invalid url protocol: quarkus
    at io.vertx.core.file.impl.FileResolverImpl.unpackUrlResource(FileResolverImpl.java:247)
    at io.vertx.core.file.impl.FileResolverImpl.resolveFile(FileResolverImpl.java:174)
    at io.vertx.core.impl.VertxImpl.resolveFile(VertxImpl.java:794)
    at io.vertx.core.file.impl.FileSystemImpl$20.perform(FileSystemImpl.java:1136)
    at io.vertx.core.file.impl.FileSystemImpl$20.perform(FileSystemImpl.java:1134)
    at io.vertx.core.file.impl.FileSystemImpl$BlockingAction.handle(FileSystemImpl.java:1175)
    at io.vertx.core.file.impl.FileSystemImpl$BlockingAction.handle(FileSystemImpl.java:1157)
    at io.vertx.core.impl.ContextBase.lambda$null$0(ContextBase.java:137)
    at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:264)
    at io.vertx.core.impl.ContextBase.lambda$executeBlocking$1(ContextBase.java:135)
    at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
    at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
    at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
    at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:834)

This is because those are served via a Vert.x StaticHandler, which accesses them via the file system, and obtains the URL to the resource via the QuarkusClassLoader: https://github.com/eclipse-vertx/vert.x/blob/master/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java#L173 and then attempts to open it in https://github.com/eclipse-vertx/vert.x/blob/bbb4ddc417a604697d2ff4f5a8eda2e74113697e/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java#L225

The problem is that QuarkusClassLoader serves it using a MemoryClassPathElement https://github.com/quarkusio/quarkus/blob/main/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/MemoryClassPathElement.java#L86 that has a quarkus: URL scheme, which is registered via a UrlStreamHandler at https://github.com/quarkusio/quarkus/blob/main/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/MemoryClassPathElement.java#L131 but Vert.x doesn’t know about it and doesn’t know how to deal with it.

I’m not sure what to do to fix this, frankly.

Expected behavior

No response

Actual behavior

No response

How to Reproduce?

No response

Output of uname -a or ver

No response

Output of java -version

No response

GraalVM version (if different from Java)

No response

Quarkus version or git rev

No response

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

No response

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 20 (20 by maintainers)

Commits related to this issue

Most upvoted comments

Well, OK, so I found how to write an extension test to have a special build step today:

package io.quarkus.vertx.http;

import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.builder.BuildChainBuilder;
import io.quarkus.builder.BuildContext;
import io.quarkus.builder.BuildStep;
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.vertx.http.deployment.spi.AdditionalStaticResourceBuildItem;
import io.restassured.RestAssured;

public class AdditionalStaticResourceTest {

    @RegisterExtension
    static final QuarkusUnitTest config = new QuarkusUnitTest()
            .addBuildChainCustomizer(buildCustomizer());

    static Consumer<BuildChainBuilder> buildCustomizer() {
        return new Consumer<BuildChainBuilder>() {
            @Override
            public void accept(BuildChainBuilder builder) {
                builder.addBuildStep(new BuildStep() {
                    @Override
                    public void execute(BuildContext context) {
                        String path = "/routes.js";
                        

                        context.produce(new GeneratedResourceBuildItem("META-INF/resources" + path,
                                "//hello".getBytes(StandardCharsets.UTF_8)));
                        context.produce(new AdditionalStaticResourceBuildItem(path, false));
                    }
                }).produces(GeneratedResourceBuildItem.class)
                .produces(AdditionalStaticResourceBuildItem.class)
                .build();
            }
        };
    }

    @Test
    public void testNonApplicationEndpointDirect() {
        RestAssured.given()
        .when().get("/routes.js")
        .then()
        .statusCode(200)
        .body(Matchers.is("//hello"));
    }
}

Here’s your reproducer 😉