blob: e8e8e8373d10e58518d00f6cd8603dec0f22352c [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.validation.rebind;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.AbstractSourceCreator;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.gwt.validation.client.GwtValidation;
import com.google.gwt.validation.client.impl.AbstractGwtValidator;
import com.google.gwt.validation.client.impl.GwtBeanDescriptor;
import com.google.gwt.validation.client.impl.GwtSpecificValidator;
import com.google.gwt.validation.client.impl.GwtValidationContext;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.metadata.BeanDescriptor;
/**
* Class that creates the validator for the given input class.
*/
public class ValidatorCreator extends AbstractCreator {
// stash the map in a ThreadLocal, since each GWT module lives in its own
// thread in DevMode
private static final ThreadLocal<Map<JClassType, BeanHelper>> threadLocalHelperMap = new ThreadLocal<Map<JClassType, BeanHelper>>() {
@Override
protected synchronized Map<JClassType, BeanHelper> initialValue() {
return new HashMap<JClassType, BeanHelper>();
}
};
public static BeanHelper getBeanHelper(JClassType beanType) {
return getBeanHelpers().get(beanType);
}
public static Map<JClassType, BeanHelper> getBeanHelpers() {
return Collections.unmodifiableMap(threadLocalHelperMap.get());
}
private final Map<JClassType, BeanHelper> beansToValidate = new HashMap<JClassType, BeanHelper>();
private final GwtValidation gwtValidation;
private final Validator serverSideValidor = Validation.buildDefaultValidatorFactory().getValidator();
public ValidatorCreator(JClassType validatorType, //
GwtValidation gwtValidation, //
TreeLogger logger, //
GeneratorContext context) {
super(context, logger, validatorType);
this.gwtValidation = gwtValidation;
TypeOracle oracle = context.getTypeOracle();
for (Class<?> clazz : gwtValidation.value()) {
JClassType jClass = oracle.findType(clazz.getCanonicalName());
BeanHelper helper = new BeanHelper(jClass,
serverSideValidor.getConstraintsForClass(clazz));
beansToValidate.put(jClass, helper);
}
threadLocalHelperMap.get().putAll(beansToValidate);
}
@Override
protected void compose(ClassSourceFileComposerFactory composerFactory) {
addImports(composerFactory,
GWT.class,
GwtBeanDescriptor.class,
GwtSpecificValidator.class,
GwtValidationContext.class,
Set.class,
ConstraintViolation.class,
BeanDescriptor.class);
composerFactory.setSuperclass(AbstractGwtValidator.class.getCanonicalName());
composerFactory.addImplementedInterface(this.validatorType.getQualifiedSourceName());
}
@Override
protected void writeClassBody(SourceWriter sourceWriter) {
writeTypeSupport(sourceWriter);
sourceWriter.println();
writeConstructor(sourceWriter);
sourceWriter.println();
writeValidate(sourceWriter);
sourceWriter.println();
writeValidateProperty(sourceWriter);
sourceWriter.println();
writeValidateValue(sourceWriter);
sourceWriter.println();
writeGetConstraintsForClass(sourceWriter);
}
private String getSimpleName() {
return validatorType.getSimpleSourceName() + "Impl";
}
private void writeConstructor(SourceWriter sw) {
// public MyValidator() {
sw.println("public " + getSimpleName() + "() {");
sw.indent();
// super( <<groups>>);
sw.print("super(");
boolean first = true;
for (Class<?> group : gwtValidation.groups()) {
if (!first) {
sw.print(", ");
} else {
first = false;
}
sw.print(group.getCanonicalName() + ".class");
}
sw.println(");");
sw.outdent();
sw.println("}");
}
private void writeContext(SourceWriter sw, BeanHelper bean, String objectName) {
// GwtValidationContext<T> context =
// new GwtValidationContext<T>(object,myBeanValidator.getConstraints());
sw.print(GwtValidationContext.class.getSimpleName());
sw.print("<T> context =");
sw.print(" new " + GwtValidationContext.class.getSimpleName());
sw.print("<T>(" + objectName + ", ");
sw.print(bean.getValidatorInstanceName());
sw.print(".getConstraints()");
sw.println(");");
}
private void writeGetConstraintsForClass(SourceWriter sourceWriter) {
sourceWriter.println("public BeanDescriptor getConstraintsForClass(Class<?> clazz) {");
sourceWriter.indent();
sourceWriter.println("return null;");
sourceWriter.outdent();
sourceWriter.println("}");
}
private void writeIfEqualsBeanType(SourceWriter sourceWriter, BeanHelper bean) {
sourceWriter.println("if (object.getClass().equals("
+ bean.getTypeCanonicalName() + ".class)) {");
}
/**
* Write an Empty Interface implementing {@link GwtSpecificValidator} with
* Generic parameter of the bean type.
*
* @param bean
*/
private void writeInterface(BeanHelper bean) {
PrintWriter pw = context.tryCreate(logger, bean.getPackage(),
bean.getValidatorName());
if (pw != null) {
TreeLogger interfaceLogger = AbstractSourceCreator.branch(
logger,
"Creating the interface for "
+ bean.getFullyQualifiedValidatorName());
ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(
bean.getPackage(), bean.getValidatorName());
factory.addImplementedInterface(GwtSpecificValidator.class.getCanonicalName()
+ " <" + bean.getTypeCanonicalName() + ">");
factory.makeInterface();
SourceWriter sw2 = factory.createSourceWriter(context, pw);
sw2.commit(interfaceLogger);
pw.close();
}
}
private void writeThrowIllegalArgumnet(SourceWriter sourceWriter) {
sourceWriter.print("throw new IllegalArgumentException(\""
+ this.validatorType.getName() + " can only validate ");
sourceWriter.print(beansToValidate.toString());
sourceWriter.println("\");");
}
private void writeTypeSupport(SourceWriter sw) {
for (BeanHelper bean : beansToValidate.values()) {
writeInterface(bean);
// private final MyBeanValidator myBeanValidator =
sw.print("private final " + bean.getFullyQualifiedValidatorName() + " ");
sw.print(bean.getValidatorInstanceName());
sw.println(" = ");
sw.indent();
sw.indent();
// GWT.create(MyBeanValidator
sw.println("GWT.create(" + bean.getFullyQualifiedValidatorName()
+ ".class);");
sw.outdent();
sw.outdent();
}
}
private void writeValidate(SourceWriter sw) {
// public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>...
// groups) {
sw.println("public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {");
sw.indent();
sw.println("checkNotNull(object, \"object\");");
sw.println("checkNotNull(groups, \"groups\");");
sw.println("checkGroups(groups);");
for (BeanHelper bean : beansToValidate.values()) {
writeValidate(sw, bean);
}
writeThrowIllegalArgumnet(sw);
sw.outdent();
sw.println("}");
}
private void writeValidate(SourceWriter sw, BeanHelper bean) {
writeIfEqualsBeanType(sw, bean);
sw.indent();
writeContext(sw, bean, "object");
// return personValidator.validate(context, (<<MyBean>>) object, groups);
sw.print("return ");
sw.print(bean.getValidatorInstanceName() + ".validate(");
sw.print("context, ");
sw.print("(" + bean.getTypeCanonicalName() + ") object, ");
sw.println("groups);");
sw.outdent();
sw.println("}");
}
private void writeValidateProperty(SourceWriter sw) {
sw.println("public <T> Set<ConstraintViolation<T>> validateProperty(T object,String propertyName, Class<?>... groups) {");
sw.indent();
sw.println("checkNotNull(object, \"object\");");
sw.println("checkNotNull(propertyName, \"propertyName\");");
sw.println("checkNotNull(groups, \"groups\");");
sw.println("checkGroups(groups);");
for (BeanHelper bean : beansToValidate.values()) {
writeValidateProperty(sw, bean);
}
writeThrowIllegalArgumnet(sw);
sw.outdent();
sw.println("}");
}
private void writeValidateProperty(SourceWriter sw, BeanHelper bean) {
writeIfEqualsBeanType(sw, bean);
sw.indent();
writeContext(sw, bean, "object");
sw.print("return " + bean.getValidatorInstanceName()
+ ".validateProperty(context, (" + bean.getTypeCanonicalName()
+ ") object, propertyName, ");
sw.println("groups);");
sw.outdent(); // if
sw.println("}");
}
private void writeValidateValue(SourceWriter sw) {
sw.println("public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {");
sw.indent();
sw.println("checkNotNull(beanType, \"beanType\");");
sw.println("checkNotNull(propertyName, \"propertyName\");");
sw.println("checkNotNull(groups, \"groups\");");
sw.println("checkGroups(groups);");
for (BeanHelper bean : beansToValidate.values()) {
writeValidateValue(sw, bean);
}
writeThrowIllegalArgumnet(sw);
sw.outdent();
sw.println("}");
}
private void writeValidateValue(SourceWriter sw, BeanHelper bean) {
sw.println("if (beanType.getClass().equals(" + bean.getTypeCanonicalName()
+ ".class)) {");
sw.indent();
writeContext(sw, bean, "null");
sw.println("return " + bean.getValidatorInstanceName()
+ ".validateValue(context, (Class<" + bean.getTypeCanonicalName()
+ ">)beanType, propertyName, value, groups);");
sw.outdent(); // if
sw.println("}");
}
}