You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rz...@apache.org on 2026/10/13 07:52:43 UTC
(tomee) 15/18: Do not return EJB exception messages from the default JAX-RS mapper (#3083)
This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch tomee-10.x
in repository https://gitbox.apache.org/repos/asf/tomee.git
commit 68ab3f5ea81ed276ec61ad8403f96b0b6a6d327a
Author: Richard Zowalla <rz...@apache.org>
AuthorDate: Tue Oct 13 08:49:40 2026 +0200
Do not return EJB exception messages from the default JAX-RS mapper (#3083)
Log the cause as a warning instead. Setting the property
openejb.jaxrs.ejb-exception-mapper.expose-message=true restores it.
(cherry picked from commit 22162c6b132ec50d47da1b77048b13c12721f759)
---
.../openejb/server/cxf/rs/EJBExceptionMapper.java | 25 +++++-
.../server/cxf/rs/EJBExceptionMapperTest.java | 89 ++++++++++++++++++++++
2 files changed, 112 insertions(+), 2 deletions(-)
diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/EJBExceptionMapper.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/EJBExceptionMapper.java
index c4fa6e9d19..97019b637e 100644
--- a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/EJBExceptionMapper.java
+++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/EJBExceptionMapper.java
@@ -23,8 +23,22 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Providers;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.util.LogCategory;
+import org.apache.openejb.util.Logger;
+/**
+ * Maps {@link EJBException}s to the mapper of their cause when one is registered.
+ * Otherwise a 500 response is returned. The exception message is only written to the
+ * response body when {@value #EXPOSE_MESSAGE} is set to {@code true}, it is logged otherwise.
+ */
public class EJBExceptionMapper implements ExceptionMapper<EJBException> {
+ public static final String EXPOSE_MESSAGE = "openejb.jaxrs.ejb-exception-mapper.expose-message";
+
+ private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_RS, EJBExceptionMapper.class);
+
+ private final boolean exposeMessage = SystemInstance.get().getOptions().get(EXPOSE_MESSAGE, false);
+
@Context
private Providers providers;
@@ -44,7 +58,14 @@ public class EJBExceptionMapper implements ExceptionMapper<EJBException> {
return defaultResponse(ejbException);
}
- private Response defaultResponse(Exception cause) {
- return Response.serverError().type(MediaType.TEXT_PLAIN_TYPE).entity(cause.getMessage()).build();
+ private Response defaultResponse(final Exception cause) {
+ if (exposeMessage) {
+ return Response.serverError().type(MediaType.TEXT_PLAIN_TYPE).entity(cause.getMessage()).build();
+ }
+ LOGGER.warning("Unmapped EJB exception, returning a 500 response: {0}", String.valueOf(cause));
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Unmapped EJB exception", cause);
+ }
+ return Response.serverError().build();
}
}
diff --git a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/EJBExceptionMapperTest.java b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/EJBExceptionMapperTest.java
new file mode 100644
index 0000000000..57c6566104
--- /dev/null
+++ b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/EJBExceptionMapperTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.openejb.server.cxf.rs;
+
+import jakarta.ejb.EJBAccessException;
+import jakarta.ejb.EJBException;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ExceptionMapper;
+import jakarta.ws.rs.ext.Providers;
+import org.apache.openejb.loader.SystemInstance;
+import org.junit.After;
+import org.junit.Test;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Proxy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class EJBExceptionMapperTest {
+ private static final String DETAIL = "jdbc:db://internal-host/schema";
+
+ @After
+ public void reset() {
+ SystemInstance.reset();
+ }
+
+ @Test
+ public void defaultResponseHasNoMessage() throws Exception {
+ final Response response = newMapper(null).toResponse(new EJBException(new IllegalStateException(DETAIL)));
+ assertEquals(500, response.getStatus());
+ assertNull(response.getEntity());
+ }
+
+ @Test
+ public void defaultResponseWithoutCauseHasNoMessage() throws Exception {
+ final Response response = newMapper(null).toResponse(new EJBException(DETAIL));
+ assertEquals(500, response.getStatus());
+ assertNull(response.getEntity());
+ }
+
+ @Test
+ public void messageExposedWhenEnabled() throws Exception {
+ SystemInstance.get().setProperty(EJBExceptionMapper.EXPOSE_MESSAGE, "true");
+ final Response response = newMapper(null).toResponse(new EJBException(new IllegalStateException(DETAIL)));
+ assertEquals(500, response.getStatus());
+ assertEquals(DETAIL, response.getEntity());
+ }
+
+ @Test
+ public void accessDeniedIsForbidden() throws Exception {
+ final Response response = newMapper(null).toResponse(new EJBAccessException(DETAIL));
+ assertEquals(403, response.getStatus());
+ assertNull(response.getEntity());
+ }
+
+ @Test
+ public void causeMapperIsUsed() throws Exception {
+ final ExceptionMapper<IllegalArgumentException> mapper = e -> Response.status(234).entity(e.getMessage()).build();
+ final Response response = newMapper(mapper).toResponse(new EJBException(new IllegalArgumentException("oops")));
+ assertEquals(234, response.getStatus());
+ assertEquals("oops", response.getEntity());
+ }
+
+ private static EJBExceptionMapper newMapper(final ExceptionMapper<?> causeMapper) throws Exception {
+ final EJBExceptionMapper mapper = new EJBExceptionMapper();
+ final Providers providers = (Providers) Proxy.newProxyInstance(
+ EJBExceptionMapperTest.class.getClassLoader(), new Class<?>[]{Providers.class},
+ (proxy, method, args) -> "getExceptionMapper".equals(method.getName()) ? causeMapper : null);
+ final Field field = EJBExceptionMapper.class.getDeclaredField("providers");
+ field.setAccessible(true);
+ field.set(mapper, providers);
+ return mapper;
+ }
+}