/*
* Copyright (C) 2015 Noorq, 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.noorq.casser.mapping;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import com.noorq.casser.core.Casser;
import com.noorq.casser.core.Getter;
import com.noorq.casser.core.reflect.CasserPropertyNode;
import com.noorq.casser.core.reflect.DslExportable;
import com.noorq.casser.core.reflect.ListDsl;
import com.noorq.casser.core.reflect.MapDsl;
import com.noorq.casser.core.reflect.MapExportable;
import com.noorq.casser.core.reflect.ReflectionInstantiator;
import com.noorq.casser.core.reflect.SetDsl;
import com.noorq.casser.mapping.annotation.Index;
import com.noorq.casser.mapping.annotation.Table;
import com.noorq.casser.mapping.annotation.Tuple;
import com.noorq.casser.mapping.annotation.UDT;
import com.noorq.casser.support.CasserMappingException;
import com.noorq.casser.support.DslPropertyException;
public final class MappingUtil {
@SuppressWarnings("unchecked")
public static final ConstraintValidator<? extends Annotation, ?>[] EMPTY_VALIDATORS = new ConstraintValidator[0];
private MappingUtil() {
}
public static ConstraintValidator<? extends Annotation, ?>[] getValidators(Method getterMethod) {
List<ConstraintValidator<? extends Annotation, ?>> list = null;
for (Annotation constraintAnnotation : getterMethod.getDeclaredAnnotations()) {
list = addValidators(constraintAnnotation, list);
Class<? extends Annotation> annotationType = constraintAnnotation.annotationType();
for (Annotation possibleConstraint : annotationType.getDeclaredAnnotations()) {
list = addValidators(possibleConstraint, list);
}
}
if (list == null) {
return EMPTY_VALIDATORS;
}
else {
return list.toArray(EMPTY_VALIDATORS);
}
}
private static List<ConstraintValidator<? extends Annotation, ?>> addValidators(Annotation constraintAnnotation, List<ConstraintValidator<? extends Annotation, ?>> list) {
Class<? extends Annotation> annotationType = constraintAnnotation.annotationType();
for (Annotation possibleConstraint : annotationType.getDeclaredAnnotations()) {
if (possibleConstraint instanceof Constraint) {
Constraint constraint = (Constraint) possibleConstraint;
for (Class<? extends ConstraintValidator<?, ?>> clazz : constraint.validatedBy()) {
ConstraintValidator<? extends Annotation, ?> validator = ReflectionInstantiator.instantiateClass(clazz);
((ConstraintValidator) validator).initialize(constraintAnnotation);
if (list == null) {
list = new ArrayList<ConstraintValidator<? extends Annotation, ?>>();
}
list.add(validator);
}
}
}
return list;
}
public static Optional<IdentityName> getIndexName(Method getterMethod) {
String indexName = null;
boolean forceQuote = false;
Index index = getterMethod.getDeclaredAnnotation(Index.class);
if (index != null) {
indexName = index.value();
forceQuote = index.forceQuote();
if (indexName == null || indexName.isEmpty()) {
indexName = getDefaultColumnName(getterMethod);
}
}
return indexName != null ? Optional.of(new IdentityName(indexName, forceQuote)) : Optional.empty();
}
public static String getPropertyName(Method getter) {
return getter.getName();
}
public static String getDefaultColumnName(Method getter) {
return Casser.settings().getPropertyToColumnConverter()
.apply(getPropertyName(getter));
}
public static IdentityName getUserDefinedTypeName(Class<?> iface, boolean required) {
String userTypeName = null;
boolean forceQuote = false;
UDT userDefinedType = iface
.getDeclaredAnnotation(UDT.class);
if (userDefinedType != null) {
userTypeName = userDefinedType.value();
forceQuote = userDefinedType.forceQuote();
if (userTypeName == null || userTypeName.isEmpty()) {
userTypeName = getDefaultEntityName(iface);
}
return new IdentityName(userTypeName, forceQuote);
}
if (required) {
throw new CasserMappingException(
"entity must have annotation @UserDefinedType " + iface);
}
return null;
}
public static boolean isTuple(Class<?> iface) {
Tuple tuple = iface
.getDeclaredAnnotation(Tuple.class);
return tuple != null;
}
public static boolean isUDT(Class<?> iface) {
UDT udt = iface
.getDeclaredAnnotation(UDT.class);
return udt != null;
}
public static IdentityName getTableName(Class<?> iface, boolean required) {
String tableName = null;
boolean forceQuote = false;
Table table = iface.getDeclaredAnnotation(Table.class);
if (table != null) {
tableName = table.value();
forceQuote = table.forceQuote();
} else if (required) {
throw new CasserMappingException(
"entity must have annotation @Table " + iface);
}
if (tableName == null || tableName.isEmpty()) {
tableName = getDefaultEntityName(iface);
}
return new IdentityName(tableName, forceQuote);
}
public static String getDefaultEntityName(Class<?> iface) {
return Casser.settings().getPropertyToColumnConverter()
.apply(iface.getSimpleName());
}
public static Class<?> getMappingInterface(Object pojo) {
Class<?> iface = null;
if (pojo instanceof Class) {
iface = (Class<?>) pojo;
if (!iface.isInterface()) {
throw new CasserMappingException("expected interface " + iface);
}
} else {
Class<?>[] ifaces = pojo.getClass().getInterfaces();
int len = ifaces.length;
for (int i = 0; i != len; ++i) {
iface = ifaces[0];
if (MapExportable.class.isAssignableFrom(iface)) {
continue;
}
if (iface.getDeclaredAnnotation(Table.class) != null ||
iface.getDeclaredAnnotation(UDT.class) != null ||
iface.getDeclaredAnnotation(Tuple.class) != null) {
break;
}
}
}
if (iface == null) {
throw new CasserMappingException("dsl interface not found for " + pojo);
}
return iface;
}
public static CasserPropertyNode resolveMappingProperty(
Getter<?> getter) {
try {
Object childDsl = getter.get();
if (childDsl instanceof DslExportable) {
DslExportable e = (DslExportable) childDsl;
return e.getParentDslCasserPropertyNode();
}
else if (childDsl instanceof MapDsl) {
MapDsl mapDsl = (MapDsl) childDsl;
return mapDsl.getParent();
}
else if (childDsl instanceof ListDsl) {
ListDsl listDsl = (ListDsl) childDsl;
return listDsl.getParent();
}
else if (childDsl instanceof SetDsl) {
SetDsl setDsl = (SetDsl) childDsl;
return setDsl.getParent();
}
throw new CasserMappingException(
"getter must reference to the dsl object " + getter);
} catch (DslPropertyException e) {
return e.getPropertyNode();
}
}
}