当前位置: 首页 > 知识库问答 >
问题:

在Glassfish 4.1中从Object.AfterUnmarshal捕获异常

马晓博
2023-03-14

我目前正在JDK 1.8.0-40上运行Glassfish 4.1。我正在使用javaee-web-api-7.0和jerse-media-moxy-2.22。我正在将JSON和XML从JAXB注释的java对象编组/解组到JAXB注释的java对象。

我设置了ContextResolver ,以便为Unmarshaller提供自定义ValidationEventHandler,该ValidationEventHandler将从属性设置器收集异常,并抛出带有聚合验证错误的BadRequestException。这部分起作用了。

但是,对于检查未设置属性的对象,我还有BeforeMarshalAfterUnmarshal方法(必须设置属性的规则因属性的值而异,因此我排除了对架构的验证)。如果从AfterUnmarshal方法引发异常,则ValidationEventHandler不会看到异常,而是冒泡到ExceptionMapper

是否有任何方法可以捕获单个对象上的BeforeMarshalAfterUnmarshal方法的异常,并将它们传递给ValidationEventHandler

我认为可以实现MessageBodyReader来捕获异常,使用Unmarshaller.GetEventHandler,手动调用ValidationEventHandler.HandleEvent并抛出BadRequestException <罢工> 如果 HandleEvent返回false [edit:如果从unmarshaller.unmarshal引发异常,则无法继续解封,因此唯一可能的追索是终止处理]。但这将缺少事件位置信息,而且我并不特别喜欢实现自己的MessageBodyReader。我希望有一个更容易的内置方式来做到这一点,我还没有发现。

事先谢谢你的帮助。

共有1个答案

宰父涵忍
2023-03-14

经过一大堆挖掘和头疼,我最终开发出了一个解决方案。

编辑:你不需要打补丁泽西来实现这个行为。我在任何地方都找不到它的文档,但是org.glassfish.jersey.internal.inject.custom注释将提供程序标记为自定义(而仅有@provider是不够的)。如果提供程序是用于application/json的,则还必须通过将commonproperties.moxy_json_feature_disable设置为true来禁用MOXy。因此,您只需:

@Custom
@Provider
public class MyCustomMessageBodyReader...
[...]

<罢工> 这是我的解决方案中我最不喜欢的部分,但也让我从一堆代码重复中拯救了出来。泽西选择排序算法 MessageBodyReader/Writer无法确定应用程序提供程序的优先级(我可以找到)。我想延长 AbstractRootElementJAXBProvider来重用它的功能,但这意味着我不能使它比Jersey提供的更具体 XMLRootelementJAXBProvider。因为默认情况下Jersey只根据媒体类型距离、对象类型距离以及提供程序是否注册为自定义提供程序(通过 @provider注释未注册为自定义提供程序),则将始终选择Jersey实现而不是my MessageBodyReader/Writer

<罢工> 我从Github查看了Jersey 2.10.4的源代码并进行了补丁 要使用的MessageBodyFactory @priority批注作为选择算法的一部分 MessageBodyReader/Writer

diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessageBodyFactory.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessageBodyFactory.java
index 3845b0c..110f18c 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessageBodyFactory.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessageBodyFactory.java
@@ -72,6 +72,7 @@ import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.ReaderInterceptor;
 import javax.ws.rs.ext.WriterInterceptor;

