This is an automated email from the ASF dual-hosted git repository.

jungm pushed a commit to branch tomee-10.x
in repository https://gitbox.apache.org/repos/asf/tomee.git


The following commit(s) were added to refs/heads/tomee-10.x by this push:
     new b8b11cdda6 TOMEE-4716 - deploy MicroProfile Health at the context root 
regardless of declared JAX-RS applications (#2960) (#3015)
b8b11cdda6 is described below

commit b8b11cdda69c686aa9258b360752478a193a3c7c
Author: Markus Jung <[email protected]>
AuthorDate: Thu Oct 1 13:29:50 2026 +0200

    TOMEE-4716 - deploy MicroProfile Health at the context root regardless of 
declared JAX-RS applications (#2960) (#3015)
    
    * TOMEE-4716 deploy the MicroProfile health endpoint at the context root 
regardless of declared JAX-RS applications
    
    * TOMEE-4716 test the health endpoint with an application at the context 
root and with multiple applications
    
    The test with an application at the context root fails: the application is 
deployed, but the health endpoint is not available.
    
    * TOMEE-4716 deploy the health endpoint with an application mapped to the 
context root
    
    CXF runs one server per address, so a separate container application at the 
context root clashes with an application mapped to /. The container resources 
are deployed with that application instead. They are passed to the listener 
next to the application, so the application instance stays as it is and its 
name bindings don't apply to them.
    
    ---------
    
    
    (cherry picked from commit bc850ab18b9b59e273e147cbc55d6fc74d262bd7)
    
    Co-authored-by: Richard Zowalla <[email protected]>
---
 .../openejb/assembler/classic/WebAppInfo.java      |   2 +
 .../microprofile/health/HealthEndpointTest.java    | 201 +++++++++++++++++++++
 .../openejb/server/cxf/rs/CxfRsHttpListener.java   |  29 ++-
 .../apache/openejb/server/rest/RESTService.java    |  40 +++-
 .../apache/openejb/server/rest/RsHttpListener.java |   5 +-
 .../microprofile/TomEEMicroProfileListener.java    |   6 +
 6 files changed, 270 insertions(+), 13 deletions(-)

diff --git 
a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java
 
b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java
index de6f3e3eb9..466706aa09 100644
--- 
a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java
+++ 
b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java
@@ -37,6 +37,8 @@ public class WebAppInfo extends CommonInfoObject {
     public final Set<String> watchedResources = new TreeSet<>();
     public final Set<String> restClass = new TreeSet<>();
     public final Set<String> restApplications = new TreeSet<>();
+    /** Resource classes the container contributes, deployed at the context 
root whatever applications the webapp declares. */
+    public final Set<String> containerRestClass = new TreeSet<>();
     public final Set<String> ejbWebServices = new TreeSet<>();
     public final Set<String> ejbRestServices = new TreeSet<>();
     public final Set<ClassListInfo> webAnnotatedClasses = new 
LinkedHashSet<>();
diff --git 
a/itests/tomee-microprofile-itests/src/test/java/org/apache/tomee/microprofile/health/HealthEndpointTest.java
 
b/itests/tomee-microprofile-itests/src/test/java/org/apache/tomee/microprofile/health/HealthEndpointTest.java
new file mode 100644
index 0000000000..eb5fa1c085
--- /dev/null
+++ 
b/itests/tomee-microprofile-itests/src/test/java/org/apache/tomee/microprofile/health/HealthEndpointTest.java
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.microprofile.health;
+
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.NameBinding;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.tomee.server.composer.Archive;
+import org.apache.tomee.server.composer.TomEE;
+import org.junit.Test;
+
+import java.io.File;
+import java.lang.annotation.Retention;
+import java.net.URL;
+import java.util.Set;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * MicroProfile Health endpoints belong to the context root of every web 
application, whatever JAX-RS
+ * {@link Application} subclasses the application declares.
+ */
+public class HealthEndpointTest {
+
+    @Test
+    public void applicationListingItsClasses() throws Exception {
+        final TomEE tomee = deploy(Archive.archive()
+                                          .add(HealthEndpointTest.class)
+                                          .add(ListingApp.class)
+                                          .add(HelloResource.class)
+                                          .asJar());
+
+        assertEquals(200, get(tomee, "/test/api/hello").getStatus());
+        assertEquals(200, get(tomee, "/test/health").getStatus());
+        assertEquals(200, get(tomee, "/test/health/live").getStatus());
+    }
+
+    @Test
+    public void applicationListingNothing() throws Exception {
+        final TomEE tomee = deploy(Archive.archive()
+                                          .add(HealthEndpointTest.class)
+                                          .add(ScanningApp.class)
+                                          .add(HelloResource.class)
+                                          .asJar());
+
+        assertEquals(200, get(tomee, "/test/api/hello").getStatus());
+        assertEquals(200, get(tomee, "/test/health").getStatus());
+        assertEquals(200, get(tomee, "/test/health/live").getStatus());
+    }
+
+    @Test
+    public void applicationAtTheContextRoot() throws Exception {
+        final TomEE tomee = deploy(Archive.archive()
+                                          .add(HealthEndpointTest.class)
+                                          .add(RootApp.class)
+                                          .add(HelloResource.class)
+                                          .asJar());
+
+        assertEquals(200, get(tomee, "/test/hello").getStatus());
+        assertEquals(200, get(tomee, "/test/health").getStatus());
+        assertEquals(200, get(tomee, "/test/health/live").getStatus());
+    }
+
+    @Test
+    public void scanningApplicationAtTheContextRoot() throws Exception {
+        final TomEE tomee = deploy(Archive.archive()
+                                          .add(HealthEndpointTest.class)
+                                          .add(RootScanningApp.class)
+                                          .add(HelloResource.class)
+                                          .asJar());
+
+        assertEquals(200, get(tomee, "/test/hello").getStatus());
+        assertEquals(200, get(tomee, "/test/health").getStatus());
+        assertEquals(200, get(tomee, "/test/health/live").getStatus());
+    }
+
+    @Test
+    public void applicationWithNameBindingsAtTheContextRoot() throws Exception 
{
+        final TomEE tomee = deploy(Archive.archive()
+                                          .add(HealthEndpointTest.class)
+                                          .add(Denied.class)
+                                          .add(DeniedRootApp.class)
+                                          .add(DenyingFilter.class)
+                                          .add(HelloResource.class)
+                                          .asJar());
+
+        assertEquals(403, get(tomee, "/test/hello").getStatus());
+        assertEquals(200, get(tomee, "/test/health").getStatus());
+        assertEquals(200, get(tomee, "/test/health/live").getStatus());
+    }
+
+    @Test
+    public void multipleApplications() throws Exception {
+        final TomEE tomee = deploy(Archive.archive()
+                                          .add(HealthEndpointTest.class)
+                                          .add(ListingApp.class)
+                                          .add(OtherApp.class)
+                                          .add(HelloResource.class)
+                                          .asJar());
+
+        assertEquals(200, get(tomee, "/test/api/hello").getStatus());
+        assertEquals(200, get(tomee, "/test/other/hello").getStatus());
+        assertEquals(200, get(tomee, "/test/health").getStatus());
+        assertEquals(200, get(tomee, "/test/health/live").getStatus());
+    }
+
+    private static TomEE deploy(final File appJar) throws Exception {
+        return TomEE.microprofile()
+                    .add("webapps/test/WEB-INF/beans.xml", "")
+                    .add("webapps/test/WEB-INF/lib/app.jar", appJar)
+                    .build();
+    }
+
+    private static Response get(final TomEE tomee, final String path) throws 
Exception {
+        final URL base = tomee.toURI().toURL();
+        return WebClient.create(base.toExternalForm()).path(path).get();
+    }
+
+    @ApplicationPath("/api")
+    public static class ListingApp extends Application {
+        @Override
+        public Set<Class<?>> getClasses() {
+            return Set.of(HelloResource.class);
+        }
+    }
+
+    @ApplicationPath("/api")
+    public static class ScanningApp extends Application {
+    }
+
+    @ApplicationPath("/")
+    public static class RootApp extends Application {
+        @Override
+        public Set<Class<?>> getClasses() {
+            return Set.of(HelloResource.class);
+        }
+    }
+
+    @ApplicationPath("/")
+    public static class RootScanningApp extends Application {
+    }
+
+    @NameBinding
+    @Retention(RUNTIME)
+    public @interface Denied {
+    }
+
+    @Denied
+    @ApplicationPath("/")
+    public static class DeniedRootApp extends Application {
+        @Override
+        public Set<Class<?>> getClasses() {
+            return Set.of(HelloResource.class, DenyingFilter.class);
+        }
+    }
+
+    @Denied
+    public static class DenyingFilter implements ContainerRequestFilter {
+        @Override
+        public void filter(final ContainerRequestContext requestContext) {
+            
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+        }
+    }
+
+    @ApplicationPath("/other")
+    public static class OtherApp extends Application {
+        @Override
+        public Set<Class<?>> getClasses() {
+            return Set.of(HelloResource.class);
+        }
+    }
+
+    @Path("hello")
+    public static class HelloResource {
+        @GET
+        public String hello() {
+            return "hello";
+        }
+    }
+}
diff --git 
a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
 
b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
index b0e82b19da..39cb2b1137 100644
--- 
a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
+++ 
b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
@@ -39,6 +39,7 @@ import org.apache.cxf.jaxrs.model.OperationResourceInfo;
 import org.apache.cxf.jaxrs.model.ProviderInfo;
 import org.apache.cxf.jaxrs.provider.ServerProviderFactory;
 import org.apache.cxf.jaxrs.sse.SseContextProvider;
+import org.apache.cxf.jaxrs.utils.AnnotationUtils;
 import org.apache.cxf.jaxrs.utils.HttpUtils;
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.cxf.jaxrs.validation.JAXRSBeanValidationInInterceptor;
@@ -180,6 +181,7 @@ public class CxfRsHttpListener implements RsHttpListener {
     private final CxfRSService service;
     private HttpDestination destination;
     private Server server;
+    private Collection<Class<?>> containerResources = Collections.emptySet();
     private String context = "";
     private String servlet = "";
     private final Collection<Pattern> staticResourcesList = new 
CopyOnWriteArrayList<>();
@@ -356,7 +358,7 @@ public class CxfRsHttpListener implements RsHttpListener {
 
     public boolean isCXFResource(final HttpServletRequest request) {
         try {
-            if (!applicationProvidesResources(findApplication())) { // nothing 
is registered in JAX-RS
+            if (containerResources.isEmpty() && 
!applicationProvidesResources(findApplication())) { // nothing is registered in 
JAX-RS
                 return false;
             }
 
@@ -631,15 +633,18 @@ public class CxfRsHttpListener implements RsHttpListener {
     }
 
     @Override
-    public void deployApplication(final Application application, final String 
prefix, final String webContext,
+    public void deployApplication(final Application application, final 
Collection<Class<?>> containerResources,
+                                  final String prefix, final String webContext,
                                   final Collection<Object> additionalProviders,
                                   final Map<String, EJBRestServiceInfo> 
restEjbs, final ClassLoader classLoader,
                                   final Collection<Injection> injections, 
final Context context, final WebBeansContext owbCtx,
                                   final ServiceConfiguration 
serviceConfiguration) {
+        this.containerResources = containerResources;
+
         final ClassLoader oldLoader = 
Thread.currentThread().getContextClassLoader();
         Thread.currentThread().setContextClassLoader(CxfUtil.initBusLoader());
         try {
-            final ApplicationData applicationData = 
getApplicationData(application, prefix, additionalProviders);
+            final ApplicationData applicationData = 
getApplicationData(application, containerResources, prefix, 
additionalProviders);
 
             logApplication(applicationData);
 
@@ -653,7 +658,9 @@ public class CxfRsHttpListener implements RsHttpListener {
 
             final List<Class<?>> classes = new ArrayList<>();
 
-            for (final Class<?> clazz : application.getClasses()) {
+            final Set<Class<?>> resourceClasses = new 
LinkedHashSet<>(application.getClasses());
+            resourceClasses.addAll(containerResources);
+            for (final Class<?> clazz : resourceClasses) {
                 if (!additionalProviders.contains(clazz) && 
!clazz.isInterface()) {
                     classes.add(clazz);
 
@@ -736,6 +743,13 @@ public class CxfRsHttpListener implements RsHttpListener {
              */
             factory.setApplication(application);
 
+            // the container resources are outside of the application, so its 
name bindings don't apply to them
+            for (final ClassResourceInfo cri : 
factory.getServiceFactory().getClassResourceInfo()) {
+                if (containerResources.contains(cri.getServiceClass())) {
+                    
cri.setNameBindings(AnnotationUtils.getNameBindings(factory.getBus(), 
cri.getServiceClass()));
+                }
+            }
+
             this.context = webContext;
             if (!webContext.startsWith("/")) {
                 this.context = "/" + webContext;
@@ -818,7 +832,8 @@ public class CxfRsHttpListener implements RsHttpListener {
         }
     }
 
-    private ApplicationData getApplicationData(final Application application, 
final String prefix, final Collection<Object> additionalProviders) {
+    private ApplicationData getApplicationData(final Application application, 
final Collection<Class<?>> containerResources,
+                                               final String prefix, final 
Collection<Object> additionalProviders) {
 
         final ApplicationData applicationData = new ApplicationData(prefix, 
application);
 
@@ -893,6 +908,10 @@ public class CxfRsHttpListener implements RsHttpListener {
             }
         }
 
+        for (final Class<?> clazz : containerResources) {
+            applicationData.addResource(false, clazz, null);
+        }
+
         for (final Object singleton : application.getSingletons()) {
             // We've already added the provider above.  This is a duplicate
             if (additionalProviders.contains(singleton)) continue;
diff --git 
a/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java
 
b/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java
index 9f77bbb764..34d75395bf 100644
--- 
a/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java
+++ 
b/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java
@@ -82,6 +82,7 @@ import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -162,6 +163,8 @@ public abstract class RESTService implements ServerService, 
SelfManaging {
         try {
             boolean deploymentWithApplication = 
"true".equalsIgnoreCase(appInfo.properties.getProperty(OPENEJB_USE_APPLICATION_PROPERTY,
 APPLICATION_DEPLOYMENT));
             if (deploymentWithApplication) {
+                final Set<Class<?>> containerResources = 
loadContainerResources(webApp, classLoader);
+                boolean applicationAtContextRoot = false;
                 Class<?> appClazz;
                 for (final String app : webApp.restApplications) {
                     Application application;
@@ -258,9 +261,14 @@ public abstract class RESTService implements 
ServerService, SelfManaging {
                             }
                         }
 
-                        if (!application.getClasses().isEmpty() || 
!application.getSingletons().isEmpty()) {
+                        // CXF runs one server per address, so the container 
resources join the application at the context root
+                        final boolean atContextRoot = ("/" + 
wildcard).equals(prefix);
+                        final Set<Class<?>> appContainerResources = 
atContextRoot ? containerResources : Collections.emptySet();
+                        applicationAtContextRoot |= atContextRoot;
+
+                        if (!application.getClasses().isEmpty() || 
!application.getSingletons().isEmpty() || !appContainerResources.isEmpty()) {
                             pojoConfigurations = 
PojoUtil.findPojoConfig(pojoConfigurations, appInfo, webApp);
-                            deployApplication(appInfo, webApp.contextRoot, 
restEjbs, classLoader, injections, owbCtx, context, additionalProviders, 
pojoConfigurations, application, prefix);
+                            deployApplication(appInfo, webApp.contextRoot, 
restEjbs, classLoader, injections, owbCtx, context, additionalProviders, 
pojoConfigurations, application, appContainerResources, prefix);
                         }
                     }
 
@@ -269,6 +277,11 @@ public abstract class RESTService implements 
ServerService, SelfManaging {
                     }
                 }
 
+                if (!webApp.restApplications.isEmpty() && 
deploymentWithApplication && !applicationAtContextRoot && 
!containerResources.isEmpty()) {
+                    pojoConfigurations = 
PojoUtil.findPojoConfig(pojoConfigurations, appInfo, webApp);
+                    deployApplication(appInfo, webApp.contextRoot, restEjbs, 
classLoader, injections, owbCtx, context, additionalProviders, 
pojoConfigurations, new InternalApplication(null), containerResources, "/" + 
wildcard);
+                }
+
                 if (webApp.restApplications.isEmpty()) {
                     final Application application = new 
InternalApplication(null);
                     for (final String clazz : webApp.restClass) {
@@ -292,7 +305,7 @@ public abstract class RESTService implements ServerService, 
SelfManaging {
                     addEjbToApplication(application, restEjbs);
 
                     if (deploymentWithApplication) {
-                        if (!application.getClasses().isEmpty() || 
!application.getSingletons().isEmpty()) {
+                        if (!application.getClasses().isEmpty() || 
!application.getSingletons().isEmpty() || !containerResources.isEmpty()) {
                             final String path = appPrefix(webApp, 
application.getClass());
                             final String prefix;
                             if (path != null) {
@@ -302,7 +315,7 @@ public abstract class RESTService implements ServerService, 
SelfManaging {
                             }
 
                             pojoConfigurations = 
PojoUtil.findPojoConfig(pojoConfigurations, appInfo, webApp);
-                            deployApplication(appInfo, webApp.contextRoot, 
restEjbs, classLoader, injections, owbCtx, context, additionalProviders, 
pojoConfigurations, application, prefix);
+                            deployApplication(appInfo, webApp.contextRoot, 
restEjbs, classLoader, injections, owbCtx, context, additionalProviders, 
pojoConfigurations, application, containerResources, prefix);
                         }
                     } else {
                         fullServletDeployment(appInfo, webApp, webContext, 
restEjbs, classLoader, injections, owbCtx, context, additionalProviders, 
pojoConfigurations);
@@ -372,6 +385,18 @@ public abstract class RESTService implements 
ServerService, SelfManaging {
         }
     }
 
+    private static Set<Class<?>> loadContainerResources(final WebAppInfo 
webApp, final ClassLoader classLoader) {
+        final Set<Class<?>> resources = new HashSet<>();
+        for (final String clazz : webApp.containerRestClass) {
+            try {
+                resources.add(classLoader.loadClass(clazz));
+            } catch (final ClassNotFoundException e) {
+                throw new OpenEJBRestRuntimeException("can't load class " + 
clazz, e);
+            }
+        }
+        return resources;
+    }
+
     private void addEjbToApplication(final Application application, final 
Map<String, EJBRestServiceInfo> restEjbs) {
         for (final Map.Entry<String, EJBRestServiceInfo> ejb : 
restEjbs.entrySet()) {
             
application.getClasses().add(ejb.getValue().context.getBeanClass());
@@ -479,6 +504,7 @@ public abstract class RESTService implements ServerService, 
SelfManaging {
             } // else keep application prefix
 
             final Set<String> restClasses = new HashSet<>(webApp.restClass);
+            restClasses.addAll(webApp.containerRestClass);
             restClasses.addAll(webApp.ejbRestServices);
 
             for (final String clazz : restClasses) {
@@ -509,7 +535,7 @@ public abstract class RESTService implements ServerService, 
SelfManaging {
         LOGGER.info("Using deployment by endpoint instead of by application 
for JAXRS deployment because an old configuration (by class/ejb) was found on " 
+ clazz);
     }
 
-    private void deployApplication(final AppInfo appInfo, final String 
contextRoot, final Map<String, EJBRestServiceInfo> restEjbs, final ClassLoader 
classLoader, final Collection<Injection> injections, final WebBeansContext 
owbCtx, final Context context, final Collection<Object> additionalProviders, 
final Collection<IdPropertiesInfo> pojoConfigurations, final Application 
application, final String prefix) {
+    private void deployApplication(final AppInfo appInfo, final String 
contextRoot, final Map<String, EJBRestServiceInfo> restEjbs, final ClassLoader 
classLoader, final Collection<Injection> injections, final WebBeansContext 
owbCtx, final Context context, final Collection<Object> additionalProviders, 
final Collection<IdPropertiesInfo> pojoConfigurations, final Application 
application, final Collection<Class<?>> containerResources, final String 
prefix) {
         // get configuration
         Properties configuration;
         if (InternalApplication.class.equals(application.getClass())) {
@@ -543,7 +569,7 @@ public abstract class RESTService implements ServerService, 
SelfManaging {
         final RsRegistry.AddressInfo address = 
rsRegistry.createRsHttpListener(appInfo.appId, contextRoot, listener, 
classLoader, nopath.substring(NOPATH_PREFIX.length() - 1), host, auth, realm);
 
         services.add(new DeployedService(address.complete, contextRoot, 
application.getClass().getName(), appInfo.appId));
-        listener.deployApplication(application, address.complete.substring(0, 
address.complete.length() - wildcard.length()), 
nopath.substring(NOPATH_PREFIX.length(), nopath.length() - wildcard.length()), 
additionalProviders, restEjbs, // app config
+        listener.deployApplication(application, containerResources, 
address.complete.substring(0, address.complete.length() - wildcard.length()), 
nopath.substring(NOPATH_PREFIX.length(), nopath.length() - wildcard.length()), 
additionalProviders, restEjbs, // app config
                 classLoader, injections, context, owbCtx, // injection/webapp 
context
                 new ServiceConfiguration(configuration, appInfo.services)); // 
deployment config
     }
@@ -743,7 +769,7 @@ public abstract class RESTService implements ServerService, 
SelfManaging {
 
                         deployApplication(appInfo, next.getValue().path, 
restEjbs, comp.getClassLoader(), comp.getInjections(),
                                 
containerSystem.getAppContext(appInfo.appId).getWebBeansContext(), 
comp.getJndiContext(),
-                                providers, pojoConfigurations, application, 
wildcard);
+                                providers, pojoConfigurations, application, 
Collections.emptySet(), wildcard);
                     } else {
                         for (final Map.Entry<String, EJBRestServiceInfo> ejb : 
restEjbs.entrySet()) {
                             final BeanContext ctx = ejb.getValue().context;
diff --git 
a/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RsHttpListener.java
 
b/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RsHttpListener.java
index 3eef33fa7e..eaa7bdb91b 100644
--- 
a/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RsHttpListener.java
+++ 
b/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RsHttpListener.java
@@ -40,5 +40,8 @@ public interface RsHttpListener extends HttpListener {
 
     void undeploy();
 
-    void deployApplication(Application application, String prefix, String 
webContext, Collection<Object> additionalProviders, Map<String, 
EJBRestServiceInfo> restEjbs, ClassLoader classLoader, Collection<Injection> 
injections, Context context, WebBeansContext owbCtx, ServiceConfiguration 
serviceConfiguration);
+    /**
+     * @param containerResources resource classes the container deploys along 
with the application, outside of its name bindings
+     */
+    void deployApplication(Application application, Collection<Class<?>> 
containerResources, String prefix, String webContext, Collection<Object> 
additionalProviders, Map<String, EJBRestServiceInfo> restEjbs, ClassLoader 
classLoader, Collection<Injection> injections, Context context, WebBeansContext 
owbCtx, ServiceConfiguration serviceConfiguration);
 }
diff --git 
a/tomee/tomee-microprofile/mp-common/src/main/java/org/apache/tomee/microprofile/TomEEMicroProfileListener.java
 
b/tomee/tomee-microprofile/mp-common/src/main/java/org/apache/tomee/microprofile/TomEEMicroProfileListener.java
index f9f1544c2e..e0cb351cb1 100644
--- 
a/tomee/tomee-microprofile/mp-common/src/main/java/org/apache/tomee/microprofile/TomEEMicroProfileListener.java
+++ 
b/tomee/tomee-microprofile/mp-common/src/main/java/org/apache/tomee/microprofile/TomEEMicroProfileListener.java
@@ -120,6 +120,12 @@ public class TomEEMicroProfileListener {
                             className -> 
className.equals(MicroProfileHealthChecksEndpoint.class.getName()));
                 });
 
+        // The health endpoint serves the whole runtime, so it must not depend 
on the webapp's JAX-RS applications,
+        // which only deploy the classes they list.
+        if 
(webApp.restClass.remove(MicroProfileHealthChecksEndpoint.class.getName())) {
+            
webApp.containerRestClass.add(MicroProfileHealthChecksEndpoint.class.getName());
+        }
+
         // we need to register the OpenAPI servlet, but in order to generate 
the OpenAPI model, SmallRye uses Jandex,
         // a XBean Finder equivalent from JBoss. This seems to be a library 
used in many placed, so we want to build the
         // index only once and pass it everywhere it's needed. Also in order 
to build the index, we need the entire

Reply via email to