Skip to content

Conversation

stuartwdouglas
Copy link
Collaborator

@stuartwdouglas stuartwdouglas commented Mar 20, 2025

This is really useful in kotlin as it allows you to define methods that are not inside a class.

e.g. this allows you to write the Kotlin quickstart as:

@GET
@Path("/hello")
@Produces(MediaType.TEXT_PLAIN)
fun hello() = "Hello from Quarkus REST"

This comment has been minimized.

Copy link

github-actions bot commented Mar 20, 2025

🎊 PR Preview a721231 has been successfully built and deployed to https://quarkus-pr-main-46908-preview.surge.sh/version/main/guides/

  • Images of blog posts older than 3 months are not available.
  • Newsletters older than 3 months are not available.

@geoand
Copy link
Contributor

geoand commented Mar 20, 2025

Interesting idea!

This comment has been minimized.

@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch from 7feff3c to d31bed1 Compare March 20, 2025 20:59

This comment has been minimized.

This comment has been minimized.

@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch 2 times, most recently from 2630a49 to 3cb5822 Compare March 21, 2025 21:19

This comment has been minimized.

@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch from 3cb5822 to 55018ad Compare March 21, 2025 22:07

This comment has been minimized.

@stuartwdouglas
Copy link
Collaborator Author

I have no idea why the new test is failing, it passes for me locally, and testing out a sample app also works.

@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch 2 times, most recently from 98bdb85 to 2fa493c Compare March 21, 2025 23:07

This comment has been minimized.

@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch from 2fa493c to 534aa34 Compare March 22, 2025 00:00

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch from 7fc5870 to 38af752 Compare March 23, 2025 23:51

This comment has been minimized.

This comment has been minimized.

@stuartwdouglas
Copy link
Collaborator Author

@geoand @FroMage if one of you has a spare few minutes is there any chance you could test this on your laptops and see if you also get a failure? I can't reproduce the failures at all locally, including in an example app, so I have no idea what could be wrong here.

@geoand
Copy link
Contributor

geoand commented Mar 25, 2025

@stuartwdouglas I'm off today so I'll give it a shot first thing tomorrow

@FroMage
Copy link
Member

FroMage commented Mar 25, 2025

Lemme try. This is a nice idea, for sure.

@FroMage
Copy link
Member

FroMage commented Mar 25, 2025

The test passes locally here :-/

Copy link
Member

@FroMage FroMage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good though, let's check what the test logs say…

Quarkus also extends the JAX-RS spec to allow you to use static methods. If the static method is on a class annotated with
`@Path`, it will be treated the same as a non-static endpoint. If there is no `@Path` annotation on the class then the path
is assumed to be a root path. This is especially useful for Kotlin as it allows you to define endpoints without creating a class.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we should add a Kotlin code sample here, but it sounds like it would be a good place to add one.

