10

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

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

我正在使用 SOAP UI 来检查我的 Web 服务。由于它是一个自由形式的条目,如果我给出错误的水果说“Guva”,那么它不会抛出异常,而是在执行 UnMarshalling 后将其返回为 null。

我怎样才能避免这种情况?我应该使用自定义枚举类而不是 JAXB 生成的。请举一些例子。IE

问候斯里兰卡

4

3 回答 3

20

注意: 我是EclipseLink JAXB (MOXy)负责人,也是JAXB (JSR-222)专家组的成员。

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

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枚举的转换:

水果适配器

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枚举相关联。

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)])
于 2012-08-27T19:16:50.800 回答
2

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

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

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;
        }
    });
于 2014-05-30T15:40:48.573 回答
0

另一种方法是生成 XSD 模式,如下所示:如何在 jaxb 中解组并在不使用显式模式文件的情况下享受模式验证

这是我从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);
}
于 2015-03-10T10:50:37.563 回答