【问题标题】:JAXB unmarshaller's handleEvent not being called未调用 JAXB 解组器的 handleEvent
【发布时间】:2018-04-17 08:42:19
【问题描述】:

我正在尝试使用 MOXy 设置一个简单的 Jersey JAX-RS 应用程序以支持 JAXB JSON,并且我想自定义解组器。我做了以下事情:

@Provider
public class CustomProvider extends ConfigurableMoxyJsonProvider{
  @Override
  protected void preReadFrom(..., Unmarshaller unmarshaller) throws JAXBException{
    super.preReadFrom(...);
    System.out.println("preReadFrom entered");

    unmarshaller.setEventHandler(new ValidationEventHandler(){
      @Override
      public boolean handleEvent(ValidationEvent event){
        System.out.println("Entered handleEvent");

        return false;
      }
    });
  }
}

我为preReadFrom 编写了一个覆盖,并在解组器上设置了一个事件处理程序。当我传递一个无效的 JSON 正文时,preReadFrom 中的打印语句会执行,但不是事件处理程序中的那个。因此提供程序已正确注册,但未调用事件处理程序。

什么可能导致这个问题?

我想要实现的是当用户在 JSON 正文中传递无关的属性时,我想抛出一个错误(默认情况下,这些属性被忽略)。在各种网站上搜索,添加事件处理程序是唯一的方法。如果我也能以不同的方式实现这一点,那就太好了。

【问题讨论】:

  • 为什么不在传递给preReadFrom 之前自定义Unmarshaller?为什么你需要一个全新的供应商?能否提供一些可运行的代码进行测试?
  • 我正在这样做。我正在自定义传递给preReadFrom 的解组器。通过自定义,如果您的意思是设置一些属性 - 我将我的意图添加到问题中。我找不到任何可以实现该意图的属性。
  • 你不能访问Unmarshaller 之前它被传递给preReadFrom 方法吗?它来自哪里?
  • 有什么特别的理由说明这会是有益的吗?我们也可以这样做吗?
  • 那么您可以直接更改Unmarshaller,而不必创建新的提供程序。 preReadFrom 在哪里调用?

标签: java json jaxb jersey


【解决方案1】:
  1. 我假设 System.out.println("preReadFrom entered"); 正在被调用,而您的 CustomProvider实际上已注册并使用。因为在 Weblogic 中,例如即使您注册了不同的提供程序,除非您禁用 Moxy,否则仍会调用默认的 ConfigurableMoxyJsonProvider

  2. 如果第一个假设是正确的,那么肯定会调用 public boolean handleEvent(ValidationEvent event) 进行验证,例如您的 Pojo、属性是否为数字并且您在 json 中传递字符串。

  3. 对于UnmappedElements,我看到 Moxy “忽略”了 Json 的警告。这意味着如果您的 pojo 如下所示:

    public class Emp {
        public Emp() {
            super();
        }
        private int id ;
        public void setId(int id) {
            this.id = id;
        }
    
        public int getId() {
            return id;
        }
    
    }
    

    你的 Json 就像:{"id" : 11, "name1" : 111} 然后你的handleEvent 不会被调用。原因是 Moxy 使用 org.eclipse.persistence.internal.oxm.record.UnmarshalRecordI‌mpl.startUnmappedEle‌​ment() 在向事件处理程序发出警告之前检查媒体类型是否为 xml。

那么如何解决这个问题。我可能不知道最好的答案,但这是我的解决方案:

在您的preReadFrom 方法中添加您的自定义UnmappedHandlerClass,如下所示

protected void preReadFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
                           MultivaluedMap<String, String> httpHeaders,
                           Unmarshaller unmarshaller) throws JAXBException {
    System.out.println("preReadFrom entered");
    super.preReadFrom(type, genericType, annotations, MediaType.WILDCARD_TYPE, httpHeaders, unmarshaller);
    System.out.println("preReadFrom returned from super");

    //new code
    if(unmarshaller instanceof org.eclipse.persistence.jaxb.JAXBUnmarshaller) {
        org.eclipse.persistence.jaxb.JAXBUnmarshaller   moxyUn = ( org.eclipse.persistence.jaxb.JAXBUnmarshaller)unmarshaller;
        moxyUn.getXMLUnmarshaller().setUnmappedContentHandlerClass(CustomUnmapped.class);
    }
//your existing code
    unmarshaller.setEventHandler(new ValidationEventHandler() {
        @Override
        public boolean handleEvent(ValidationEvent event) {
            System.out.println("Entered handleEvent");

            return false;
        }
    });
}

您可以像这样使用 Customunmapped 类:

class CustomUnmapped extends org.eclipse.persistence.internal.oxm.unmapped.DefaultUnmappedContentHandler {
    @Override
    public void startElement(String p1, String p2, String p3, Attributes p4) throws SAXException {
        throw new SAXNotRecognizedException(p1);
    }
}

那应该行。但在尝试 3 之前,只需确保您的 a) CustomProvider 实际上是通过添加断点或 System.out.. 语句来调用的。 b) 你的 handleEvent 被调用来处理一般错误,比如在 json 中为数字字段传递字符串 x。

【讨论】:

  • 说了这么多之后,我还想咨询 Moxy 团队的@blaise-doughan,了解未映射的 Json 字段以及是否有更简单的方法来处理。
  • @nitishc What I want to achieve is when a user passes extraneous attributes in the JSON body, I want to throw an error 这行表明您确实需要自定义 UnmappedContentHandler 和 ValidationHandler。
  • 哇!感谢您在第 2 点中的详细说明。到目前为止,我通过传递无效的 JSON 进行检查。在这种情况下,不会调用 handleEvent。但是当我传递一个字符串而不是一个数字时 - 正如你所说 - 它被称为!我想知道为什么。
  • 这在第 3 点中进行了解释 @nitishch 原因是默认的“Unampped”元素处理仅适用于 xml,因为上面第 3 点中提到了签入类。这可以使用我添加的 sn-p 来解决。
  • 原来这是因为 ContextResolver 中的一些错误配置。我在 ContextResolver 中有 JAXBContext.property(ServerProperties.MOXY_JSON_FEATURE_DISABLE, true)。出于某种原因,我删除了它,现在一切正常:)
猜你喜欢
  • 1970-01-01
  • 2013-11-08
  • 2017-09-06
  • 2013-11-15
  • 1970-01-01
  • 2012-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多