String path = scannedResourcePaths.get(classInfo.name());
ResourceClass clazz = new ResourceClass();
if ((classInfo.enclosingClass() != null) && !Modifier.isStatic(classInfo.flags())) {
if ((classInfo.enclosingClass() != null) && !Modifier.isStatic(classInfo.flags()) && path != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would the presence of a path change the outcome of this test?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the difference between a static method on a class that is already considered a resource, vs allowing static methods on classes that are otherwise not considered JAX-RS resource (but instead locatable subresources).

@FroMage
Copy link
Member

FroMage commented Mar 25, 2025

It's the FooNoClassPathStaticMethod that it doesn't find, that's probably a hint, for some reason it's not picking up the non-@Path-annotated class.

@FroMage
Copy link
Member

FroMage commented Mar 25, 2025

ResteasyReactiveScanner is picking it up as a possible subresource. Not a scanned resource. Perhaps that's the difference. Lemme try a commit.

@FroMage
Copy link
Member

FroMage commented Mar 25, 2025

Let's see what CI says with my change.

Note that I'm detecting this feature bcause there's a static method annotated with @Path in an unannotated class, but I'm sure you'll want this next:

public class FooNoClassPathStaticMethod {

        @GET
        public static String hello() {
            return "noclass";
        }
    }

As in, no @Path, which is already allowed when there's a @Path annotation on the class, in which case it's implicitely the same. Here it'd be implicitely @Path("") as well, I guess.

I did not add support for that.

This comment has been minimized.

This comment has been minimized.

@FroMage
Copy link
Member

FroMage commented Mar 25, 2025

Didn't help :(

continue;
}
URITemplate classTemplate = new URITemplate(clazz.getPath(), true);
List<List<ResourceClass>> rcMap = List.of(locatableResourceClasses, resourceClasses);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is what picks up the static methods on locatable subresources. Locally it seems to work, both when I run the test and if I create an example app. I'm not sure what could be different about CI that causes it to fail.

@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch from 8b8ce6e to a0aa662 Compare March 26, 2025 20:56

This comment has been minimized.

This comment has been minimized.

@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch from a0aa662 to 172c52d Compare March 31, 2025 03:05

This comment has been minimized.

This comment has been minimized.

@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch from 172c52d to 90221df Compare May 6, 2025 01:03

This comment has been minimized.

This comment has been minimized.

This is really useful in kotlin as it allows you to define methods that are not inside a class.
@stuartwdouglas stuartwdouglas force-pushed the stuartwdouglas/static-jaxrs branch from 90221df to d40f170 Compare May 6, 2025 22:04
Copy link

quarkus-bot bot commented May 6, 2025

Status for workflow Quarkus Documentation CI

This is the status report for running Quarkus Documentation CI on commit d40f170.

✅ The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

Warning

There are other workflow runs running, you probably need to wait for their status before merging.

Copy link

quarkus-bot bot commented May 6, 2025

Status for workflow Quarkus CI

This is the status report for running Quarkus CI on commit d40f170.

Failing Jobs

Status Name Step Failures Logs Raw logs Build scan
JVM Tests - JDK 17 Build Failures Logs Raw logs 🔍
JVM Tests - JDK 21 Build Failures Logs Raw logs 🔍
JVM Tests - JDK 17 Windows Build Failures Logs Raw logs 🔍

Full information is available in the Build summary check run.
You can consult the Develocity build scans.

Failures

⚙️ JVM Tests - JDK 17 #

- Failing: extensions/resteasy-reactive/rest/deployment 
! Skipped: extensions/avro/deployment extensions/grpc/deployment extensions/hibernate-reactive/deployment and 62 more

📦 extensions/resteasy-reactive/rest/deployment

io.quarkus.resteasy.reactive.server.test.StaticMethodTest.testStaticMethod line 38 - History - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <404>.

	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)

⚙️ JVM Tests - JDK 21 #

- Failing: extensions/resteasy-reactive/rest/deployment 
! Skipped: extensions/avro/deployment extensions/grpc/deployment extensions/hibernate-reactive/deployment and 62 more

📦 extensions/resteasy-reactive/rest/deployment

io.quarkus.resteasy.reactive.server.test.StaticMethodTest.testStaticMethod line 38 - History - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <404>.

	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
	at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:73)

⚙️ JVM Tests - JDK 17 Windows #

- Failing: extensions/resteasy-reactive/rest/deployment 
! Skipped: extensions/avro/deployment extensions/grpc/deployment extensions/hibernate-reactive/deployment and 62 more

📦 extensions/resteasy-reactive/rest/deployment

io.quarkus.resteasy.reactive.server.test.StaticMethodTest.testStaticMethod line 38 - History - More details - Source on GitHub

java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <404>.

	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)

Flaky tests - Develocity

⚙️ JVM Integration Tests - JDK 21

📦 integration-tests/opentelemetry-grpc-only

io.quarkus.it.opentelemetry.grpc.HelloGrpcClientTest.testHello - History

  • java.lang.RuntimeException: Failed to start quarkus - java.lang.RuntimeException
java.lang.RuntimeException: java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.test.junit.QuarkusTestExtension.throwBootFailureException(QuarkusTestExtension.java:693)
	at io.quarkus.test.junit.QuarkusTestExtension.interceptTestClassConstructor(QuarkusTestExtension.java:791)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)

@FroMage
Copy link
Member

FroMage commented May 7, 2025

It sucks that this has been blocked so long, but I'm not sure what more I can do to figure out why this fails in CI :-/

@geoand
Copy link
Contributor

geoand commented May 7, 2025

FWIW, I can reproduce the problem locally.

There is an initial problem that because of @Path("/"), StaticMethod is used to match all the requests (this restriction will be lifted here).
But even if one changes StaticMethod to

    @Path("hello")
    public static class StaticMethod {

        @GET
        public static String hello() {
            return "hello";
        }
    }

then the new feature still doesn't seem to work, but this time because there is no matcher, see screenshot:

Screenshot from 2025-05-07 14-42-46

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants