在执行JAXB Unmarshalling时处理无效的枚举值

时间:2012-08-27 18:16:30

标签: web-services soapui jaxb2

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

**enum Fruit {
    APPLE,ORANGE;
}**

我正在使用SOAP UI来检查我的Web服务。因为它是一个自由形式的条目,如果我给错误的水果说“Guva”然后在执行UnMarshalling之后将其返回为null。

我该如何避免这种情况?我应该使用自定义枚举类而不是JAXB生成的。请举个例子。即

问候 SRI

3 个答案:

答案 0 :(得分:17)

注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。

默认情况下,您的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;

}

<强>演示

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));
    }

}

JAXB参考实施

不幸的是,JAXB RI中似乎存在一个错误,因为无效的枚举值没有通过验证事件。

Not a number: ABC

解决方法

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

FruitAdapter

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);
        }
    }

}

<强>水果

使用@XmlJavaTypeAdapter注释将XmlAdapterFruit enumb相关联。

package forum12147306;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlJavaTypeAdapter(FruitAdapter.class)
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]

EclipseLink JAXB(MOXy)

使用MOXy抛出两个验证事件。要将MOXy指定为JAXB提供程序,请参阅:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

Exception Description: The object [ABC], of class [class java.lang.String], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[number-->number/text()]] with descriptor [XMLDescriptor(forum12147306.Root --> [DatabaseTable(root)])], could not be converted to [class java.lang.Integer].
Internal Exception: java.lang.NumberFormatException: For input string: "ABC"

Exception Description: No conversion value provided for the value [Guva] in field [fruit/text()].
Mapping: org.eclipse.persistence.oxm.mappings.XMLDirectMapping[fruit-->fruit/text()]
Descriptor: XMLDescriptor(forum12147306.Root --> [DatabaseTable(root)])

答案 1 :(得分:1)

基于原始回复的简短回答。你需要做两件事

  1. 实现自定义适配器以引发和异常
  2. 添加事件处理程序以使其无法解组
  3. 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);
            }
        }
    }
    

    unmarshaller的事件处理程序无法解析错误 - 即返回 false (您可能需要决定何时失败以及何时不失败)

        JAXBContext jc = JAXBContext.newInstance(Root.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setEventHandler(new ValidationEventHandler() {
            @Override
            public boolean handleEvent(ValidationEvent validationEvent) {
                 return false;
            }
        });
    

答案 2 :(得分:0)

另一种方法是生成XSD架构,如下所示:how can i unmarshall in jaxb and enjoy the schema validation without using an explicit schema file

以下是我从dolbysurnd偷走的代码段:

import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

private static List<DOMResult> generateJaxbSchemas(JAXBContext context) throws IOException {
    final List<DOMResult> domResultList = new ArrayList<>();
    context.generateSchema(new SchemaOutputResolver() {
        @Override
        public Result createOutput(String ns, String file) throws IOException {
            DOMResult domResult = new DOMResult();
            domResult.setSystemId(file);
            domResultList.add(domResult);
            return domResult;
        }
    });
    return domResultList;
}

private static Unmarshaller createUnmarshaller(JAXBContext context) throws SAXException, IOException, JAXBException {
    Unmarshaller unmarshaller = context.createUnmarshaller();
    List<DOMSource> domSourceList = new ArrayList<>();
    for (DOMResult domResult : generateJaxbSchemas(context)) {
        domSourceList.add(new DOMSource(domResult.getNode()));
    }
    SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
    Schema schema = schemaFactory.newSchema(domSourceList.toArray(new DOMSource[0]));
    unmarshaller.setSchema(schema);
    return unmarshaller;
}

public void unmarshal(JAXBContext context, Reader reader) throws JAXBException, SAXException, IOException {
    Unmarshaller unmarshaller = createUnmarshaller(context);
    Object result = unmarshaller.unmarshal(reader);
}