001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.compiler;
020:
021: import org.apache.beehive.netui.compiler.grammar.ValidatablePropertyGrammar;
022: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
023: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationTypeElementDeclaration;
024: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationValue;
025: import org.apache.beehive.netui.compiler.typesystem.declaration.ClassDeclaration;
026: import org.apache.beehive.netui.compiler.typesystem.declaration.MemberDeclaration;
027: import org.apache.beehive.netui.compiler.typesystem.declaration.MethodDeclaration;
028: import org.apache.beehive.netui.compiler.typesystem.declaration.Modifier;
029: import org.apache.beehive.netui.compiler.typesystem.declaration.ParameterDeclaration;
030: import org.apache.beehive.netui.compiler.typesystem.declaration.TypeDeclaration;
031: import org.apache.beehive.netui.compiler.typesystem.env.CoreAnnotationProcessorEnv;
032: import org.apache.beehive.netui.compiler.typesystem.type.DeclaredType;
033: import org.apache.beehive.netui.compiler.typesystem.type.TypeInstance;
034:
035: import java.util.Map;
036:
037: public class FormBeanChecker extends BaseChecker implements
038: JpfLanguageConstants {
039: public FormBeanChecker(CoreAnnotationProcessorEnv env,
040: Diagnostics diags) {
041: super (env, null, diags);
042: }
043:
044: public Map onCheck(ClassDeclaration jclass)
045: throws FatalCompileTimeException {
046: GetterValidatablePropertyGrammar validatablePropertyGrammar = new GetterValidatablePropertyGrammar();
047: boolean hasFormBeanAnnotation = CompilerUtils.getAnnotation(
048: jclass, FORM_BEAN_TAG_NAME, true) != null;
049: boolean isFormBeanClass = hasFormBeanAnnotation;
050:
051: // Look for ValidationField annotations on the methods; if there are some present, then we consider this
052: // a form bean class, even if it's not annotated as such.
053: MethodDeclaration[] methods = CompilerUtils.getClassMethods(
054: jclass, null);
055:
056: for (int i = 0; i < methods.length; i++) {
057: MethodDeclaration method = methods[i];
058: isFormBeanClass |= checkValidationAnnotation(method,
059: VALIDATABLE_PROPERTY_TAG_NAME,
060: validatablePropertyGrammar);
061: // We don't currently support validation rule annotations directly on getter methods.
062: /*
063: hasOne |= checkValidationAnnotation( method, LOCALE_RULES_ATTR, _validationLocaleRulesGrammar );
064: hasOne |= checkValidationAnnotation( method, VALIDATE_REQUIRED_TAG_NAME, _baseValidationRuleGrammar );
065: hasOne |= checkValidationAnnotation( method, VALIDATE_RANGE_TAG_NAME, _validateRangeGrammar );
066: hasOne |= checkValidationAnnotation( method, VALIDATE_MIN_LENGTH_TAG_NAME, _baseValidationRuleGrammar );
067: hasOne |= checkValidationAnnotation( method, VALIDATE_MAX_LENGTH_TAG_NAME, _baseValidationRuleGrammar );
068: hasOne |= checkValidationAnnotation( method, VALIDATE_CREDIT_CARD_TAG_NAME, _baseValidationRuleGrammar );
069: hasOne |= checkValidationAnnotation( method, VALIDATE_EMAIL_TAG_NAME, _baseValidationRuleGrammar );
070: hasOne |= checkValidationAnnotation( method, VALIDATE_MASK_TAG_NAME, _baseValidationRuleGrammar );
071: hasOne |= checkValidationAnnotation( method, VALIDATE_DATE_TAG_NAME, _baseValidationRuleGrammar );
072: hasOne |= checkValidationAnnotation( method, VALIDATE_TYPE_TAG_NAME, _validateTypeGrammar );
073: */
074: }
075:
076: CoreAnnotationProcessorEnv env = getEnv();
077:
078: // Make sure ActionForm subclasses are public static, and that they have default constructors.
079: if (isFormBeanClass
080: || CompilerUtils.isAssignableFrom(
081: STRUTS_FORM_CLASS_NAME, jclass, env)) {
082: if (jclass.getDeclaringType() != null
083: && !jclass.hasModifier(Modifier.STATIC)) {
084: getDiagnostics().addError(jclass,
085: "error.form-not-static");
086: }
087:
088: if (!jclass.hasModifier(Modifier.PUBLIC)) {
089: getDiagnostics().addError(jclass,
090: "error.form-not-public");
091: }
092:
093: if (!CompilerUtils.hasDefaultConstructor(jclass)) {
094: getDiagnostics().addError(jclass,
095: "error.form-no-default-constructor");
096: }
097: }
098:
099: // check that a class with declarative validation uses a FormBean annotation
100: if (isFormBeanClass && !hasFormBeanAnnotation) {
101: getDiagnostics().addWarning(jclass,
102: "warning.validatable-formbean-use-formbean",
103: ANNOTATION_INTERFACE_PREFIX + FORM_BEAN_TAG_NAME);
104: }
105:
106: // Check to see if this class extends the (deprecated) FormData class and overrides its validate() method.
107: // If so, then declarative validation annotations won't work unless the override calls super.validate().
108: // Print a warning describing this behavior and suggesting implementing Validatable instead.
109: methods = jclass.getMethods();
110: if (CompilerUtils.isAssignableFrom(PAGEFLOW_FORM_CLASS_NAME,
111: jclass, env)) {
112: for (int i = 0; i < methods.length; i++) {
113:
114: MethodDeclaration method = methods[i];
115: if (method.getSimpleName().equals("validate")) {
116: ParameterDeclaration[] params = method
117: .getParameters();
118:
119: if (params.length == 2) {
120: TypeInstance param1Type = params[0].getType();
121: TypeInstance param2Type = params[1].getType();
122:
123: if (param1Type instanceof DeclaredType
124: && param2Type instanceof DeclaredType) {
125: TypeDeclaration param1Decl = ((DeclaredType) param1Type)
126: .getDeclaration();
127: TypeDeclaration param2Decl = ((DeclaredType) param2Type)
128: .getDeclaration();
129: TypeDeclaration actionMappingDecl = env
130: .getTypeDeclaration(STRUTS_ACTION_MAPPING_CLASS_NAME);
131: TypeDeclaration httpRequestDecl = env
132: .getTypeDeclaration(HTTP_REQUEST_CLASS_NAME);
133:
134: if (param1Decl != null
135: && CompilerUtils.typesAreEqual(
136: param1Decl,
137: actionMappingDecl)
138: && param2Decl != null
139: && CompilerUtils
140: .typesAreEqual(param2Decl,
141: httpRequestDecl)) {
142: getDiagnostics()
143: .addWarning(
144: method,
145: "warning.formdata-override-validate",
146: jclass
147: .getQualifiedName(),
148: PAGEFLOW_FORM_CLASS_NAME,
149: PAGEFLOW_VALIDATABLE_INTERFACE_NAME);
150: }
151: }
152: }
153: }
154: }
155: }
156:
157: return null;
158: }
159:
160: private boolean checkValidationAnnotation(MethodDeclaration method,
161: String annotationTagName, AnnotationGrammar grammar)
162: throws FatalCompileTimeException {
163: AnnotationInstance annotation = CompilerUtils.getAnnotation(
164: method, annotationTagName);
165:
166: if (annotation != null) {
167: if (CompilerUtils.getBeanProperty(method) == null) {
168: getDiagnostics().addError(annotation,
169: "error.validation-field-on-non-getter");
170: }
171:
172: grammar.check(annotation, null, method);
173:
174: return true;
175: }
176:
177: return false;
178: }
179:
180: private class GetterValidatablePropertyGrammar extends
181: ValidatablePropertyGrammar {
182: public GetterValidatablePropertyGrammar() {
183: super (FormBeanChecker.this .getEnv(), FormBeanChecker.this
184: .getDiagnostics(), FormBeanChecker.this
185: .getRuntimeVersionChecker());
186: }
187:
188: public String[][] getRequiredAttrs() {
189: return null; // This override causes the 'propertyName' attribute *not* to be required
190: }
191:
192: protected void onCheckMember(
193: AnnotationTypeElementDeclaration memberDecl,
194: AnnotationValue member, AnnotationInstance annotation,
195: AnnotationInstance[] parentAnnotations,
196: MemberDeclaration classMember) {
197: if (memberDecl.getSimpleName().equals(PROPERTY_NAME_ATTR)) {
198: addError(
199: member,
200: "error.validatable-field-property-name-not-allowed",
201: PROPERTY_NAME_ATTR);
202: }
203: }
204: }
205: }
|