properties = beanHelper.getBeanDescriptor().getConstrainedProperties();
for (PropertyDescriptor p : properties) {
writeValidatePropertyCall(sw, p, false);
}
// all class level constraints
int count = 0;
Class> clazz = beanHelper.getClazz();
for (ConstraintDescriptor> constraint : beanHelper.getBeanDescriptor().getConstraintDescriptors()) {
if (hasMatchingAnnotation(constraint)) {
if (!constraint.getConstraintValidatorClasses().isEmpty()) {
Class extends ConstraintValidator extends Annotation, ?>> validatorClass = getValidatorForType(
constraint, clazz);
// validate(context, violations, null, object,
sw.print("validate(context, violations, null, object, ");
// new MyValidtor();
sw.print("new ");
sw.print(validatorClass.getCanonicalName());
sw.print("(), "); // TODO(nchalko) use ConstraintValidatorFactory
// this.aConstraintDescriptor, groups);;
sw.print(constraintDescriptorVar("this", count));
sw.println(", groups);");
} else if (constraint.getComposingConstraints().isEmpty()) {
// TODO(nchalko) What does the spec say to do here.
logger.log(TreeLogger.WARN, "No ConstraintValidator of " + constraint
+ " for type " + clazz);
}
// TODO(nchalko) handle constraint.isReportAsSingleViolation() and
// hasComposingConstraints
}
count++;
}
// validate super classes and super interfaces
writeValidateInheritance(sw, clazz, Stage.OBJECT, null);
// return violations;
sw.println("return violations;");
writeCatchUnexpectedException(sw,
"\"Error validating " + beanHelper.getTypeCanonicalName() + "\"");
// }
sw.outdent();
sw.println("}");
}
private void writeValidateConstraint(SourceWriter sw, PropertyDescriptor p,
Class> elementClass, ConstraintDescriptor> constraint,
String constraintDescriptorVar) throws UnableToCompleteException {
writeValidateConstraint(sw, p, elementClass, constraint,
constraintDescriptorVar, DEFAULT_VIOLATION_VAR);
}
/**
* Writes the call to actually validate a constraint, including its composite
* constraints.
*
* If the constraint is annotated as
* {@link javax.validation.ReportAsSingleViolation ReportAsSingleViolation},
* then is called recursively and the {@code violationsVar} is changed to
* match the the {@code constraintDescriptorVar}.
*
* @param sw the Source Writer
* @param p the property
* @param elementClass The class of the Element
* @param constraint the constraint to validate.
* @param constraintDescriptorVar the name of the constraintDescriptor
* variable.
* @param violationsVar the name of the variable to hold violations
* @throws UnableToCompleteException
*/
private void writeValidateConstraint(SourceWriter sw, PropertyDescriptor p,
Class> elementClass, ConstraintDescriptor> constraint,
String constraintDescriptorVar, String violationsVar)
throws UnableToCompleteException {
boolean isComposite = !constraint.getComposingConstraints().isEmpty();
boolean firstReportAsSingleViolation =
constraint.isReportAsSingleViolation()
&& violationsVar.equals(DEFAULT_VIOLATION_VAR) && isComposite;
boolean reportAsSingleViolation = firstReportAsSingleViolation
|| !violationsVar.equals(DEFAULT_VIOLATION_VAR);
boolean hasValidator = !constraint.getConstraintValidatorClasses()
.isEmpty();
String compositeViolationsVar = constraintDescriptorVar + "_violations";
// Only do this the first time in a constraint composition.
if (firstReportAsSingleViolation) {
// Report myConstraint as Single Violation
sw.print("// Report ");
sw.print(constraint.getAnnotation().annotationType().getCanonicalName());
sw.println(" as Single Violation");
writeNewViolations(sw, compositeViolationsVar);
}
if (hasValidator) {
Class extends ConstraintValidator extends Annotation, ?>> validatorClass;
try {
validatorClass = getValidatorForType(constraint, elementClass);
} catch (UnexpectedTypeException e) {
throw error(logger, e);
}
if (firstReportAsSingleViolation) {
// if (!
sw.println("if (!");
sw.indent();
sw.indent();
}
// validate(myContext, violations object, value, new MyValidator(),
// constraintDescriptor, groups));
sw.print("validate(myContext, ");
sw.print(violationsVar);
sw.print(", object, value, ");
sw.print("new "); // TODO(nchalko) use ConstraintValidatorFactory
sw.print(validatorClass.getCanonicalName());
sw.print("(), ");
sw.print(constraintDescriptorVar);
sw.print(", groups)");
if (firstReportAsSingleViolation) {
// ) {
sw.println(") {");
sw.outdent();
} else if (!reportAsSingleViolation) {
// ;
sw.println(";");
} else if (isComposite) {
// ||
sw.println(" ||");
}
} else if (!isComposite) {
// TODO(nchalko) What does the spec say to do here.
logger.log(TreeLogger.WARN, "No ConstraintValidator of " + constraint + " for "
+ p.getPropertyName() + " of type " + elementClass);
}
if (firstReportAsSingleViolation) {
// if (
sw.print("if (");
sw.indent();
sw.indent();
}
int count = 0;
for (ConstraintDescriptor> compositeConstraint : constraint
.getComposingConstraints()) {
String compositeVar = constraintDescriptorVar + "_" + count++;
writeValidateConstraint(sw, p, elementClass, compositeConstraint,
compositeVar, firstReportAsSingleViolation ? compositeViolationsVar
: violationsVar);
if (!reportAsSingleViolation) {
// ;
sw.println(";");
} else {
// ||
sw.println(" ||");
}
}
if (isComposite && reportAsSingleViolation) {
// false
sw.print("false");
}
if (firstReportAsSingleViolation) {
// ) {
sw.println(" ) {");
sw.outdent();
// addSingleViolation(myContext, violations, object, value,
// constraintDescriptor);
sw.print("addSingleViolation(myContext, violations, object, value, ");
sw.print(constraintDescriptorVar);
sw.println(");");
// }
sw.outdent();
sw.println("}");
if (hasValidator) {
// }
sw.outdent();
sw.println("}");
}
}
}
private void writeValidateFieldCall(SourceWriter sw, PropertyDescriptor p,
boolean useValue) {
String propertyName = p.getPropertyName();
// validateProperty_<>(context,
sw.print(validateMethodFieldName(p));
sw.print("(context, ");
sw.print("violations, ");
// null, (MyType) value,
// or
// object, object.getLastName(),
if (useValue) {
sw.print("null, ");
sw.print("(");
sw.print(getQualifiedSourceNonPrimitiveType(beanHelper.getElementType(p,
true)));
sw.print(") value");
} else {
sw.print("object, ");
JField field = beanType.getField(propertyName);
if (field.isPublic()) {
sw.print("object.");
sw.print(propertyName);
} else {
fieldsToWrap.add(field);
sw.print(toWrapperName(field) + "(object)");
}
}
sw.print(", ");
// groups));
sw.println("groups);");
}
private void writeValidateGetterCall(SourceWriter sw, PropertyDescriptor p,
boolean useValue) {
// validateProperty_get<>(context, violations,
sw.print(validateMethodGetterName(p));
sw.print("(context, ");
sw.print("violations, ");
// object, object.getMyProp(),
// or
// null, (MyType) value,
if (useValue) {
sw.print("null, ");
sw.print("(");
sw.print(getQualifiedSourceNonPrimitiveType(beanHelper.getElementType(p,
false)));
sw.print(") value");
} else {
sw.print("object, ");
JMethod method = beanType.findMethod(asGetter(p), NO_ARGS);
if (method.isPublic()) {
sw.print("object.");
sw.print(asGetter(p));
sw.print("()");
} else {
gettersToWrap.add(method);
sw.print(toWrapperName(method) + "(object)");
}
}
sw.print(", ");
// groups);
sw.println("groups);");
}
private void writeValidateInheritance(SourceWriter sw, Class> clazz,
Stage stage, PropertyDescriptor property)
throws UnableToCompleteException {
writeValidateInterfaces(sw, clazz, stage, property);
Class> superClass = clazz.getSuperclass();
if (superClass != null) {
writeValidatorCall(sw, superClass, stage, property);
}
}
private void writeValidateInterfaces(SourceWriter sw, Class> clazz,
Stage stage, PropertyDescriptor p) throws UnableToCompleteException {
for (Class> type : clazz.getInterfaces()) {
writeValidatorCall(sw, type, stage, p);
writeValidateInterfaces(sw, type, stage, p);
}
}
private void writeValidateIterable(SourceWriter sw, PropertyDescriptor p) {
// int i = 0;
sw.println("int i = 0;");
// for (Object instance : value) {
sw.println("for(Object instance : value) {");
sw.indent();
// if(instance != null && !context.alreadyValidated(instance)) {
sw.println(" if(instance != null && !context.alreadyValidated(instance)) {");
sw.indent();
// violations.addAll(
sw.println("violations.addAll(");
sw.indent();
sw.indent();
// context.getValidator().validate(
sw.println("context.getValidator().validate(");
sw.indent();
sw.indent();
Class> elementClass = p.getElementClass();
if (elementClass.isArray() || List.class.isAssignableFrom(elementClass)) {
// context.appendIndex("myProperty",i++),
sw.print("context.appendIndex(\"");
sw.print(p.getPropertyName());
sw.println("\",i),");
} else {
// context.appendIterable("myProperty"),
sw.print("context.appendIterable(\"");
sw.print(p.getPropertyName());
sw.println("\"),");
}
// instance, groups));
sw.println("instance, groups));");
sw.outdent();
sw.outdent();
sw.outdent();
sw.outdent();
// }
sw.outdent();
sw.println("}");
// i++;
sw.println("i++;");
// }
sw.outdent();
sw.println("}");
}
private void writeValidateMap(SourceWriter sw, PropertyDescriptor p) {
// for (Entry, Type> entry : value.entrySet()) {
sw.print("for(");
sw.print(Entry.class.getCanonicalName());
sw.println(", ?> entry : value.entrySet()) {");
sw.indent();
// if(entry.getValue() != null &&
// !context.alreadyValidated(entry.getValue())) {
sw.println(" if(entry.getValue() != null && !context.alreadyValidated(entry.getValue())) {");
sw.indent();
// violations.addAll(
sw.println("violations.addAll(");
sw.indent();
sw.indent();
// context.getValidator().validate(
sw.println("context.getValidator().validate(");
sw.indent();
sw.indent();
// context.appendKey("myProperty",entry.getKey()),
sw.print("context.appendKey(\"");
sw.print(p.getPropertyName());
sw.println("\",entry.getKey()),");
// entry.getValue(), groups));
sw.println("entry.getValue(), groups));");
sw.outdent();
sw.outdent();
sw.outdent();
sw.outdent();
// }
sw.outdent();
sw.println("}");
// }
sw.outdent();
sw.println("}");
}
private void writeValidateProperty(SourceWriter sw)
throws UnableToCompleteException {
// public Set> validate(
sw.println("public Set> validateProperty(");
// GwtValidationContext context, BeanType object, String propertyName,
// Class>... groups) throws ValidationException {
sw.indent();
sw.indent();
sw.println("GwtValidationContext context,");
sw.println(beanHelper.getTypeCanonicalName() + " object,");
sw.println("String propertyName,");
sw.println("Class>... groups) throws ValidationException {");
sw.outdent();
// try {
sw.println("try {");
sw.indent();
writeNewViolations(sw);
for (PropertyDescriptor property : beanHelper.getBeanDescriptor().getConstrainedProperties()) {
// if (propertyName.equals(myPropety)) {
sw.print("if (propertyName.equals(\"");
sw.print(property.getPropertyName());
sw.println("\")) {");
sw.indent();
writeValidatePropertyCall(sw, property, false);
// validate all super classes and interfaces
writeValidateInheritance(sw, beanHelper.getClazz(), Stage.PROPERTY,
property);
// }
sw.outdent();
sw.print("} else ");
}
writeIfPropertyNameNotFound(sw);
// return violations;
sw.println("return violations;");
writeCatchUnexpectedException(
sw,
"\"Error validating \" + propertyName + \" of "
+ beanHelper.getTypeCanonicalName() + "\"");
// }
sw.outdent();
sw.println("}");
}
private void writeValidatePropertyCall(SourceWriter sw,
PropertyDescriptor property, boolean useValue) {
if (useValue) {
// boolean valueTypeMatches = false;
sw.println("boolean valueTypeMatches = false;");
}
if (beanHelper.hasGetter(property)) {
if (useValue) {
// if ( value == null || value instanceof propertyType) {
sw.print("if ( value == null || value instanceof ");
sw.print(getQualifiedSourceNonPrimitiveType(beanHelper.getElementType(
property, false)));
sw.println(") {");
sw.indent();
// valueTypeMatches = true;
sw.println("valueTypeMatches = true;");
}
// validate_getMyProperty
writeValidateGetterCall(sw, property, useValue);
if (useValue) {
// }
sw.outdent();
sw.println("}");
}
}
if (beanHelper.hasField(property)) {
if (useValue) {
// if ( value == null || value instanceof propertyType) {
sw.print("if ( value == null || value instanceof ");
sw.print(getQualifiedSourceNonPrimitiveType(beanHelper.getElementType(
property, true)));
sw.println(") {");
sw.indent();
// valueTypeMatches = true;
sw.println("valueTypeMatches = true;");
}
// validate_myProperty
writeValidateFieldCall(sw, property, useValue);
if (useValue) {
// } else
sw.outdent();
sw.println("}");
}
}
if (useValue & (beanHelper.hasGetter(property) || beanHelper.hasField(property))) {
// if(!valueTypeMatches) {
sw.println("if(!valueTypeMatches) {");
sw.indent();
// throw new ValidationException(value.getClass +
// " is not a valid type for " + propertyName);
sw.print("throw new ValidationException");
sw.println("(value.getClass() +\" is not a valid type for \"+ propertyName);");
// }
sw.outdent();
sw.println("}");
}
}
private void writeValidatePropertyMethod(SourceWriter sw,
PropertyDescriptor p, boolean useField) throws UnableToCompleteException {
Class> elementClass = p.getElementClass();
JType elementType = beanHelper.getElementType(p, useField);
// private final void validateProperty_{get}(
sw.print("private final void ");
if (useField) {
sw.print(validateMethodFieldName(p));
} else {
sw.print(validateMethodGetterName(p));
}
sw.println("(");
sw.indent();
sw.indent();
// final GwtValidationContext context,
sw.println("final GwtValidationContext context,");
// final Set> violations,
sw.println("final Set> violations,");
// final BeanType object, value,
sw.println(beanHelper.getTypeCanonicalName() + " object,");
// Class>... groups) {
sw.print("final ");
sw.print(elementType.getParameterizedQualifiedSourceName());
sw.println(" value,");
sw.println("Class>... groups) {");
sw.outdent();
// context = context.append("myProperty");
sw.print("final GwtValidationContext myContext = context.append(\"");
sw.print(p.getPropertyName());
sw.println("\");");
// TODO(nchalko) move this out of here to the Validate method
if (p.isCascaded() && hasValid(p, useField)) {
// if(value != null) {
sw.println("if(value != null) {");
sw.indent();
if (isIterableOrMap(elementClass)) {
if (hasValid(p, useField)) {
JClassType associationType = beanHelper.getAssociationType(p,
useField);
createBeanHelper(associationType);
if (Map.class.isAssignableFrom(elementClass)) {
writeValidateMap(sw, p);
} else {
writeValidateIterable(sw, p);
}
}
} else {
createBeanHelper(elementClass);
// if (!context.alreadyValidated(value)) {
sw.println(" if (!context.alreadyValidated(value)) {");
sw.indent();
// violations.addAll(myContext.getValidator().validate(context, value,
// groups));
sw.print("violations.addAll(");
sw.println("myContext.getValidator().validate(myContext, value, groups));");
// }
sw.outdent();
sw.println("}");
}
// }
sw.outdent();
sw.println("}");
}
// It is possible for an annotation with the exact same values to be set on
// both the field and the getter.
// Keep track of the ones we have used to make sure we don't duplicate.
// It doesn't matter which one we use because they have exactly the same
// values.
Set includedAnnotations = Sets.newHashSet();
int count = 0;
for (ConstraintDescriptor> constraint : p.getConstraintDescriptors()) {
Object annotation = constraint.getAnnotation();
if (!includedAnnotations.contains(annotation)
&& hasMatchingAnnotation(p, useField, constraint)) {
includedAnnotations.add(annotation);
String constraintDescriptorVar = constraintDescriptorVar(
p.getPropertyName(), count);
writeValidateConstraint(sw, p, elementClass, constraint,
constraintDescriptorVar);
}
count++;
}
sw.outdent();
sw.println("}");
}
private void writeValidateValue(SourceWriter sw)
throws UnableToCompleteException {
// public Set> validate(
sw.println("public Set> validateValue(");
// GwtValidationContext context, Class beanType,
// String propertyName, Object value, Class>... groups) {
sw.indent();
sw.indent();
sw.println("GwtValidationContext context,");
sw.println("Class<" + beanHelper.getTypeCanonicalName() + "> beanType,");
sw.println("String propertyName,");
sw.println("Object value,");
sw.println("Class>... groups) {");
sw.outdent();
// try {
sw.println("try {");
sw.indent();
writeNewViolations(sw);
for (PropertyDescriptor property :
beanHelper.getBeanDescriptor().getConstrainedProperties()) {
// if (propertyName.equals(myPropety)) {
sw.print("if (propertyName.equals(\"");
sw.print(property.getPropertyName());
sw.println("\")) {");
sw.indent();
if (!isIterableOrMap(property.getElementClass())) {
writeValidatePropertyCall(sw, property, true);
}
// validate all super classes and interfaces
writeValidateInheritance(sw, beanHelper.getClazz(),
Stage.VALUE, property);
// }
sw.outdent();
sw.print("} else ");
}
writeIfPropertyNameNotFound(sw);
// return violations;
sw.println("return violations;");
writeCatchUnexpectedException(
sw,
"\"Error validating \" + propertyName + \" of "
+ beanHelper.getTypeCanonicalName() + "\"");
sw.outdent();
sw.println("}");
}
private void writeValidatorCall(SourceWriter sw, Class> type, Stage stage,
PropertyDescriptor p) throws UnableToCompleteException {
if (BeanHelper.isClassConstrained(type) && !isIterableOrMap(type)) {
BeanHelper helper = createBeanHelper(type);
beansToValidate.add(helper);
switch (stage) {
case OBJECT:
// voilations.addAll(myValidator.validate(context,object,groups));
sw.print("violations.addAll(");
sw.print(helper.getValidatorInstanceName());
sw.println(".validate(context, object, groups));");
break;
case PROPERTY:
if (isPropertyConstrained(helper, p)) {
// voilations.addAll(myValidator.validateProperty(context,object
// ,propertyName, groups));
sw.print("violations.addAll(");
sw.print(helper.getValidatorInstanceName());
sw.print(".validateProperty(context, object,");
sw.println(" propertyName, groups));");
}
break;
case VALUE:
if (isPropertyConstrained(helper, p)) {
// voilations.addAll(myValidator.validateProperty(context,beanType
// ,propertyName, value, groups));
sw.print("violations.addAll(");
sw.print(helper.getValidatorInstanceName());
sw.print(".validateValue(context, ");
// TODO(nchalko) this seems like an unneeded param
sw.print(helper.getTypeCanonicalName());
sw.println(".class, propertyName, value, groups));");
}
break;
default:
throw new IllegalStateException();
}
}
}
private void writeWrappers(SourceWriter sw) {
sw.println("// Write the wrappers after we know which are needed");
for (JField field : fieldsToWrap) {
writeFieldWrapperMethod(sw, field);
sw.println();
}
for (JMethod method : gettersToWrap) {
writeGetterWrapperMethod(sw, method);
sw.println();
}
}
}