JAXB unmarshaller的handleEvent未被调用

时间:2017-11-04 21:15:53

标签: java json jaxb jersey

我尝试使用MOXy设置简单的Jersey JAX-RS应用程序以支持JAXB JSON,我想自定义unmarshaller。我做了以下事情:

@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编写了一个覆盖,并在unmarshaller上设置了一个事件处理程序。当我传递一个无效的JSON主体时,preReadFrom中的print语句执行但不执行事件处理程序中的print语句。因此提供程序已正确注册,但未调用事件处理程序。

可能导致此问题的原因是什么?

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

1 个答案:

答案 0 :(得分:0)

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

  2. 如果第一个假设是正确的,那么肯定会让public boolean handleEvent(ValidationEvent event)调用验证,例如你的Pojo属性是数字的,你在json中传递String。

  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。

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

    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之前,只需确保通过添加断点或System.out ..语句实际调用a)CustomProvider。 b)你的handleEvent被调用一般错误,比如在json中传递一个字符串x,用于数字字段。