Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compilation error on using Generics for Rest Client: java.lang.RuntimeException: Invalid type for descriptor T #43011

Open
ricardoalonso opened this issue Sep 4, 2024 · 11 comments

Comments

@ricardoalonso
Copy link

ricardoalonso commented Sep 4, 2024

Describe the bug

When creating clients for Rest Service, I was trying to create a generic interface to map the methods from PanacheEntityResource class that's used to create services for entities:

@Produces(MediaType.APPLICATION_JSON)
public interface BasicClient<T extends BasicType> {    
    @GET    
    T get();
}
@Path("/typea")
@RegisterRestClient(configKey = "typeab-service")
public interface TypeAClient extends BasicClient<TypeA> {
}
@Path("/typeb")
@RegisterRestClient(configKey = "typeab-service")
public interface TypeBClient extends BasicClient<TypeB> {
}

I have created a simple project ( code-with-quarkus.zip ) to show the problem. The regular Java compilation (without tests) runs fine, but when the client is used, the problem appears:

[ERROR] Errors:
[ERROR]   ServiceTest.testTypeAClient » Runtime java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors        
[error]: Build step io.quarkus.arc.deployment.ArcProcessor#generateResources threw an exception: java.lang.reflect.UndeclaredThrowableException        
at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:860)        
at io.quarkus.builder.BuildContext.run(BuildContext.java:256)        
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)        
at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2516)        
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2495)        
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1521)        
at java.base/java.lang.Thread.run(Thread.java:1583)        
at org.jboss.threads.JBossThread.run(JBossThread.java:483)
Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: Invalid type for descriptor T        
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)        
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)        
at io.quarkus.arc.processor.BeanProcessor.generateResources(BeanProcessor.java:432)        
at io.quarkus.arc.deployment.ArcProcessor.generateResources(ArcProcessor.java:537)        
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733)        
at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:854)        
... 7 more
Caused by: java.lang.RuntimeException: Invalid type for descriptor T        
at io.quarkus.gizmo.DescriptorUtils.typeToString(DescriptorUtils.java:222)        
at io.quarkus.gizmo.MethodDescriptor.<init>(MethodDescriptor.java:66)        
at io.quarkus.gizmo.MethodDescriptor.of(MethodDescriptor.java:109)        
at io.quarkus.arc.processor.ClientProxyGenerator.generate(ClientProxyGenerator.java:161)        
at io.quarkus.arc.processor.BeanProcessor$4$1.call(BeanProcessor.java:326)        
at io.quarkus.arc.processor.BeanProcessor$4$1.call(BeanProcessor.java:323)        
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)        
... 6 more

If I implement without the interface, it works fine.

Expected behavior

Use a generic super interface to map common methods.

Actual behavior

See the above stack trace.

How to Reproduce?

See the attached sample project.

Output of uname -a or ver

Linux localhost.localdomain 6.9.12-200.fc40.x86_64 #1 SMP PREEMPT_DYNAMIC Sat Jul 27 15:56:15 UTC 2024 x86_64 GNU/Linux

Output of java -version

openjdk version "21.0.4" 2024-07-16 OpenJDK Runtime Environment (Red_Hat-21.0.4.0.7-2) (build 21.0.4+7) OpenJDK 64-Bit Server VM (Red_Hat-21.0.4.0.7-2) (build 21.0.4+7, mixed mode, sharing)

Quarkus version or git rev

3.14.1

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

Apache Maven 3.9.8 (36645f6c9b5079805ea5009217e36f2cffd34256)
Maven home: /home/ricardo.alonso/.m2/wrapper/dists/apache-maven-3.9.8-bin/337e6d14/apache-maven-3.9.8
Java version: 21.0.4, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-21-openjdk-21.0.4.0.7-2.fc40.x86_64
Default locale: en_GB, platform encoding: UTF-8
OS name: "linux", version: "6.9.12-200.fc40.x86_64", arch: "amd64", family: "unix"

Additional information

No response

@ricardoalonso ricardoalonso added the kind/bug Something isn't working label Sep 4, 2024
@quarkus-bot
Copy link

quarkus-bot bot commented Sep 4, 2024

/cc @cescoffier (rest-client), @geoand (rest-client)

@geoand
Copy link
Contributor

geoand commented Sep 4, 2024

This is kind of a weird case to be honest...

I absolutely understand what you are trying to do, but currently there is no way to tell Quarkus to not make BasicClient a REST Client interface itself.

Perhaps we could introduce something like @IgnoreForRestClient

@geoand geoand removed the kind/bug Something isn't working label Sep 4, 2024
@ricardoalonso
Copy link
Author

ricardoalonso commented Sep 4, 2024

Let me understand. Quarkus try to create the Rest Client proxy from the child interface which is annotated and from the father interface, which is not annotated?

@geoand
Copy link
Contributor

geoand commented Sep 4, 2024

It tries to create them for all the interfaces in your case

@ricardoalonso
Copy link
Author

ricardoalonso commented Sep 4, 2024

The @IgnoreForRestClient could be a solution, but could be simpler to just not follow the hierarchy tree? Only generate the client proxy for the explicit annotated interface and not for the relatives?

@geoand
Copy link
Contributor

geoand commented Sep 4, 2024

Unfortunately that would not work because it's perfectly valid to have non annotated interfaces for the rest client

@gsmet
Copy link
Member

gsmet commented Sep 4, 2024

Is it mandated? Because I can see how it could be impractical in the end.

Being explicit about when you want a client doesn’t seem too far fetched?

Also in this very case, maybe we should just skip it? It’s not annotated and it’s invalid, looks like something we could skip?

@geoand
Copy link
Contributor

geoand commented Sep 5, 2024

Is it mandated?

Yes, otherwise the programmatic usage won't work

It’s not annotated and it’s invalid, looks like something we could skip?

Invalid how? You mean because of the generics?

@gsmet
Copy link
Member

gsmet commented Sep 5, 2024

Yeah, I mean if we know we cannot instantiate it, we might as well skip it.

@geoand
Copy link
Contributor

geoand commented Sep 5, 2024

Potentially, but there could be corner cases

@rekt-hard
Copy link

We also just stumbled upon this issue. This was working before we updated our dependencies from quarkus-resteasy* to quarkus-rest*.

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

No branches or pull requests

4 participants