blob: 0e6d12e707ca1ee6eca8a007d191ab1c6fad5f6f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.myfaces.extensions.validator.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.beans.Introspector;
import java.lang.reflect.Method;
import org.apache.myfaces.extensions.validator.core.ExtValCoreConfiguration;
import org.apache.myfaces.extensions.validator.core.property.PropertyDetails;
import org.apache.myfaces.extensions.validator.core.storage.MappedConstraintSourceStorage;
import org.apache.myfaces.extensions.validator.core.storage.PropertyStorage;
import org.apache.myfaces.extensions.validator.internal.UsageCategory;
import org.apache.myfaces.extensions.validator.internal.UsageInformation;
/**
* Contains helper methods that deal with annotation usage in the context of ExtVal.
*
* @author Gerhard Petracek
* @since r4
*/
@UsageInformation(UsageCategory.INTERNAL)
@SuppressWarnings("unchecked")
public final class ConstraintSourceUtils
{
protected ConstraintSourceUtils()
{
// Utility class, don't allow instantiation.
}
public static PropertyDetails resolveMappedConstraintSourceFor(String originalKey,
Class originalClass,
String originalProperty)
{
MappedConstraintSourceStorage mappedConstraintSourceStorage = getConstraintSourceStorage();
if (isMappedConstraintSourceCached(mappedConstraintSourceStorage, originalClass, originalProperty))
{
return getMappedConstraintSource(mappedConstraintSourceStorage, originalClass, originalProperty);
}
originalClass = ProxyUtils.getUnproxiedClass(originalClass);
PropertyStorage propertyStorage = ReflectionUtils.getPropertyStorage();
Class newClass = findMappedClass(propertyStorage, originalClass, originalProperty);
//mapped source is ignored via @IgnoreConstraintSource or there is just no mapping annotation at the target
if (newClass == null)
{
tryToCacheMappedConstraintSourceMetaData(
mappedConstraintSourceStorage, originalClass, originalProperty, null);
return null;
}
String newProperty = findMappedProperty(propertyStorage, originalClass, newClass, originalProperty);
PropertyDetails result = new PropertyDetails(originalKey, newClass, newProperty);
tryToCacheMappedConstraintSourceMetaData(
mappedConstraintSourceStorage, originalClass, originalProperty, result);
return result;
}
private static boolean isMappedConstraintSourceCached(
MappedConstraintSourceStorage storage, Class baseBeanClass, String property)
{
return storage.containsMapping(baseBeanClass, property);
}
private static PropertyDetails getMappedConstraintSource(
MappedConstraintSourceStorage storage, Class baseBeanClass, String property)
{
return storage.getMappedConstraintSource(baseBeanClass, property);
}
private static void tryToCacheMappedConstraintSourceMetaData(
MappedConstraintSourceStorage storage, Class originalClass, String originalProperty, PropertyDetails result)
{
storage.storeMapping(originalClass, originalProperty, result);
}
private static MappedConstraintSourceStorage getConstraintSourceStorage()
{
return ExtValUtils
.getStorage(MappedConstraintSourceStorage.class, MappedConstraintSourceStorage.class.getName());
}
private static Class findMappedClass(PropertyStorage storage, Class baseBeanClass, String property)
{
Class<? extends Annotation> constraintSourceAnnotationImplementation = ExtValCoreConfiguration.get()
.constraintSourceAnnotation();
Annotation foundConstraintSourceAnnotation = tryToGetAnnotationFromProperty(
storage, baseBeanClass, property, constraintSourceAnnotationImplementation);
if (foundConstraintSourceAnnotation == null)
{
foundConstraintSourceAnnotation = tryToGetAnnotationFromField(
storage, baseBeanClass, property, constraintSourceAnnotationImplementation);
}
if (foundConstraintSourceAnnotation == null && !isMappedConstraintSourceIgnored(baseBeanClass, property))
{
foundConstraintSourceAnnotation = tryToGetConstraintSourceAnnotationFromClass(
baseBeanClass, constraintSourceAnnotationImplementation);
}
if (foundConstraintSourceAnnotation != null)
{
return ExtValAnnotationUtils.extractValueOf(foundConstraintSourceAnnotation, Class.class);
}
return null;
}
private static String findMappedProperty(
PropertyStorage storage, Class baseBeanClass, Class newBaseBeanClass, String originalProperty)
{
Annotation targetPropertyAnnotation = getTargetPropertyMetaData(storage, baseBeanClass, originalProperty);
if (targetPropertyAnnotation != null)
{
return extractNewPropertyName(newBaseBeanClass, targetPropertyAnnotation);
}
return originalProperty;
}
private static Annotation getTargetPropertyMetaData(
PropertyStorage storage, Class baseBeanClass, String originalProperty)
{
Class<? extends Annotation> targetPropertyAnnotation = getTargetPropertyAnnotationImplementation();
Class<? extends Annotation> targetPropertyIdAnnotation = getTargetPropertyIdAnnotationImplementation();
Annotation result = findTargetPropertyIdAnnotation(
storage, baseBeanClass, originalProperty, targetPropertyIdAnnotation);
if (result == null)
{
result = findTargetPropertyAnnotation(
storage, baseBeanClass, originalProperty, targetPropertyAnnotation);
}
return result;
}
private static Class<? extends Annotation> getTargetPropertyAnnotationImplementation()
{
return ExtValCoreConfiguration.get().targetPropertyAnnotation();
}
private static Class<? extends Annotation> getTargetPropertyIdAnnotationImplementation()
{
return ExtValCoreConfiguration.get().targetPropertyIdAnnotation();
}
private static String extractNewPropertyName(Class targetClass, Annotation annotation)
{
Object annotationValue = ExtValAnnotationUtils.extractValueOf(annotation, Object.class);
//@TargetProperty
if (annotationValue instanceof String)
{
return (String) annotationValue;
}
//@TargetPropertyId
if (annotationValue instanceof Class)
{
return findNameOfAnnotatedProperty(targetClass, (Class) annotationValue);
}
return null;
}
//EXTVAL-83/use-case 5
private static String findNameOfAnnotatedProperty(
Class targetClass, Class<? extends Annotation> customTargetMarkerAnnotation)
{
for (Method currentMethod : targetClass.getDeclaredMethods())
{
if (currentMethod.isAnnotationPresent(customTargetMarkerAnnotation))
{
return convertMethodToPropertyName(currentMethod.getName());
}
}
for (Field currentField : targetClass.getDeclaredFields())
{
if (currentField.isAnnotationPresent(customTargetMarkerAnnotation))
{
return convertFieldToPropertyName(currentField.getName());
}
}
return null;
}
private static String convertMethodToPropertyName(String name)
{
String result = name;
if (name.startsWith("is"))
{
result = name.substring(2);
}
else if (name.startsWith("get"))
{
result = name.substring(3);
}
return Introspector.decapitalize(result);
}
private static String convertFieldToPropertyName(String name)
{
if (name.startsWith("_"))
{
return name.substring(1);
}
return name;
}
private static Annotation findTargetPropertyIdAnnotation(PropertyStorage storage,
Class baseBeanClass,
String property,
Class<? extends Annotation> targetPropertyIdAnnotation)
{
Annotation result = tryToGetAnnotationFromProperty(
storage, baseBeanClass, property, targetPropertyIdAnnotation);
if (result == null)
{
result = tryToGetAnnotationFromField(storage, baseBeanClass, property, targetPropertyIdAnnotation);
}
return result;
}
private static Annotation findTargetPropertyAnnotation(PropertyStorage storage,
Class baseBeanClass,
String property,
Class<? extends Annotation> targetPropertyAnnotation)
{
Annotation result = tryToGetAnnotationFromProperty(storage, baseBeanClass, property, targetPropertyAnnotation);
if (result == null)
{
result = tryToGetAnnotationFromField(storage, baseBeanClass, property, targetPropertyAnnotation);
}
return result;
}
private static boolean isMappedConstraintSourceIgnored(Class baseBeanClass, String property)
{
PropertyStorage storage = ReflectionUtils.getPropertyStorage();
Method method = ReflectionUtils.tryToGetMethodOfProperty(storage, baseBeanClass, property);
if (method != null && method.isAnnotationPresent(getIgnoreConstraintSourceAnnotationImplementation()))
{
return true;
}
Field field = ReflectionUtils.tryToGetFieldOfProperty(storage, baseBeanClass, property);
if (field != null && field.isAnnotationPresent(getIgnoreConstraintSourceAnnotationImplementation()))
{
return true;
}
return false;
}
private static Annotation tryToGetConstraintSourceAnnotationFromClass(
Class baseBeanClass, Class<? extends Annotation> annotation)
{
if (baseBeanClass.isAnnotationPresent(annotation))
{
return baseBeanClass.getAnnotation(annotation);
}
return null;
}
private static Class<? extends Annotation> getIgnoreConstraintSourceAnnotationImplementation()
{
return ExtValCoreConfiguration.get().ignoreConstraintSourceAnnotation();
}
private static Annotation tryToGetAnnotationFromField(
PropertyStorage storage, Class baseBeanClass, String property, Class<? extends Annotation> annotationClass)
{
Field field = ReflectionUtils.tryToGetFieldOfProperty(storage, baseBeanClass, property);
if (field != null && field.isAnnotationPresent(annotationClass))
{
return field.getAnnotation(annotationClass);
}
return null;
}
private static Annotation tryToGetAnnotationFromProperty(PropertyStorage storage,
Class baseBeanClass,
String property,
Class<? extends Annotation> annotationClass)
{
Method method = ReflectionUtils.tryToGetMethodOfProperty(storage, baseBeanClass, property);
if (method != null && method.isAnnotationPresent(annotationClass))
{
return method.getAnnotation(annotationClass);
}
return null;
}
}