archidata/src/org/kar/archidata/annotation/AnnotationTools.java

535 lines
17 KiB
Java

package org.kar.archidata.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.annotation.checker.Checker;
import org.kar.archidata.annotation.checker.CollectionItemNotNull;
import org.kar.archidata.annotation.checker.CollectionItemUnique;
import org.kar.archidata.annotation.checker.CollectionNotEmpty;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.options.OptionRenameColumn;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.morphia.annotations.Entity;
import dev.morphia.mapping.Mapper;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import jakarta.ws.rs.DefaultValue;
public class AnnotationTools {
static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class);
// For SQL declaration table Name
public static String getTableName(final Class<?> clazz, final QueryOptions options) throws DataAccessException {
if (options != null) {
final List<OverrideTableName> data = options.get(OverrideTableName.class);
if (data.size() == 1) {
return data.get(0).getName();
}
}
return AnnotationTools.getTableName(clazz);
}
// For SQL declaration table Name
public static String getTableName(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Table.class);
if (annotation.length == 0) {
// when no annotation is detected, then the table name is the class name
return element.getSimpleName();
}
final String tmp = ((Table) annotation[0]).name();
if (tmp == null) {
return element.getSimpleName();
}
return tmp;
}
public static String getCollectionName(final Class<?> clazz, final QueryOptions options) {
if (options != null) {
// TODO: maybe change OverrideTableName with OverrideCollectionName
final List<OverrideTableName> data = options.get(OverrideTableName.class);
if (data.size() == 1) {
return data.get(0).getName();
}
}
return AnnotationTools.getCollectionName(clazz);
}
// For No-SQL Table/Collection Name
public static String getCollectionName(final Class<?> clazz) {
final Annotation[] annotation = clazz.getDeclaredAnnotationsByType(Entity.class);
if (annotation.length == 0) {
// when no annotation is detected, then the table name is the class name
return clazz.getSimpleName();
}
final String tmp = ((Entity) annotation[0]).value();
if (tmp == null || tmp.length() == 0 || Mapper.IGNORED_FIELDNAME.equals(tmp)) {
return clazz.getSimpleName();
}
return tmp;
}
public static CollectionItemNotNull getCollectionItemNotNull(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(CollectionItemNotNull.class);
if (annotation.length == 0) {
return null;
}
return (CollectionItemNotNull) annotation[0];
}
public static CollectionItemUnique getCollectionItemUnique(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(CollectionItemUnique.class);
if (annotation.length == 0) {
return null;
}
return (CollectionItemUnique) annotation[0];
}
public static CollectionNotEmpty getCollectionNotEmpty(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(CollectionNotEmpty.class);
if (annotation.length == 0) {
return null;
}
return (CollectionNotEmpty) annotation[0];
}
public static boolean getSchemaReadOnly(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return false;
}
return ((Schema) annotation[0]).readOnly();
}
public static String getSchemaExample(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
}
return ((Schema) annotation[0]).example();
}
public static boolean getNoWriteSpecificMode(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(NoWriteSpecificMode.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static String getSchemaDescription(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
}
return ((Schema) annotation[0]).description();
}
public static String getSchemaDescription(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
}
return ((Schema) annotation[0]).description();
}
public static String getDefault(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DefaultValue.class);
if (annotation.length == 0) {
return null;
}
return ((DefaultValue) annotation[0]).value();
}
public static ManyToOne getManyToOne(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(ManyToOne.class);
if (annotation.length == 0) {
return null;
}
return (ManyToOne) annotation[0];
}
public static ManyToMany getManyToMany(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(ManyToMany.class);
if (annotation.length == 0) {
return null;
}
return (ManyToMany) annotation[0];
}
public static OneToMany getOneToMany(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(OneToMany.class);
if (annotation.length == 0) {
return null;
}
return (OneToMany) annotation[0];
}
public static DataJson getDataJson(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DataJson.class);
if (annotation.length == 0) {
return null;
}
return (DataJson) annotation[0];
}
public static Checker[] getCheckers(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Checker.class);
if (annotation.length == 0) {
return null;
}
return (Checker[]) annotation;
}
public static DecimalMin getConstraintsDecimalMin(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DecimalMin.class);
if (annotation.length == 0) {
return null;
}
return ((DecimalMin) annotation[0]);
}
public static DecimalMax getConstraintsDecimalMax(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DecimalMax.class);
if (annotation.length == 0) {
return null;
}
return ((DecimalMax) annotation[0]);
}
public static Long getConstraintsMax(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Max.class);
if (annotation.length == 0) {
return null;
}
return ((Max) annotation[0]).value();
}
public static Long getConstraintsMin(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Min.class);
if (annotation.length == 0) {
return null;
}
return ((Min) annotation[0]).value();
}
public static int getLimitSize(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return 255;
}
final int length = ((Column) annotation[0]).length();
return length <= 0 ? 0 : length;
}
public static Size getConstraintsSize(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Size.class);
if (annotation.length == 0) {
return null;
}
return (Size) annotation[0];
}
public static String getConstraintsPattern(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Pattern.class);
if (annotation.length == 0) {
return null;
}
return ((Pattern) annotation[0]).regexp();
}
public static boolean getConstraintsEmail(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Email.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static boolean isAnnotationGroup(final Field field, final Class<?> annotationType) {
try {
final Annotation[] anns = field.getAnnotations();
for (final Annotation ann : anns) {
if (ann.annotationType() == annotationType) {
return true;
}
}
for (final Annotation ann : anns) {
final Annotation[] anns2 = ann.annotationType().getDeclaredAnnotations();
for (final Annotation ann2 : anns2) {
if (ann2.annotationType() == annotationType) {
return true;
}
}
}
} catch (final Exception ex) {
LOGGER.error("Catch exception when try to get annotation...{}", ex.getLocalizedMessage());
return false;
}
return false;
}
public static String getFieldNameRaw(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return element.getName();
}
final String name = ((Column) annotation[0]).name();
if (name.isBlank()) {
return element.getName();
}
return name;
}
public record FieldName(
String inStruct,
String inTable) {};
public static FieldName getFieldName(final Field element, final QueryOptions options) {
final String inStructName = getFieldNameRaw(element);
String inTableName = inStructName;
if (options != null) {
final List<OptionRenameColumn> renamesColumn = options.get(OptionRenameColumn.class);
for (final OptionRenameColumn rename : renamesColumn) {
if (rename.columnName.equals(inStructName)) {
inTableName = rename.colomnNewName;
LOGGER.trace("Detect overwrite of column name '{}' => '{}'", inStructName, inTableName);
break;
}
}
}
return new FieldName(inStructName, inTableName);
}
public static boolean getColumnNotNull(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return false;
}
return !((Column) annotation[0]).nullable();
}
public static boolean getNullable(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Nullable.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static boolean getConstraintsNotNull(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(NotNull.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static Field getPrimaryKeyField(final Class<?> clazz) {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.isPrimaryKey(field)) {
return field;
}
}
return null;
}
public static boolean isPrimaryKey(final Field element) {
final Annotation[] annotationSQL = element.getDeclaredAnnotationsByType(Id.class);
if (annotationSQL.length > 0) {
return true;
}
final Annotation[] annotationMongo = element.getDeclaredAnnotationsByType(dev.morphia.annotations.Id.class);
if (annotationMongo.length > 0) {
return true;
}
return false;
}
public static boolean isUnique(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return false;
}
return ((Column) annotation[0]).unique();
}
public static GenerationType getStrategy(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(GeneratedValue.class);
if (annotation.length == 0) {
return null;
}
return ((GeneratedValue) annotation[0]).strategy();
}
public static boolean isDeletedField(final Field element) {
return element.getDeclaredAnnotationsByType(DataDeleted.class).length != 0;
}
public static boolean isCreatedAtField(final Field element) {
return element.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
}
public static boolean isUpdateAtField(final Field element) {
return element.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
}
public static boolean isDefaultNotRead(final Field element) {
return element.getDeclaredAnnotationsByType(DataNotRead.class).length != 0;
}
public static boolean isIdField(final Field element) {
if (element.getDeclaredAnnotationsByType(Id.class).length != 0) {
return true;
}
return element.getDeclaredAnnotationsByType(dev.morphia.annotations.Id.class).length != 0;
}
// Note: delete field can not be renamed with OptionRenameColumn
public static String getDeletedFieldName(final Class<?> clazz) {
try {
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
if (AnnotationTools.isDeletedField(elem)) {
return AnnotationTools.getFieldNameRaw(elem);
}
}
} catch (final Exception ex) {
ex.printStackTrace();
}
return null;
}
// Note: update field can not be renamed with OptionRenameColumn
public static String getUpdatedFieldName(final Class<?> clazz) {
try {
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
if (AnnotationTools.isUpdateAtField(elem)) {
return AnnotationTools.getFieldNameRaw(elem);
}
}
} catch (final Exception ex) {
ex.printStackTrace();
}
return null;
}
public static Field getIdField(final Class<?> clazz) {
try {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.isIdField(field)) {
return field;
}
}
} catch (final Exception ex) {
ex.printStackTrace();
}
return null;
}
public static boolean hasFieldsName(final Class<?> clazz, final String name) {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.getFieldNameRaw(field).equals(name)) {
return true;
}
}
return false;
}
public static List<String> getFieldsNames(final Class<?> clazz) {
return getFieldsNamesFilter(clazz, false);
}
public static List<String> getAllFieldsNames(final Class<?> clazz) {
return getFieldsNamesFilter(clazz, true);
}
private static List<String> getFieldsNamesFilter(final Class<?> clazz, final boolean full) {
final List<String> out = new ArrayList<>();
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (!full && AnnotationTools.isGenericField(field)) {
continue;
}
out.add(AnnotationTools.getFieldNameRaw(field));
}
return out;
}
public static boolean isGenericField(final Field elem) {
return AnnotationTools.isPrimaryKey(elem) || AnnotationTools.isCreatedAtField(elem)
|| AnnotationTools.isUpdateAtField(elem) || AnnotationTools.isDeletedField(elem);
}
public static Field getFieldOfId(final Class<?> clazz) {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.isIdField(field)) {
return field;
}
}
return null;
}
public static Field getFieldNamed(final Class<?> clazz, final String name) {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.getFieldNameRaw(field).equals(name)) {
return field;
}
}
return null;
}
}