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

ClassTooLargeException when building an application containing many CDI beans #45380

Open
kirilvalyavicharski opened this issue Jan 6, 2025 · 13 comments
Labels
area/arc Issue related to ARC (dependency injection) kind/bug Something isn't working

Comments

@kirilvalyavicharski
Copy link

Describe the bug

During the build phase of the application, we are getting a ClassTooLargeException
The number of CDI beans is ~ 13000 and it will be increasing!

We have a multi-module project heavily dependent on CDI.
We are using the quarkus-maven-plugin

<plugin>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-maven-plugin</artifactId>
      <version>3.17.5</version>
    <executions>
        <execution>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>
</plugin>
[ERROR] Failed to execute goal io.quarkus:quarkus-maven-plugin:3.17.5:build (default) on project out-mapping-ear: Failed to build quarkus application: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[ERROR]         [error]: Build step io.quarkus.arc.deployment.ArcProcessor#generateResources threw an exception: java.lang.reflect.UndeclaredThrowableException
[ERROR]         at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:862)
[ERROR]         at io.quarkus.builder.BuildContext.run(BuildContext.java:256)
[ERROR]         at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
[ERROR]         at java.base/java.lang.Thread.run(Thread.java:833)
[ERROR]         at org.jboss.threads.JBossThread.run(JBossThread.java:499)
[ERROR] Caused by: java.util.concurrent.ExecutionException: org.objectweb.asm.ClassTooLargeException: Class too large: io/quarkus/arc/setup/Default_ComponentsProvider
[ERROR]         at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
[ERROR]         at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
[ERROR]         at io.quarkus.arc.processor.BeanProcessor.generateResources(BeanProcessor.java:440)
[ERROR]         at io.quarkus.arc.deployment.ArcProcessor.generateResources(ArcProcessor.java:539)
[ERROR]         at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
[ERROR]         at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
[ERROR]         ... 8 more
[ERROR] Caused by: org.objectweb.asm.ClassTooLargeException: Class too large: io/quarkus/arc/setup/Default_ComponentsProvider
[ERROR]         at org.objectweb.asm.ClassWriter.toByteArray(ClassWriter.java:616)
[ERROR]         at io.quarkus.gizmo.ClassCreator.writeTo(ClassCreator.java:246)
[ERROR]         at io.quarkus.gizmo.ClassCreator.close(ClassCreator.java:257)
[ERROR]         at io.quarkus.arc.processor.ComponentsProviderGenerator.generate(ComponentsProviderGenerator.java:201)
[ERROR]         at io.quarkus.arc.processor.BeanProcessor$1.call(BeanProcessor.java:294)
[ERROR]         at io.quarkus.arc.processor.BeanProcessor$1.call(BeanProcessor.java:290)
[ERROR]         at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[ERROR]         ... 7 more
[ERROR] -> [Help 1]

This is the list of quarkus dependencies:

 <dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-core</artifactId>
     <version>3.17.5</version>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-arc</artifactId>
     <version>3.17.5</version>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest</artifactId>
     <version>3.17.5</version>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-undertow</artifactId>
     <version>3.17.5</version>
</dependency>

Expected behavior

Successful build

Actual behavior

[ERROR] Failed to execute goal io.quarkus:quarkus-maven-plugin:3.17.5:build (default) on project out-mapping-ear: Failed to build quarkus application: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[ERROR]         [error]: Build step io.quarkus.arc.deployment.ArcProcessor#generateResources threw an exception: java.lang.reflect.UndeclaredThrowableException
[ERROR]         at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:862)
[ERROR]         at io.quarkus.builder.BuildContext.run(BuildContext.java:256)
[ERROR]         at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
[ERROR]         at java.base/java.lang.Thread.run(Thread.java:833)
[ERROR]         at org.jboss.threads.JBossThread.run(JBossThread.java:499)
[ERROR] Caused by: java.util.concurrent.ExecutionException: org.objectweb.asm.ClassTooLargeException: Class too large: io/quarkus/arc/setup/Default_ComponentsProvider
[ERROR]         at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
[ERROR]         at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
[ERROR]         at io.quarkus.arc.processor.BeanProcessor.generateResources(BeanProcessor.java:440)
[ERROR]         at io.quarkus.arc.deployment.ArcProcessor.generateResources(ArcProcessor.java:539)
[ERROR]         at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
[ERROR]         at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
[ERROR]         ... 8 more
[ERROR] Caused by: org.objectweb.asm.ClassTooLargeException: Class too large: io/quarkus/arc/setup/Default_ComponentsProvider
[ERROR]         at org.objectweb.asm.ClassWriter.toByteArray(ClassWriter.java:616)
[ERROR]         at io.quarkus.gizmo.ClassCreator.writeTo(ClassCreator.java:246)
[ERROR]         at io.quarkus.gizmo.ClassCreator.close(ClassCreator.java:257)
[ERROR]         at io.quarkus.arc.processor.ComponentsProviderGenerator.generate(ComponentsProviderGenerator.java:201)
[ERROR]         at io.quarkus.arc.processor.BeanProcessor$1.call(BeanProcessor.java:294)
[ERROR]         at io.quarkus.arc.processor.BeanProcessor$1.call(BeanProcessor.java:290)
[ERROR]         at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[ERROR]         ... 7 more
[ERROR] -> [Help 1]

How to Reproduce?

In out project, we currently have ~ 13000 CDI beans
I expect that you need to create a lot of @dependent beans!
Not sure whether the size of the beans class itself matters!

Output of uname -a or ver

OS name: "mac os x", version: "14.7.1", arch: "aarch64", family: "mac"

Output of java -version

OpenJDK 64-Bit Server VM Corretto-17.0.7.7.1 (build 17.0.7+7-LTS, mixed mode, sharing)

