Web services 在执行JAXB解组时处理无效的枚举值

Web services 在执行JAXB解组时处理无效的枚举值,web-services,soapui,jaxb2,Web Services,Soapui,Jaxb2,我的Jaxb基于XML模式设置创建了一个枚举类 **enum Fruit { APPLE,ORANGE; }** 我正在使用soapui检查我的web服务。因为它是一个自由形式的条目,如果我给了一个错误的水果,比如说“Guva”,那么它不会抛出异常,而是在进行解组后将其返回为null 我怎样才能避免这种情况?我应该使用自定义枚举类而不是JAXB生成的枚举类吗。请举例说明。i、 e. package forum12147306; import javax.xml.bind.JAXBEx

我的Jaxb基于XML模式设置创建了一个枚举类

**enum Fruit {
    APPLE,ORANGE;
}**
我正在使用soapui检查我的web服务。因为它是一个自由形式的条目,如果我给了一个错误的水果,比如说“Guva”,那么它不会抛出异常,而是在进行解组后将其返回为null

我怎样才能避免这种情况?我应该使用自定义枚举类而不是JAXB生成的枚举类吗。请举例说明。i、 e.

package forum12147306;

import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class FruitAdapter extends XmlAdapter<String, Fruit> {

    @Override
    public String marshal(Fruit fruit) throws Exception {
        return fruit.name();
    }

    @Override
    public Fruit unmarshal(String string) throws Exception {
        try {
            return Fruit.valueOf(string);
        } catch(Exception e) {
            throw new JAXBException(e);
        }
    }

}
问候
sri

注意:我是专家组的负责人和成员

默认情况下,JAXB(JSR-222)实现不会因任何转换异常而失败。如果使用JAXB API进行解组,那么可以设置
ValidationEventHandler
来捕获任何问题。下面是一个例子

根目录

package forum12147306;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Root {

    private int number;
    private Fruit fruit;

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public Fruit getFruit() {
        return fruit;
    }

    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }

}
package forum12147306;

public enum Fruit {

    APPLE, 
    ORANGE;

}
Not a number: ABC
javax.xml.bind.JAXBException
 - with linked exception:
[java.lang.IllegalArgumentException: No enum const class forum12147306.Fruit.Guva]
水果

package forum12147306;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Root {

    private int number;
    private Fruit fruit;

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public Fruit getFruit() {
        return fruit;
    }

    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }

}
package forum12147306;

public enum Fruit {

    APPLE, 
    ORANGE;

}
Not a number: ABC
javax.xml.bind.JAXBException
 - with linked exception:
[java.lang.IllegalArgumentException: No enum const class forum12147306.Fruit.Guva]
演示

package forum12147306;

import java.io.StringReader;
import javax.xml.bind.*;

public class Demo {

    private static final String XML = "<root><number>ABC</number><fruit>Guva</fruit></root>";
    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setEventHandler(new ValidationEventHandler() {

            @Override
            public boolean handleEvent(ValidationEvent validationEvent) {
                 System.out.println(validationEvent.getMessage());
                 //validationEvent.getLinkedException().printStackTrace();
                 return true;
            }

        });

        Root root = (Root) unmarshaller.unmarshal(new StringReader(XML));
    }

}
解决问题

编写您自己的
XmlAdapter
来处理与
Fruit
enum的转换:

水果适配器

新输出

package forum12147306;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Root {

    private int number;
    private Fruit fruit;

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public Fruit getFruit() {
        return fruit;
    }

    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }

}
package forum12147306;

public enum Fruit {

    APPLE, 
    ORANGE;

}
Not a number: ABC
javax.xml.bind.JAXBException
 - with linked exception:
[java.lang.IllegalArgumentException: No enum const class forum12147306.Fruit.Guva]

日食JAXB(MOXy)

使用MOXy会引发两个验证事件。要将MOXy指定为JAXB提供程序,请参见:


以原始答复为基础的简短答复。你需要做两件事

  • 实现自定义适配器以引发异常和异常
  • 添加事件处理程序以失败解组
  • Fruit.java定义并使用适配器

    package forum12147306;
    
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    
    @XmlJavaTypeAdapter(FruitAdapter.class)
    public enum Fruit {
    
        APPLE, 
        ORANGE;
    
    }
    
    class FruitAdapter extends XmlAdapter<String, Fruit> {
    
        @Override
        public String marshal(Fruit fruit) throws Exception {
            return fruit.name();
        }
    
        @Override
        public Fruit unmarshal(String string) throws Exception {
            try {
                return Fruit.valueOf(string);
            } catch(Exception e) {
                throw new JAXBException(e);
            }
        }
    }
    

    另一种方法是生成XSD模式,如下所示:

    以下是我从中偷来的片段:

    import java.io.IOException;
    导入java.io.Reader;
    导入java.util.ArrayList;
    导入javax.xml.bind.JAXBContext;
    导入javax.xml.bind.JAXBException;
    导入javax.xml.bind.SchemaOutputResolver;
    导入javax.xml.bind.Unmarshaller;
    导入javax.xml.transform.Result;
    导入javax.xml.transform.dom.DOMResult;
    导入javax.xml.transform.dom.DOMSource;
    导入javax.xml.validation.Schema;
    导入javax.xml.validation.SchemaFactory;
    导入org.xml.sax.SAXException;
    私有静态列表模式(JAXBContext上下文)引发IOException{
    最终列表domResultList=new ArrayList();
    generateSchema(新的SchemaOutputResolver(){
    @凌驾
    公共结果createOutput(字符串ns、字符串文件)引发IOException{
    DOMResult DOMResult=新的DOMResult();
    domResult.setSystemId(文件);
    添加(domResult);
    返回结果;
    }
    });
    返回domResultList;
    }
    私有静态解组器createUnmarshaller(JAXBContext上下文)抛出SAXException、IOException、JAXBEException{
    Unmarshaller Unmarshaller=context.createUnmarshaller();
    List domSourceList=newarraylist();
    for(DOMResult DOMResult:generateJaxbSchemas(上下文)){
    添加(新的DOMSource(domResult.getNode());
    }
    SchemaFactory SchemaFactory=SchemaFactory.newInstance(“http://www.w3.org/2001/XMLSchema");
    Schema Schema=schemaFactory.newSchema(domSourceList.toArray(新的DOMSource[0]);
    解组器。设置模式(模式);
    返回解组器;
    }
    public void unmarshal(JAXBContext上下文、读卡器)抛出jaxbeexception、SAXException、IOException{
    Unmarshaller Unmarshaller=createUnmarshaller(上下文);
    对象结果=解组器。解组器(读取器);
    }
    
    非常感谢您提供的详细示例。“…JAXB中似乎有一个bug”-这种行为仍然存在。可能不匹配的枚举不是关键错误:-)您的“变通方法”工作正常。我也将此设计用于非枚举。真的很棒!Blaise Doughan自从你发布这个答案后MOXy有什么变化吗?我似乎无法让MOXy 2.6.2触发XML或Json中未知枚举值的事件。我是否也必须将XmlJavaTypeAdapter与MOXy一起使用?JAXB中仍然存在该缺陷!ThanksHow我可以将此解决方案与Spring一起使用,只使用注释吗?