使用注释的 JAXB 验证
2022-09-01 13:21:29
如果我有一个简单的类,例如:-
@XmlRootElement
public class MyClass
{
@XmlAttribute(required=true)
private String myattribute
}
是否可以在没有xml架构的情况下验证相应的xml文档,即仅使用注释?
如果我有一个简单的类,例如:-
@XmlRootElement
public class MyClass
{
@XmlAttribute(required=true)
private String myattribute
}
是否可以在没有xml架构的情况下验证相应的xml文档,即仅使用注释?
问得好。据我所知,该属性是由XJC在找到非可选模式类型时生成的,我认为它也被模式生成器使用。然而,在运行时,它不用于任何事情,除了纪录片注释之外没有其他目的。required
您可以考虑的一件事是 JAXB 运行时的回调选项。在这种情况下,您可以只定义一个方法,该方法以编程方式验证对象的状态,如果它不喜欢它,则引发异常。有关其他选项,请参阅上面的链接,包括注册单独的验证程序类。afterUnmarshal()
MyClass
话虽如此,针对架构的验证确实是最好的方法。如果你没有,你应该考虑写一个。schemagen 工具可以从对象模型生成架构,然后您可以对其进行修改以添加所需的任何约束。希望,将从类字段中生成必需的架构元素。schemagen
required=true
这是一个很好的问题,特别是考虑到对象优先,模式从不开发的普及。我也想在封送处理之前通过利用现有的注释来验证对象。
虽然我们要么等待JAXB-430,要么成为Java的公认贡献者,但接下来是一个非常有限的本土尝试,仅涉及。请注意,由于 ,这将不适用于非默认安全策略。XmlElement(required=true}
Field.setAccessible()
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." ;
}
}
}
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());
}
}
是的...它不做深度检查。我不确定 JAXB 是否处理循环图,所以我在不知道是否必须处理的情况下没有尝试递归。我将保存它给亲爱的读者或下一次编辑。