Quarkus version or git rev

3.17.5

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

Apache Maven 3.8.6

Additional information

No response

@kirilvalyavicharski kirilvalyavicharski added the kind/bug Something isn't working label Jan 6, 2025
@quarkus-bot quarkus-bot bot added the area/arc Issue related to ARC (dependency injection) label Jan 6, 2025
Copy link

quarkus-bot bot commented Jan 6, 2025

/cc @Ladicek (arc), @manovotn (arc), @mkouba (arc)

@mkouba
Copy link
Contributor

mkouba commented Jan 6, 2025

13 000 CDI beans? That's quite a number for a Quarkus app. Do you really use all those classes as fully fledged beans?

@kirilvalyavicharski
Copy link
Author

kirilvalyavicharski commented Jan 6, 2025

Dear, mkouba
Thank you very much for the fast response!

We have recently migrated our application from Payara 6 to Quarkus. As this is a large and continuously evolving project, the number of CDI beans is expected to increase over time. A significant portion of these CDI beans comes from the clean code patterns we are following.

We did not anticipate any restrictions on the number of CDI beans, and we couldn’t find any documentation indicating a maximum limit on the beans.

Could you please clarify whether there are any implicit constraints on the number of CDI beans, or if this could be a potential bug?

@mkouba
Copy link
Contributor

mkouba commented Jan 7, 2025

Dear, mkouba Thank you very much for the fast response!

We have recently migrated our application from Payara 6 to Quarkus. As this is a large and continuously evolving project, the number of CDI beans is expected to increase over time. A significant portion of these CDI beans comes from the clean code patterns we are following.

We did not anticipate any restrictions on the number of CDI beans, and we couldn’t find any documentation indicating a maximum limit on the beans.

Could you please clarify whether there are any implicit constraints on the number of CDI beans, or if this could be a potential bug?

There are no hard limits but 13K beans is way bigger than the usual microservice use case. In Quarkus, we do generate a lot of metadata classes and in case of CDI we need to generate a class that wires all dependencies together - the Default_ComponentsProvider from your stack trace.

Just out of curiosity - what patterns are you following?

Also would it be possible to split your application into several smaller modules? I'm pretty sure it would have other benefits too.

@gsmet
Copy link
Member

gsmet commented Jan 7, 2025

Could we split Default_ComponentsProvider in several classes in the same way we did it for the methods? I mean we could have the split classes contribute to the main Default_ComponentsProvider data structures.

I'm totally in line that this is an edge case and I'm not entirely sure it would scale very well but I'm not sure either having a hard limit that is hard to document is a good thing.

Especially since you could hit it after your migration to Quarkus when adding some additional beans.

@kirilvalyavicharski
Copy link
Author

Dear, mkouba Thank you very much for the fast response!
We have recently migrated our application from Payara 6 to Quarkus. As this is a large and continuously evolving project, the number of CDI beans is expected to increase over time. A significant portion of these CDI beans comes from the clean code patterns we are following.
We did not anticipate any restrictions on the number of CDI beans, and we couldn’t find any documentation indicating a maximum limit on the beans.
Could you please clarify whether there are any implicit constraints on the number of CDI beans, or if this could be a potential bug?

There are no hard limits but 13K beans is way bigger than the usual microservice use case. In Quarkus, we do generate a lot of metadata classes and in case of CDI we need to generate a class that wires all dependencies together - the Default_ComponentsProvider from your stack trace.

Just out of curiosity - what patterns are you following?

Also would it be possible to split your application into several smaller modules? I'm pretty sure it would have other benefits too.

This microservice was originally part of a large monolith. From a functional perspective, it follows the Single Responsibility Principle. It is not a small project, but the concept of a microservice here is understood not as a small piece of code running somewhere, but as a single, responsible unit.

We understand that 13000 beans is quite a lot. However, this comes from following the SOLID principles, where we aim to have as many single-responsibility classes as possible. This approach naturally results in a higher number of beans.

That's why I think the Default_ComponentsProvider serving as the single location for managing all dependencies could potentially be slightly optimized to handle a large number of beans more effectively.
In our case, this setup doesn’t seem to scale well. While others may not have encountered this issue yet, it’s possible that we are among the first to face it at this scale.

@kirilvalyavicharski
Copy link
Author

Could we split Default_ComponentsProvider in several classes in the same way we did it for the methods? I mean we could have the split classes contribute to the main Default_ComponentsProvider data structures.

I'm totally in line that this is an edge case and I'm not entirely sure it would scale very well but I'm not sure either having a hard limit that is hard to document is a good thing.

Especially since you could hit it after your migration to Quarkus when adding some additional beans.

Thank you for answering.
I also think that this area should be improved, by splitting the Default_ComponentsProvider in several classes, otherwise this could easily become a blocker.

@geoand
Copy link
Contributor

geoand commented Jan 7, 2025

Just for our information, how long does the legacy application take to startup?

@kirilvalyavicharski
Copy link
Author

Just for our information, how long does the legacy application take to startup?

The startup time is ~ 8/9 seconds

@geoand
Copy link
Contributor

geoand commented Jan 8, 2025

Thanks for the info

@kirilvalyavicharski
Copy link
Author

Thank you for your interest in this topic!

I would also truly appreciate any insights on whether you see this as a bug and if there are any plans to address it. Understanding whether a fix is expected would help us determine the next steps and how to proceed.

My intention is not to apply any pressure but simply to gain a better understanding of the situation.

Thanks, everyone!

@geoand
Copy link
Contributor

geoand commented Jan 8, 2025

@mkouba is going to check and see if it can fixed

@kirilvalyavicharski
Copy link
Author

Very much appreciate it :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/arc Issue related to ARC (dependency injection) kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants