All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.drinkjava2.jdialects.TableModelUtilsOfEntity Maven / Gradle / Ivy

There is a newer version: 5.0.15.jre8
Show newest version
/*
 * Copyright 2016 the original author or authors.
 *
 * 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.github.drinkjava2.jdialects;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import com.github.drinkjava2.jdialects.annotation.jpa.TemporalType;
import com.github.drinkjava2.jdialects.model.ColumnModel;
import com.github.drinkjava2.jdialects.model.TableModel;
import com.github.drinkjava2.jdialects.springsrc.utils.ReflectionUtils;

/**
 * The tool to convert entity classes to TableModels
 * 
 * @author Yong Zhu
 * @since 1.0.6
 */
@SuppressWarnings("all")
public abstract class TableModelUtilsOfEntity {// NOSONAR

	public static Map, TableModel> globalTableModelCache = new ConcurrentHashMap, TableModel>();

	public static Map> globalTableToEntityCache = new ConcurrentHashMap>();

	/**
	 * Convert tableName to entity class, note: before use this method
	 * entity2Models() method should be called first to cache talbeModels in memory
	 */
	public static Class tableNameToEntityClass(String tableName) {
		String lowCase = tableName.toLowerCase();
		Class result = globalTableToEntityCache.get(lowCase);
		if (result != null)
			return result;
		for (Entry, TableModel> entry : globalTableModelCache.entrySet()) {
			if (lowCase.equalsIgnoreCase(entry.getValue().getTableName())) {
				globalTableToEntityCache.put(lowCase, entry.getKey());
				return entry.getKey();
			}
		}
		return null;
	}

	private static boolean matchNameCheck(String annotationName, String cName) {
		if (("javax.persistence." + annotationName).equals(cName))
			return true;
		if (("com.github.drinkjava2.jdialects.annotation.jpa." + annotationName).equals(cName))
			return true;
		if (("com.github.drinkjava2.jdialects.annotation.jdia." + annotationName).equals(cName))
			return true;
		for (int i = 0; i <= 9; i++) {
			if (("com.github.drinkjava2.jdialects.annotation.jdia." + annotationName + i).equals(cName))
				return true;
		}
		return false;
	}

	/** Get all entity annotations started with annotationName */
	private static List> getEntityAnnos(Object targetClass, String annotationName) {
		Annotation[] anno = null;
		if (targetClass instanceof Field)
			anno = ((Field) targetClass).getAnnotations();
		else
			anno = ((Class) targetClass).getAnnotations();
		List> l = new ArrayList>();
		for (Annotation annotation : anno) {
			Class type = annotation.annotationType();
			String cName = type.getName();
			if (matchNameCheck(annotationName, cName)) {
				l.add(changeAnnotationValuesToMap(annotation, type));
			}
		}
		return l;
	}

	private static Map getFirstEntityAnno(Object targetClass, String annotationName) {
		Annotation[] anno = null;
		if (targetClass instanceof Field)
			anno = ((Field) targetClass).getAnnotations();
		else
			anno = ((Class) targetClass).getAnnotations();
		for (Annotation annotation : anno) {
			Class type = annotation.annotationType();
			String cName = type.getName();
			if (matchNameCheck(annotationName, cName))
				return changeAnnotationValuesToMap(annotation, type);
		}
		return new HashMap();
	}

	private static boolean existEntityAnno(Object targetClass, String annotationName) {
		Map annotion = getFirstEntityAnno(targetClass, annotationName);
		return annotion.size() == 1;
	}

	/** Change Annotation fields values into a Map */
	private static Map changeAnnotationValuesToMap(Annotation annotation,
			Class type) {
		Map result = new HashMap();
		result.put("AnnotationExist", true);
		for (Method method : type.getDeclaredMethods())
			try {
				result.put(method.getName(), method.invoke(annotation, (Object[]) null));
			} catch (Exception e) {// NOSONAR
			}
		return result;
	}

	/**
	 * Convert entity class to a read-only TableModel instance
	 */
	public static TableModel entity2ReadOnlyModel(Class entityClass) {
		DialectException.assureNotNull(entityClass, "Entity class can not be null");
		TableModel model = globalTableModelCache.get(entityClass);
		if (model != null)
			return model;
		model = entity2ModelWithConfig(entityClass);
		model.setReadOnly(true);
		globalTableModelCache.put(entityClass, model);
		return model;
	}

	/** Convert entity classes to a read-only TableModel instances */
	public static TableModel[] entity2ReadOnlyModel(Class... entityClasses) {
		List l = new ArrayList();
		for (Class clazz : entityClasses) {
			l.add(entity2ReadOnlyModel(clazz));
		}
		return l.toArray(new TableModel[l.size()]);
	}

