我的 Jaxb 基于 XML 模式设置创建了一个 Enum 类。
**enum Fruit {
APPLE,ORANGE;
}**
我正在使用 SOAP UI 来检查我的 Web 服务。由于它是一个自由形式的条目,如果我给出错误的水果说“Guva”,那么它不会抛出异常,而是在执行 UnMarshalling 后将其返回为 null。
我怎样才能避免这种情况?我应该使用自定义枚举类而不是 JAXB 生成的。请举一些例子。IE
问候斯里兰卡
我的 Jaxb 基于 XML 模式设置创建了一个 Enum 类。
**enum Fruit {
APPLE,ORANGE;
}**
我正在使用 SOAP UI 来检查我的 Web 服务。由于它是一个自由形式的条目,如果我给出错误的水果说“Guva”,那么它不会抛出异常,而是在执行 UnMarshalling 后将其返回为 null。
我怎样才能避免这种情况?我应该使用自定义枚举类而不是 JAXB 生成的。请举一些例子。IE
问候斯里兰卡
注意: 我是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
注释将XmlAdapter
与Fruit
枚举相关联。
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)])
基于原始回复的简短回答。你需要做两件事
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;
}
});
另一种方法是生成 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);
}