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
Multiple JAX-RS Applications #11415
Comments
FWIW, back in march I started a discussion on Zulip regarding "Multiple/modular Swagger UIs": https://quarkusio.zulipchat.com/#narrow/stream/187030-users/topic/Multiple.2Fmodular.20Swagger.20UIs |
What's the advantage to multiple JAX-RS Applications vs different Resource @paths? |
The ability to have different |
@famod can you elaborate on the use case for that? I don't understand why different exception mappers for the same problem are needed? |
Well, you might want to have a very modular structure in a larger Quarkus app. In this case you'll likely want to separate the exception classes from each other that are specific for certain "subdomains". |
Ok, I think I see what you mean. However, I don't think this feature is something that would be easy to implement as it would mean having to segregate CDI beans between the different JAX-RS Applications. And right now I don't think adding classes to I could be wrong on the above, but that's my understanding |
Adding to @famod's comment, it is not just about ExceptionMappers but all JAX-RS constructs that can be attached on the application-level: Exception mappers, Message Body Reader/Writer to support additional type mappings, ContainerResponseFilters, etc. |
I see what you mean, but I'm saying I'm not sure such isolation ability is something easily achievable in Quarkus, or even something that should be done |
I am not sure I understand what makes it "not easy" to implement. Today, there is only a single JaxRS application; so, there is no need to map rest resources to applications. This information/mapping would need to be collected during build-time and be used to instanciate/configure multiple servlets (one for each applicaton). Maybe this last part is not as easy as i think; and it also sounds like it can cause problems; but then there could be a Quarkus specific API to convey the same infromation in a different way. E.g. offer a builditem in the quarkus build for applications to produce in their own extensions; or a config in the application.properties. I am starting to understand what you mean with segregating CDI beans; could you eleborate on how it is done today in the resteasy extension? I.e. how are the resource beans, or the other providers selected during runtime and tied to the JaxRS application. I understand, that there is no way in CDI to segregate beans, but already today, resteasy/jaxrs in quarkus needs to tie the CDI bean of the resource to the resteasy/jaxrs application in some way... |
Ok, i have been giving this some more thought and investigated as well. Why is this useful? I see this as an important feature to support the migration of bigger microservices or monoliths that are to be broken up to quarkus. I would be happy with a hidden feature to support multiple JaxRS endpoints that does not have to be 100% JAX-RS spec compliant but gives the option. Similar to how Custom CDI scopes are supported by Arc; just not via CDI extensions that are enirely runtime-based but some possibility to do it in a custom Quarkus Extension. I.e. Application.getClasses() might not be a good fit for Quarkus, so instead offer a custom way via the build for anyone to tie resources to applications. E.g. new JaxRsApplicationResourceMappingBuildItem(applicationClass, Set.of(resourceAClass, resourceBClass)). Obviously, this additional ceremony would only be needed in case there are multiple JaxRS applciation discovered. If there only is one, all behaves as today. One important point to note is that each Jax-RS application has a one-to-one mapping to its own servlet. So, we would have as many servlets as Jax-RS applications. I don't see anything wrong with that level of isolation as already today there are a lot of different servlets. What is needed for it? I have looked around how it looks today; basically, these are the main classes that are involved:
From a technical perspective, it looks like all *BuildItems need to be changed to MultiBuildItems and there needs to be be some way to correlate them; so, we know which ResteasyServerConfigBuildItem belongs to which ResteasyDeploymentBuildItem. To me, this is the @ApplicationPath value of the application. @kenfinnigan : Regarding your comment on segregating CDI beans: Again, i am not 100% sure I understood the comment and if there is some problem lurking that I don't see currently. But maybe you mean what i describe with JaxRsApplicationResourceMappingBuildItem? Also, i see getClasses() beeing called today during runtime/startup from resteasy. So, there would be the option to synthesize this method based on the data collected via JaxRsApplicationResourceMappingBuildItem. I have not looked into resteasy, but i assume it will use the results of getClasses to ask CDI for the bean which i assume should just work....!? I would be heavily interested in seeing this feature happen and also willing to contribute. Let me know your thoughts. If there is zero change to see this happen, it would be good for me to know early because this might be a become a showstopper in our Quarkus migration journey. |
@38leinaD it's not just the JAX-RS side of things that needs amending, as far as I understand. It would also be necessary to segregate the CDI container (ArC) so that beans for one JAX-RS application are not injectable into the other. My understanding is that the Is that right? |
Leaving aside the build-time complexities of supporting this in Quarkus, we could ask the RESTEasy team if multiple applications are even supported by RESTEasy at runtime in the same module/classloader. Given what I know about statics and ThreadLocals in the runtime I just don't know if it's even meant to be supported. Probably @asoldano will know? As to whether this would be good for Quarkus, originally I would have said no since the workaround is simple: make those separate Quarkus applications. But now that we try to support bigger applications, it's not clear if we should reject it out of hand, or if we should first consider the effort/risk/benefit ratio to decide this. It sounds to me like quite some work to support (if the runtime supports it at all) and maintain for a fairly edge case IMO. |
Maybe getClasses in the JAX-RS spec has a broader scope, but from my experience with writing rest services, it usually boils down to returning resource-classes, providers and exeception mappers from the getClasses method. If we are talking about "segregate the CDI container (ArC) so that beans for one JAX-RS application are not injectable into the other", i am not sure what that means realistically; can a sub-resource be injected in another resource? With exception mappers and providers, there is no injection involved i think. Is it possible in the getClasses to just define random bean-classes that are injecteable via @Inject? If it is possible with Jax-Rs indeed, i have never used it. And you can always do an @Inject for any CDI beans from within your resources. There is no segregation that only CDI beans that are listed in the getClasses can be injected. |
This is what |
AFAIR this is not supported currently; the idea is that a JavaEE / JakartaEE deployment (associated to its classloader) can possibly be a JAX-RS deployment. Each deployment has a single Application. |
I understand that one resteasy deployment has a single application. But why is it not possible to have multiple resteasy deployments on the same classloader? I.e. there is no limitation in JavaEE to define multiple Jax-RS applications in a single war/classloader. My assumption is that if Quarkus uses resteasy, which is also used in appservers (?), resteasy in quarkus should also not have a problem to have multiple resteasy deployments. Each deployment is tied to its own servlet. |
uh, I just realized there was already a discussion about supporting this in WildFly and it looks like it's only partially working. You might want to read the long discussion that started with this message https://www.eclipse.org/lists/jaxrs-dev/msg00564.html where the spec lead was saying that the spec is not really stating this is supported or not and some clarifications would be needed. |
@ronsigal, I'm sure you have better memories of the discussion and can help here. |
Just a quick summary/opinion based on all the good comments: Also as i understood it, there really is no limitation in resteasy to have multiple jaxrs deployments in the same war/classloader. it works in jboss/wildfly (just tried it out on jboss eap 7.1); so it should also not be a problem in quarkus!? Is that a correct assumption? |
You mean something like this? https://access.redhat.com/documentation/en-us/red_hat_fuse/7.3/html/apache_cxf_development_guide/jaxrs20filters#JAXRS20Filters-DynamicBinding Looks promising. Worth a look I guess. Is there anything special to be aware of in Quarkus when using this approach? |
Not necessarily trivial, because this only works in the servlet mode, if it works, which means in Quarkus you'll need to be in servlet mode which is slower than the default mode. And from what @asoldano says it's not clear if RESTEasy even supports having multiple deployments in the same class loader. Frankly by looking at the code I'm really unsure but I think it doesn't. |
Ok, I was not aware that there are different modes in resteasy for running inside a servlet container and not. But I would have expected quarkus to use that servlet container mode as it has a servlet container. @sberyozkin the dynamic feature looks indeed interesting. @famod let me know if you have tried it out and what your result is. I just tried it and it does not seem to work. The dynamic feature is called for each resource method, but when i configure a provider (i tried with an exceptionmapper) it seemed to have absolutely no impact... |
Although not specifically targeting this issue, one can now do what is mentioned here by utilizing https://quarkus.io/version/main/guides/all-config#quarkus-core_quarkus.class-loading.removed-resources-removed-resources. For example, if you have an
The capability was introduced in #18121 |
Description
When developing bigger microservices or monolithic applications, it is useful to be able to define multiple JAX-RS applications.
Currently, Quarkus only allows to have a single Application: See https://github.com/quarkusio/quarkus/blob/master/extensions/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java#L193
Obviously, this involves more ceremony by the developer who makes use of the feature (implementing a JaxRS Application class and implementing the getClasses() method to assign the different resources), but as this is a "power-user" feature, it will not impact the standard user.
The text was updated successfully, but these errors were encountered: