java 使用注解的 JAXB 验证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2365644/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JAXB validation using annotations
提问by Martin
If I have a simple class such as:-
如果我有一个简单的类,例如:-
@XmlRootElement
public class MyClass
{
@XmlAttribute(required=true)
private String myattribute
}
Is it possible to validate a corresponding xml document WITHOUT an xml schema i.e. using only the annotations?
是否可以在没有 xml 模式的情况下验证相应的 xml 文档,即仅使用注释?
采纳答案by skaffman
Good question. As far as I know, the requiredattribute is generated by XJC when it finds a non-optional schema type, and I think it's also used by the schema generator. At runtime, though, it's not used for anything, serving no other purpose than a documentary annotation.
好问题。据我所知,该required属性是由 XJC 在发现非可选模式类型时生成的,我认为它也被模式生成器使用。但是,在运行时,它不用于任何用途,除了文档注释之外别无其他用途。
One thing you could consider is the JAXB runtime's callback options. In this case, you could just define a afterUnmarshal()method on MyClasswhich programmatically validates the state of the object, throwing an exception if it doesn't like it. See the above link for other options, including registering separate validator classes.
您可以考虑的一件事是 JAXB 运行时的回调选项。在这种情况下,您可以定义一个afterUnmarshal()方法,在MyClass该方法上以编程方式验证对象的状态,如果不喜欢则抛出异常。有关其他选项,请参阅上面的链接,包括注册单独的验证器类。
Having said that, validation against a schema really is the best way. If you don't have one, you should considering writing one. The schemagentool can generate a schema from your object model, which you can then modify to add whatever constraints you like. Hopefully, schemagenwill generate mandatory schema elements from your required=trueclass fields.
话虽如此,针对模式的验证确实是最好的方法。如果你没有,你应该考虑写一个。该schemagen工具可以生成你的对象模型,然后你就可以修改添加你喜欢的任何约束的模式。希望schemagen能从您的required=true类字段中生成必需的架构元素。
回答by David J. Liszewski
Great question, especially considering popularity of object-first, schema-never development. I too would like to validate objects by leveraging the existing annotations prior to marshaling.
很好的问题,特别是考虑到对象优先,模式从不开发的流行。我也想通过在编组之前利用现有的注释来验证对象。
Whilst either we wait for JAXB-430, or become accepted contributors to Java, what follows is an extremely limited home-grown attempt regarding only XmlElement(required=true}. Note this will not work with non-default security policy because of Field.setAccessible().
虽然我们要么等待JAXB-430,要么成为 Java 的公认贡献者,但接下来是非常有限的本土尝试,仅针对XmlElement(required=true}. 请注意,这不适用于非默认安全策略,因为Field.setAccessible().
Use Case Test
用例测试
import javax.xml.bind.annotation.XmlElement;
import JaxbValidator.ValidationException;
import org.testng.annotations.Test;
public class JaxbValidatorTest {
static class Llama {
@XmlElement(required = false)
private final String no;
@XmlElement(required = true)
private final String yes;
public Llama(String no, String yes) {
super();
this.no = no;
this.yes = yes;
}
}
@Test
public void validateRequired() {
try {
Llama o = new Llama("a", "b");
// THE MAIN EVENT - see if 'required' is honored
JaxbValidator.validateRequired(o, Llama.class);
} catch (ValidationException e) {
assert false : "Should not have thrown validation exception.";
}
try {
Llama o = new Llama(null, null);
// Again - see if 'required' is honored
JaxbValidator.validateRequired(o, Llama.class);
assert false : "Should have thrown validation exception for 'yes'";
} catch (ValidationException e) {
assert e.getMessage() != null: "Expected validation message, got null." ;
}
}
}
Implementation
执行
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.xml.bind.annotation.XmlElement;
import org.apache.log4j.Logger;
/**
* oh so minimal consideration of JAXB annotation
*/
public class JaxbValidator {
private static final Logger LOG = Logger.getLogger(JaxbValidator.class);
public static class ValidationException extends Exception {
public ValidationException(String message, Throwable cause) {
super(message, cause);
}
public ValidationException(String message) {
super(message);
}
}
/**
* Enforce 'required' attibute.
*
* Requires either no security manager is used or the default security manager is employed.
* @see {@link Field#setAccessible(boolean)}.
*/
public static <T> void validateRequired(T target, Class<T> targetClass)
throws ValidationException {
StringBuilder errors = new StringBuilder();
Field[] fields = targetClass.getDeclaredFields();
for (Field field : fields) {
XmlElement annotation = field.getAnnotation(XmlElement.class);
if (annotation != null && annotation.required()) {
try {
field.setAccessible(true);
if (field.get(target) == null) {
if (errors.length() != 0) {
errors.append(" ");
}
String message = String.format("%s: required field '%s' is null.",
targetClass.getSimpleName(),
field.getName());
LOG.error(message);
errors.append(message);
}
} catch (IllegalArgumentException e) {
LOG.error(field.getName(), e);
} catch (IllegalAccessException e) {
LOG.error(field.getName(), e);
}
}
}
if (errors.length() != 0) {
throw new ValidationException(errors.toString());
}
}
And yes ... it doesn't do deep inspection. I wasn't sure if JAXB handles cyclic graphs, so I didn't attempt recursion without knowing if that had to be dealt with. I shall save that for a dear reader or next edit.
是的......它没有进行深入检查。我不确定 JAXB 是否处理循环图,所以我没有在不知道是否必须处理的情况下尝试递归。我会把它留给亲爱的读者或下次编辑。