+import javax.annotation.Priority;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import javax.xml.transform.Source;
@@ -107,6 +108,8 @@ import jersey.repackaged.com.google.common.primitives.Primitives;
  */
 public class MessageBodyFactory implements MessageBodyWorkers {

+    private static final int DEFAULT_WORKER_PRIORITY = 1000;
+
     private static final Logger LOGGER = Logger.getLogger(MessageBodyFactory.class.getName());

     /**
@@ -218,13 +221,15 @@ public class MessageBodyFactory implements MessageBodyWorkers {
         public final T provider;
         public final List<MediaType> types;
         public final Boolean custom;
+        public final int priority;
         public final Class<?> providerClassParam;

         protected WorkerModel(
-                final T provider, final List<MediaType> types, final Boolean custom, Class<T> providerType) {
+                final T provider, final List<MediaType> types, final Boolean custom, final int priority, Class<T> providerType) {
             this.provider = provider;
             this.types = types;
             this.custom = custom;
+            this.priority = priority;
             this.providerClassParam = getProviderClassParam(provider, providerType);
         }

@@ -239,8 +244,8 @@ public class MessageBodyFactory implements MessageBodyWorkers {

     private static class MbrModel extends WorkerModel<MessageBodyReader> {

-        public MbrModel(MessageBodyReader provider, List<MediaType> types, Boolean custom) {
-            super(provider, types, custom, MessageBodyReader.class);
+        public MbrModel(MessageBodyReader provider, List<MediaType> types, Boolean custom, int priority) {
+            super(provider, types, custom, priority, MessageBodyReader.class);
         }

         public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
@@ -263,8 +268,8 @@ public class MessageBodyFactory implements MessageBodyWorkers {

     private static class MbwModel extends WorkerModel<MessageBodyWriter> {

-        public MbwModel(MessageBodyWriter provider, List<MediaType> types, Boolean custom) {
-            super(provider, types, custom, MessageBodyWriter.class);
+        public MbwModel(MessageBodyWriter provider, List<MediaType> types, Boolean custom, int priority) {
+            super(provider, types, custom, priority, MessageBodyWriter.class);
         }

         public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
@@ -437,6 +442,10 @@ public class MessageBodyFactory implements MessageBodyWorkers {
             if (modelA.custom ^ modelB.custom) {
                 return (modelA.custom) ? -1 : 1;
             }
+
+            if(modelA.priority != modelB.priority) {
+                return modelA.priority - modelB.priority;
+            }
             return 0;
         }

@@ -578,17 +587,27 @@ public class MessageBodyFactory implements MessageBodyWorkers {
         }
     }

+    private static int getPriority(Priority annotation) {
+        if (annotation == null) {
+            return DEFAULT_WORKER_PRIORITY;
+        }
+
+        return annotation.value();
+    }
+
     private static void addReaders(List<MbrModel> models, Set<MessageBodyReader> readers, boolean custom) {
         for (MessageBodyReader provider : readers) {
+            int priority = getPriority(provider.getClass().getAnnotation(Priority.class));
             List<MediaType> values = MediaTypes.createFrom(provider.getClass().getAnnotation(Consumes.class));
-            models.add(new MbrModel(provider, values, custom));
+            models.add(new MbrModel(provider, values, custom, priority));
         }
     }

     private static void addWriters(List<MbwModel> models, Set<MessageBodyWriter> writers, boolean custom) {
         for (MessageBodyWriter provider : writers) {
+            int priority = getPriority(provider.getClass().getAnnotation(Priority.class));
             List<MediaType> values = MediaTypes.createFrom(provider.getClass().getAnnotation(Produces.class));
-            models.add(new MbwModel(provider, values, custom));
+            models.add(new MbwModel(provider, values, custom, priority));
         }
     }

<罢工> 构建Jersey之后,我用我的补丁版本替换了Glassfish modules目录中的Jersey通用jar。这让我注释我的 MessageBodyReader/Writer使用 @priority(500)并由泽西选择。

<罢工> 我觉得这是最干净的方式让我把我的 MessageBodyReader/Writer而不影响Glassfish中依赖于Jersey的任何其他内容。

public final class ValidatingUnmarshallerListener
        extends Unmarshaller.Listener
{
    private final ValidationEventHandler validationEventHandler;

    public ValidatingUnmarshallerListener(
            ValidationEventHandler validationEventHandler)
    {
        this.validationEventHandler = validationEventHandler;
    }

    @Override
    public void afterUnmarshal(Object target, Object parent)
    {
        if (target == null
                || !(target instanceof CanBeValidated))
        {
            return;
        }

        CanBeValidated v = (CanBeValidated) target;
        Collection<Throwable> validationErrors = v.validate();

        for (Throwable t : validationErrors)
        {
            ValidationEvent event = new ValidationEventImpl(
                    ValidationEvent.ERROR,
                    t.getLocalizedMessage(),
                    null,
                    t);

            this.validationEventHandler.handleEvent(event);
        }
    }
}
@Override
protected Object readFrom(
        Class<Object> type,
        MediaType mediaType,
        Unmarshaller u,
        InputStream entityStream)
        throws JAXBException
{
    final SAXSource source = getSAXSource(spf.provide(), entityStream);
    ValidationEventCollector eventCollector = new ValidationEventCollector();
    ValidatingUnmarshallerListener listener = new ValidatingUnmarshallerListener(eventCollector);
    u.setEventHandler(eventCollector);
    u.setListener(listener);

    final Object result;
    if (type.isAnnotationPresent(XmlRootElement.class))
    {
        result = u.unmarshal(source);
    }
    else
    {
        result = u.unmarshal(source, type).getValue();
    }

    if (eventCollector.hasEvents())
    {
        HttpError error = new HttpError(Response.Status.BAD_REQUEST);

        for (ValidationEvent event : eventCollector.getEvents())
        {
            error.addMessage(ValidationUtil.toString(event));
        }

        throw new WebApplicationException(error.toResponse());
    }

    return result;
}
 类似资料:
  • 每当我的VNC连接被终止时(每当我重新启动VM时),我都试图捕捉一个异常,并且我试图忽略它以继续我的Jython脚本。我不知道如何编写try catch语句来捕获异常,因为它起源于Java。这是一个sikuliX脚本。

  • 问题内容: 发现在Java 1.6(以及从Eclipse)上运行时,吞没了该方法中的异常之后,我试图找到一种捕获这些异常的方法,而不会在我的所有实现中都添加throw / catch 。 该API建议覆盖应对此有所帮助: 导致此future报告一个ExecutionException,并以给定throwable作为其原因,除非已经设置或取消了此Future。计算失败时,run方法在内部调用此方法。

  • 问题内容: 好,我有问题。如果在处理HTTP请求时发生未捕获的异常,则我没有机会在http.ServerResponse对象上调用end()方法。因此,服务器将永远挂起并且永远不会满足该请求。 这是一个例子: 如果访问/ error,则会发生异常,但会被捕获。用户收到错误消息-没问题。但是,如果我访问/ hang,服务器最终将抛出未捕获的异常并永远挂起。以后对/ hang的任何请求都将挂起。 糟透

  • export class SearchService { ... .map((response) => response.json()) .catch((e) => { if (e.status >== 500) { return cachedVersion(); new Error(`${ e.status

  • 问题内容: 我正在研究用于并行计算JavaSeis.org的软件开发框架。我需要一个强大的机制来报告线程异常。在开发过程中,了解异常来自何处具有很高的价值,因此我想在过度报告方面犯错。我还希望能够在线程中处理Junit4测试。下面的方法是合理的还是有更好的方法? 问题答案: 我不相信在使用时有标准的“钩子”来获取这些异常。但是,如果您需要支持(听起来很合理,假设您使用),则始终可以包装Callab

  • 我的用它的作用域启动coroutine 我的只处理一些逻辑,在本例中是某种验证器 然后我的只处理网络层/本地层 以下是我得到的错误日志: 错误直接指向显式的语句。