- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在使用 jaxb 从配置中构建对象。到目前为止,我编写了用于验证的自定义函数,但我想进入注释。
例如:
@XmlElement
public void setNumber(Integer i){
if (i<10 || i>20) throw new IllegalArgumentException(...);
this.number=i;
}
上述方法的异常是描述性的,并为我提供了错误在 xml 中的位置。
我想进入这个:
@XmlElement
@Min(10)
@Max(20)
public void setNumber(Integer i){
this.number=i;
}
我可以通过读取 afterMarshal 中的注释并根据属性注释运行验证函数来验证这一点,但随后我丢失了发生错误的实际位置(在 xml 中)。
你有没有什么,我应该使用不同的方法/框架来解决这个问题吗?
编辑:澄清一下,我必须使用注释方法,因为我需要我正在编写的配置编辑器的属性约束元数据
最佳答案
这是我自己用来解决这个问题的 XJC 插件(在我的例子中,我需要注释来独立于 XML 模式进行验证,因为我也有 JMS 端点):
它的作用:
-它为不在xs默认模式中的对象生成@valid注解(所以注解是级联的)
-它为具有 MinOccur 值 >= 1 的对象或需要使用的属性生成 @NotNull 注释
-它为具有 minOccurs > 1 的列表生成@Size
-如果有 maxLength 或 minLength 限制,它生成@Size
-@DecimalMax 用于 maxInclusive 限制
-@DecimalMin 用于 minInclusive 限制
-@Digits 如果有 totalDigits 或 fractionDigits 限制。
-@Pattern 如果有Pattern限制
请注意,minExclusive 和 maxExclusive 限制被排除在外。
要使用它,您必须将类文件与内容为“com.sun.tools.xjc.addon.jaxb.JaxbValidationsPlugins”的 META-INF/services/com.sun.tools.xjc.Plugin 文件一起打包(即类的完全限定名称)并使用 -XValidate 开关调用 XJC。
实现起来并不难,但我希望它对某些人有用。源代码作为 TXT 文件附加。享受吧!
package com.sun.tools.xjc.addon.jaxb;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.xml.sax.ErrorHandler;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JFieldVar;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.Plugin;
import com.sun.tools.xjc.model.CAttributePropertyInfo;
import com.sun.tools.xjc.model.CElementPropertyInfo;
import com.sun.tools.xjc.model.CPropertyInfo;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.FieldOutline;
import com.sun.tools.xjc.outline.Outline;
import com.sun.xml.xsom.XSComponent;
import com.sun.xml.xsom.XSSimpleType;
import com.sun.xml.xsom.impl.AttributeUseImpl;
import com.sun.xml.xsom.impl.ElementDecl;
import com.sun.xml.xsom.impl.ParticleImpl;
public class JaxbValidationsPlugins extends Plugin {
public String getOptionName() {
return "Xvalidate";
}
public List<String> getCustomizationURIs() {
return Collections.singletonList(namespace);
}
private String namespace = "http://jaxb.dev.java.net/plugin/code-injector";
public boolean isCustomizationTagName(String nsUri, String localName) {
return nsUri.equals(namespace) && localName.equals("code");
}
public String getUsage() {
return " -Xvalidate : inject Bean validation annotations (JSR 303)";
}
public boolean run(Outline model, Options opt, ErrorHandler errorHandler) {
try {
for (ClassOutline co : model.getClasses()) {
for (CPropertyInfo property : co.target.getProperties()) {
if (property instanceof CElementPropertyInfo) {
recorrePropiedad((CElementPropertyInfo) property, co, model);
} else if (property instanceof CAttributePropertyInfo) {
recorrePropiedad((CAttributePropertyInfo) property, co, model);
}
}
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
static int i = 0;
/**
* XS:Element
*
* @param property
* @param clase
* @param model
*/
public void recorrePropiedad(CElementPropertyInfo property, ClassOutline clase, Outline model) {
FieldOutline field = model.getField(property);
XSComponent definicion = property.getSchemaComponent();
ParticleImpl particle = (ParticleImpl) definicion;
int maxOccurs = ((BigInteger) getField("maxOccurs", particle)).intValue();
int minOccurs = ((BigInteger) getField("minOccurs", particle)).intValue();
JFieldVar var = (JFieldVar) clase.implClass.fields().get(getField("privateName", property));
if (minOccurs < 0 || minOccurs >= 1) {
if (!hasAnnotation(var, NotNull.class)) {
System.out.println("@NotNull: " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(NotNull.class);
}
}
if(maxOccurs>1){
if (!hasAnnotation(var, Size.class)) {
System.out.println("@Size ("+minOccurs+","+maxOccurs+") " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(Size.class).param("min", minOccurs).param("max", maxOccurs);
}
}
ElementDecl declaracion = (ElementDecl) getField("term", particle);
if (declaracion.getType().getTargetNamespace().startsWith("http://hotelbeds.com")) {
if (!hasAnnotation(var, Valid.class)) {
System.out.println("@Valid: " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(Valid.class);
}
}
if (declaracion.getType() instanceof XSSimpleType) {
procesaType((XSSimpleType) declaracion.getType(), var, property.getName(), clase.implClass.name());
} else if (declaracion.getType().getBaseType() instanceof XSSimpleType) {
procesaType((XSSimpleType) declaracion.getType().getBaseType(), var, property.getName(), clase.implClass.name());
}
// if(declaracion.getType() instanceof
// if(declaracion.getType().ge)
// procesaType(declaracion.getType().getBaseType(),var);
}
/**
* XS:Attribute
*
* @param property
* @param clase
* @param model
*/
public void recorrePropiedad(CAttributePropertyInfo property, ClassOutline clase, Outline model) {
FieldOutline field = model.getField(property);
System.out.println("Tratando attributo " + property.getName() + " de la clase " + clase.implClass.name());
XSComponent definicion = property.getSchemaComponent();
AttributeUseImpl particle = (AttributeUseImpl) definicion;
JFieldVar var = (JFieldVar) clase.implClass.fields().get(getField("privateName", property));
if (particle.isRequired()) {
if (!hasAnnotation(var, NotNull.class)) {
System.out.println("@NotNull: " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(NotNull.class);
}
}
if (particle.getDecl().getType().getTargetNamespace().startsWith("http://hotelbeds.com")) {
if (!hasAnnotation(var, Valid.class)) {
System.out.println("@Valid: " + property.getName() + " de la clase " + clase.implClass.name());
var.annotate(Valid.class);
}
}
procesaType(particle.getDecl().getType(), var, property.getName(), clase.implClass.name());
}
public void procesaType(XSSimpleType tipo, JFieldVar field, String campo, String clase) {
if (tipo.getFacet("maxLength") != null || tipo.getFacet("minLength") != null) {
Integer maxLength = tipo.getFacet("maxLength") == null ? null : parseInt(tipo.getFacet("maxLength").getValue().value);
Integer minLength = tipo.getFacet("minLength") == null ? null : parseInt(tipo.getFacet("minLength").getValue().value);
if (!hasAnnotation(field, Size.class)) {
System.out.println("@Size(" + minLength + "," + maxLength + "): " + campo + " de la clase " + clase);
field.annotate(Size.class).param("min", minLength).param("max", maxLength);
}
}
/*
* <bindings multiple="true" node=
* "//xs:complexType/.//xs:element[contains(@type,'IntPercentRestriction')]"
* > <annox:annotate> <annox:annotate
* annox:class="javax.validation.constraints.Digits" integer="3"
* fraction="2" /> <annox:annotate
* annox:class="javax.validation.constraints.Min" value="-100" />
* value="100" /> </annox:annotate> </bindings>
*//*
* <xs:restriction base="xs:decimal"> <xs:fractionDigits value="2"/>
* <xs:maxInclusive value="100.00"/> <xs:minInclusive
* value="-100.00"/> <xs:totalDigits value="5"/> </xs:restriction>
*/
if (tipo.getFacet("maxInclusive") != null && tipo.getFacet("maxInclusive").getValue().value != null && !hasAnnotation(field,DecimalMax.class)){
System.out.println("@DecimalMax(" + tipo.getFacet("maxInclusive").getValue().value + "): " + campo + " de la clase " + clase);
field.annotate(DecimalMax.class).param("value", tipo.getFacet("maxInclusive").getValue().value);
}
if (tipo.getFacet("minInclusive") != null && tipo.getFacet("minInclusive").getValue().value != null && !hasAnnotation(field,DecimalMin.class)){
System.out.println("@DecimalMin(" + tipo.getFacet("minInclusive").getValue().value + "): " + campo + " de la clase " + clase);
field.annotate(DecimalMin.class).param("value", tipo.getFacet("minInclusive").getValue().value);
}
if (tipo.getFacet("totalDigits") != null) {
Integer totalDigits = tipo.getFacet("totalDigits") == null ? null : parseInt(tipo.getFacet("totalDigits").getValue().value);
int fractionDigits = tipo.getFacet("fractionDigits") == null ? 0 : parseInt(tipo.getFacet("fractionDigits").getValue().value);
if (!hasAnnotation(field, Digits.class)) {
System.out.println("@Digits(" + totalDigits + "," + fractionDigits + "): " + campo + " de la clase " + clase);
JAnnotationUse annox = field.annotate(Digits.class).param("integer", (totalDigits - fractionDigits));
if (tipo.getFacet("fractionDigits") != null) {
annox.param("fraction", fractionDigits);
}
}
}
/**
* <annox:annotate annox:class="javax.validation.constraints.Pattern"
message="Name can only contain capital letters, numbers and the simbols '-', '_', '/', ' '"
regexp="^[A-Z0-9_\s//-]*" />
*/
if(tipo.getFacet("pattern")!=null){
System.out.println("@Pattern(" +tipo.getFacet("pattern").getValue().value+ "): " + campo + " de la clase " + clase);
if (!hasAnnotation(field, Pattern.class)) {
field.annotate(Pattern.class).param("regexp", tipo.getFacet("pattern").getValue().value);
}
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public boolean hasAnnotation(JFieldVar var, Class anotacion) {
List<JAnnotationUse> lista = (List<JAnnotationUse>) getField("annotations", var);
if (lista != null) {
for (JAnnotationUse uso : lista) {
if (((Class) getField("clazz._class", uso)).getCanonicalName().equals(anotacion.getCanonicalName())) {
return true;
}
}
}
return false;
}
private Integer parseInt(String valor) {
try {
Integer i = Integer.parseInt(valor);
if (i < 2147483647 && i > -2147483648) {
return i;
}
} catch (Exception e) {
try{
return (int)Math.round(Double.parseDouble(valor));
}catch(Exception ex){
;
}
}
return null;
}
/*
private Long parseLong(String valor) {
try {
Long i = Long.parseLong(valor);
if (i < 2147483647 && i > -2147483648) {
return i;
}
} catch (Exception e) {
return Math.round(Double.parseDouble(valor));
}
return null;
}
*/
private Object getField(String path, Object oo) {
try {
if (path.contains(".")) {
String field = path.substring(0, path.indexOf("."));
Field campo = oo.getClass().getDeclaredField(field);
campo.setAccessible(true);
Object result = campo.get(oo);
return getField(path.substring(path.indexOf(".") + 1), result);
} else {
Field campo = getSimpleField(path, oo.getClass());
campo.setAccessible(true);
return campo.get(oo);
}
} catch (Exception e) {
System.out.println("Field " + path + " not found on " + oo.getClass().getName());
}
return null;
}
private static Field getSimpleField(String fieldName, Class<?> clazz) {
Class<?> tmpClass = clazz;
try {
do {
for (Field field : tmpClass.getDeclaredFields()) {
String candidateName = field.getName();
if (!candidateName.equals(fieldName)) {
continue;
}
field.setAccessible(true);
return field;
}
tmpClass = tmpClass.getSuperclass();
} while (clazz != null);
} catch (Exception e) {
System.out.println("Field '" + fieldName + "' not found on class " + clazz);
}
return null;
}
}
关于java - jaxb 和 jsr303,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5063713/
我正在从类文件中反编译java代码。有一个java语句为: localObject2 = this.current_result_set;jsr 56;jsr 63;return (ResultSet
JSR-223 之间的主要区别是什么?和 JSR-241 ? 如果我理解正确的话: JSR -223:介绍了 Java 脚本语言引擎,仅此而已!您可以自由使用任何您想要的脚本语言,例如:Groovy、
Eclipse 的 null 分析现在支持 JSR-308,即您现在可以将 @Nonull 等放在泛型类型参数上。 但是,广泛使用的 com.google.code.findbugs:jsr305:3
我通过外部服务收到一条 XML 消息,我可以使用 MOXy 作为我的 JAXB 提供程序将其解码为 POJO。我目前能够使用 JPA (Hibernate) 将对象保存到数据库中,并且当遇到无效数据时
在 Java 门户上,您可以拥有包含其他应用程序提供的数据的 portlet。我们想用 Django 应用程序替换我们现有的 Java 门户,这意味着复制 Java 门户显示 portlet 的能力。
我刚开始使用 Java Bean 验证 (JSR-303/JSR-349/Hibernate Validator),并且了解一般概念。但是,我不确定如何验证组合类型的内容与类型本身。 例如: @Not
我是 BlackBerry OS 开发的新手,我的代码试图在传递 Criteria 参数后使用 LocationProvider 获取城市名称。我是根据这个 link 关注的我从 RIM 本身尝试了“
我有一个关于 JSR 交叉文件验证的问题。我有一个基于休息的获取和发布服务。所以我有类似的东西 @GET ItemOfferId getItem(String) 另外一个是 @Post boolean
在提到 Java、JSP 和 JSF 的各个方面时,我经常看到经常使用“JSR-XXX”标题。用于 CDI 的 JSR-299?或用于某些注释的 JSR-303。 通过“JSR”名称来学习这些概念是否
最近我选择了一个非常有用的网络服务框架,Jersey (JAX-RS 又名 jsr-311;及其摇滚启动实现),以及一个漂亮的验证库 Hibernate Validator (“Bean 验证 API
在我的场景中,我尝试创建注释来验证一个字段是否已填充(如果另一个字段具有某种值)。 界面如下所示: @Target({ElementType.FIELD, ElementType.METHOD}) @
谁能解释一下这两者之间的区别:评估规范与构建实现规范对于任何可用的 JSR 流程,例如,JSR 299 . 有时这是有值(value)的信息来源,但对于作为开发人员的我来说,我应该下载和阅读哪一个?令
我正在查看一些 Java 代码,我注意到以下内容: if (!foo(bar, baz, qux)) { i = 0; jsr 433; } javac 对此感到窒息,说这不是一个语句,并且在
我使用 Hibernate Validator 作为 JSR-303 实现。 假设我有: class Form { @Valid private Owner mainOwner;
第 10.6 章中的规范说: Implementation-specific loader The batch runtime implementation must provide an imple
我有一个具有 JSR 168 规范的 portlet,它曾经在 UPortal(一些基于旧门户的 java 框架)内运行。但是,我需要将此 portlet 从门户中删除,并将其作为独立的应用程序。现在
我正在使用 JSR-330 注释编写一些代码,并且我想针对(或使用)各种实现来测试它。 目前我已经完成了 Dagger Dagger 2 hk2 Spring 还有其他实现吗? 请注意,我不是在谈论
我的主要课程是 public class UserAddressesForm { @NotEmpty private String firstName; @NotEmpty
亲爱的 Spring 社区, 我要实现的是以下内容: 我希望每个 Controller 有一个自定义验证器 (via @InitBinder ) 我希望 Spring 调用 validator.val
阅读有关 osgi 的 wiki 页面 https://en.wikipedia.org/wiki/OSGi我看到没有关于OSGi的JSR只有OSGi相关的JSR。这是否意味着 OSGi 规范已超出
我是一名优秀的程序员,十分优秀!