	/**
	 * Convert entity class to a Editable TableModel instance
	 */
	public static TableModel entity2EditableModel(Class entityClass) {
		DialectException.assureNotNull(entityClass, "Entity class can not be null");
		TableModel model = globalTableModelCache.get(entityClass);
		if (model != null)
			return model.newCopy();
		model = entity2ModelWithConfig(entityClass);
		model.setReadOnly(true);
		globalTableModelCache.put(entityClass, model);
		return model.newCopy();
	}

	/** Convert entity classes to a editable TableModel instances */
	public static TableModel[] entity2EditableModels(Class... entityClasses) {
		List l = new ArrayList();
		for (Class clazz : entityClasses) {
			l.add(entity2EditableModel(clazz));
		}
		return l.toArray(new TableModel[l.size()]);
	}

	/**
	 * Convert a Java entity class or JPA annotated entity classes to "TableModel"
	 * Object, ignore config method
	 */
	private static TableModel entity2ModelIgnoreConfigMethod(Class entityClass) {
		DialectException.assureNotNull(entityClass, "entity2Model method does not accept a null class");

		// Entity
		String tableName = null;
		Map entityMap = getFirstEntityAnno(entityClass, "Entity");
		tableName = (String) entityMap.get("name");

		// Table
		Map tableMap = getFirstEntityAnno(entityClass, "Table");
		if (!StrUtils.isEmpty(tableMap.get("name")))
			tableName = (String) tableMap.get("name");
		if (StrUtils.isEmpty(tableName))
			tableName = entityClass.getSimpleName();
		TableModel model = new TableModel(tableName); // Build the tableModel
		model.setEntityClass(entityClass);
		if (!tableMap.isEmpty()) {
			// Index
			Annotation[] indexes = (Annotation[]) tableMap.get("indexes");
			if (indexes != null && indexes.length > 0)
				for (Annotation anno : indexes) {
					Map mp = changeAnnotationValuesToMap(anno, anno.annotationType());
					String columnListString = (String) mp.get("columnList");
					String[] columns;
					if (columnListString.indexOf(',') >= 0)
						columns = columnListString.split(",");
					else
						columns = new String[] { columnListString };
					if (columns.length > 0)
						model.index((String) mp.get("name")).columns(columns).setUnique((Boolean) mp.get("unique"));
				}

			// Unique
			Annotation[] uniques = (Annotation[]) tableMap.get("uniqueConstraints");
			if (uniques != null && uniques.length > 0)
				for (Annotation anno : uniques) {
					Map mp = changeAnnotationValuesToMap(anno, anno.annotationType());
					String[] columnNames = (String[]) mp.get("columnNames");
					if (columnNames != null && columnNames.length > 0)
						model.unique((String) mp.get("name")).columns(columnNames);
				}
		}

		// SequenceGenerator
		Map seqMap = getFirstEntityAnno(entityClass, "SequenceGenerator");
		if (!seqMap.isEmpty()) {
			model.sequenceGenerator((String) seqMap.get("name"), (String) seqMap.get("sequenceName"),
					(Integer) seqMap.get("initialValue"), (Integer) seqMap.get("allocationSize"));
		}

		// TableGenerator
		Map tableGenMap = getFirstEntityAnno(entityClass, "TableGenerator");
		if (!tableGenMap.isEmpty()) {
			model.tableGenerator((String) tableGenMap.get("name"), (String) tableGenMap.get("table"),
					(String) tableGenMap.get("pkColumnName"), (String) tableGenMap.get("valueColumnName"),
					(String) tableGenMap.get("pkColumnValue"), (Integer) tableGenMap.get("initialValue"),
					(Integer) tableGenMap.get("allocationSize"));
		}

		// UUIDAny
		Map uuidAnyMp = getFirstEntityAnno(entityClass, "UUIDAny");
		if (!uuidAnyMp.isEmpty()) {
			model.uuidAny((String) uuidAnyMp.get("name"), (Integer) uuidAnyMp.get("length"));
		}

		// FKey
		List> fkeys = getEntityAnnos(entityClass, "FKey");
		for (Map map : fkeys) {
			Boolean ddl = (Boolean) map.get("ddl");
			if (ddl == null)
				ddl = true;
			model.fkey((String) map.get("name")).columns((String[]) map.get("columns")).refs((String[]) map.get("refs"))
					.ddl(ddl);
		}

		BeanInfo beanInfo = null;
		PropertyDescriptor[] pds = null;
		try {
			beanInfo = Introspector.getBeanInfo(entityClass);
			pds = beanInfo.getPropertyDescriptors();
		} catch (Exception e) {
			DialectException.throwEX("entity2Model can not get bean info", e);
		}

		for (PropertyDescriptor pd : pds) {
			String entityfieldName = pd.getName();
			if ("class".equals(entityfieldName) || "simpleName".equals(entityfieldName)
					|| "canonicalName".equals(entityfieldName))
				continue;
			Class propertyClass = pd.getPropertyType();

			Field field = ReflectionUtils.findField(entityClass, entityfieldName);
			if (field == null)
				continue;

			Object convertClassOrName = null;
			Map convertMap = getFirstEntityAnno(field, "Version"); // @Version
			if (!convertMap.isEmpty())
				convertClassOrName = "Version";
			else {
				convertMap = getFirstEntityAnno(field, "Convert");
				if (!convertMap.isEmpty()) {
					convertClassOrName = (Class) convertMap.get("value");// jdia's annotation
					if (convertClassOrName == null || convertClassOrName == void.class)
						convertClassOrName = (Class) convertMap.get("converter");// JPA's annotation
					if (convertClassOrName == void.class)
						convertClassOrName = null;
				}

				convertMap = getFirstEntityAnno(field, "Enumerated"); // @Enumerated
				if (!convertMap.isEmpty())
					convertClassOrName = "EnumType." + convertMap.get("value"); // ORDINAL or String
			}

			if (!getFirstEntityAnno(field, "Transient").isEmpty()
					|| (convertClassOrName == null && !TypeUtils.canMapToDialectType(propertyClass))) {
				ColumnModel col = new ColumnModel(entityfieldName);
				col.setColumnType(TypeUtils.javaType2DialectType(propertyClass));
				col.setTransientable(true);
				col.setEntityField(entityfieldName);
				col.setTableModel(model);
				model.addColumn(col);
			} else {

				// @SequenceGenerator
				Map map = getFirstEntityAnno(field, "SequenceGenerator");
				if (!map.isEmpty()) {
					model.sequenceGenerator((String) map.get("name"), (String) map.get("sequenceName"),
							(Integer) map.get("initialValue"), (Integer) map.get("allocationSize"));
				}

				// @TableGenerator
				map = getFirstEntityAnno(field, "TableGenerator");
				if (!map.isEmpty()) {
					model.tableGenerator((String) map.get("name"), (String) map.get("table"),
							(String) map.get("pkColumnName"), (String) map.get("valueColumnName"),
							(String) map.get("pkColumnValue"), (Integer) map.get("initialValue"),
							(Integer) map.get("allocationSize"));
				}

				// @UUIDAny
				map = getFirstEntityAnno(field, "UUIDAny");
				if (!map.isEmpty()) {
					model.uuidAny((String) map.get("name"), (Integer) map.get("length"));
				}

				// @Version annotation
				ColumnModel col = new ColumnModel(entityfieldName);
				col.entityField(entityfieldName);
				col.setConverterClassOrName(convertClassOrName);// @Convert's value

				// Column
				Map colMap = getFirstEntityAnno(field, "Column");
				if (!colMap.isEmpty()) {
					if (!(Boolean) colMap.get("nullable"))
						col.setNullable(false);
					if (!StrUtils.isEmpty(colMap.get("name")))
						col.setColumnName((String) colMap.get("name"));
					col.setLength((Integer) colMap.get("length"));
					col.setPrecision((Integer) colMap.get("precision"));
					col.setScale((Integer) colMap.get("scale"));
					if (!StrUtils.isEmpty(colMap.get("columnDefinition"))) {
						String colDEF = (String) colMap.get("columnDefinition");
						col.setColumnDefinition(colDEF);
						colDEF = colDEF.trim();
						if (colDEF.contains(" "))
							colDEF = StrUtils.substringBefore(colDEF, " ");
						col.setColumnType(TypeUtils.colDef2DialectType(colDEF));
					} else
						col.setColumnType(TypeUtils.javaType2DialectType(propertyClass));
					col.setInsertable((Boolean) colMap.get("insertable"));
					col.setUpdatable((Boolean) colMap.get("updatable"));
				} else {
					col.setColumnType(TypeUtils.javaType2DialectType(propertyClass));// TODO_ check
				}
				if ("EnumType.ORDINAL".equals(col.getConverterClassOrName()))
					col.setColumnType(Type.INTEGER);
				else if ("EnumType.STRING".equals(col.getConverterClassOrName()))
					col.setColumnType(Type.VARCHAR);

				// @Id
				if (!getFirstEntityAnno(field, "Id").isEmpty() || !getFirstEntityAnno(field, "PKey").isEmpty())
					col.pkey();

				// Temporal annotation
				Map TemporalMap = getFirstEntityAnno(field, "Temporal");
				if (!TemporalMap.isEmpty()) {
					Object temporalType = TemporalMap.get("value").toString();
					if ("TIMESTAMP".equals(temporalType))
						col.setColumnType(Type.TIMESTAMP);
					else if ("DATE".equals(temporalType))
						col.setColumnType(Type.DATE);
					else if ("TIME".equals(temporalType))
						col.setColumnType(Type.TIME);
				}

				// @ShardTable
				Map shardTableMap = getFirstEntityAnno(field, "ShardTable");
				if (!shardTableMap.isEmpty())
					col.shardTable((String[]) shardTableMap.get("value"));

				// @ShardDatabase
				Map shardDatabaseMap = getFirstEntityAnno(field, "ShardDatabase");
				if (!shardDatabaseMap.isEmpty())
					col.shardDatabase((String[]) shardDatabaseMap.get("value"));

				col.setEntityField(entityfieldName);
				col.setTableModel(model);
				// col will also set TableModel field point to its owner
				model.addColumn(col);

				// shortcut Id generator annotations
				if (existEntityAnno(field, "AutoId"))
					col.autoId();
				if (existEntityAnno(field, "IdentityId"))
					col.identityId();
				if (existEntityAnno(field, "TimeStampId"))
					col.timeStampId();
				if (existEntityAnno(field, "UUID25"))
					col.uuid25();
				if (existEntityAnno(field, "UUID32"))
					col.uuid32();
				if (existEntityAnno(field, "UUID36"))
					col.uuid36();
				if (existEntityAnno(field, "Snowflake"))
					col.snowflake();

				// GeneratedValue
				Map gvMap = getFirstEntityAnno(field, "GeneratedValue");
				if (!gvMap.isEmpty()) {
					Object strategy = gvMap.get("strategy");
					if (strategy != null) {
						String strategyStr = strategy.toString();
						if ("AUTO".equals(strategyStr))
							col.autoId();
						else if ("IDENTITY".equals(strategyStr))
							col.identityId();
						else if ("UUID25".equals(strategyStr))
							col.uuid25();
						else if ("UUID32".equals(strategyStr))
							col.uuid32();
						else if ("UUID36".equals(strategyStr))
							col.uuid36();
						else if ("TIMESTAMP".equals(strategyStr))
							col.timeStampId();
						else {
							String generator = (String) gvMap.get("generator");
							if (StrUtils.isEmpty(generator))
								throw new DialectException(
										"GeneratedValue strategy '" + strategyStr + "' can not find a generator");
							col.idGenerator(generator);
						}
					}
				}

				// SingleFKey is a shortcut format of FKey, only for 1
				// column
				Map refMap = getFirstEntityAnno(field, "SingleFKey");
				if (!refMap.isEmpty()) {
					Boolean ddl = (Boolean) refMap.get("ddl");
					if (ddl == null)
						ddl = true;
					model.fkey((String) refMap.get("name")).columns(col.getColumnName())
							.refs((String[]) refMap.get("refs")).ddl(ddl);
				}

				// SingleIndex is a ShortCut format of Index, only for 1
				// column
				Map idxMap = getFirstEntityAnno(field, "SingleIndex");
				if (!idxMap.isEmpty())
					model.index((String) idxMap.get("name")).columns(col.getColumnName());

				// SingleUnique is a ShortCut format of Unique, only for 1
				// column
				Map uniMap = getFirstEntityAnno(field, "SingleUnique");
				if (!uniMap.isEmpty())
					model.unique((String) uniMap.get("name")).columns(col.getColumnName());
			}

		} // End of columns loop
		return model;
	}

	/**
	 * Convert entity class to a Editable TableModel instance , if this class has a
	 * "config(TableModel tableModel)" method, will also call it
	 */
	private static TableModel entity2ModelWithConfig(Class entityClass) {
		TableModel model;
		model = entity2ModelIgnoreConfigMethod(entityClass);
		Method method = null;
		try {
			method = entityClass.getMethod("config", TableModel.class);
		} catch (Exception e) {// NOSONAR
		}
		if (method != null)
			try {
				method.invoke(null, model);
			} catch (Exception e) {
				throw new DialectException(e);
			}
		if (model == null)
			throw new DialectException("Can not create TableModel for entityClass " + entityClass);
		TableModel.sortColumns(model.getColumns());
		return model;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy