diff --git a/src/org/kar/archidata/annotation/AnnotationTools.java b/src/org/kar/archidata/annotation/AnnotationTools.java index dea7c1b..83b4001 100644 --- a/src/org/kar/archidata/annotation/AnnotationTools.java +++ b/src/org/kar/archidata/annotation/AnnotationTools.java @@ -257,6 +257,19 @@ public class AnnotationTools { return true; } + public static Field getPrimaryKeyField(final Class clazz) throws Exception { + 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) throws Exception { final Annotation[] annotation = element.getDeclaredAnnotationsByType(Id.class); if (annotation.length == 0) { diff --git a/src/org/kar/archidata/dataAccess/DataAccess.java b/src/org/kar/archidata/dataAccess/DataAccess.java index c640464..c9e19f0 100644 --- a/src/org/kar/archidata/dataAccess/DataAccess.java +++ b/src/org/kar/archidata/dataAccess/DataAccess.java @@ -174,7 +174,7 @@ public class DataAccess { throw new InternalServerErrorException("Can Not manage the DB-access"); } - /** extract a list of "-" separated element from a SQL input data. + /** Extract a list of Long with "-" separated element from a SQL input data. * @param rs Result Set of the BDD * @param iii Id in the result set * @return The list of Long value @@ -185,7 +185,7 @@ public class DataAccess { return null; } final List out = new ArrayList<>(); - final String[] elements = trackString.split("-"); + final String[] elements = trackString.split(separator); for (final String elem : elements) { final Long tmp = Long.parseLong(elem); out.add(tmp); @@ -193,6 +193,25 @@ public class DataAccess { return out; } + /** Extract a list of UUID with "-" separated element from a SQL input data. + * @param rs Result Set of the BDD + * @param iii Id in the result set + * @return The list of Long value + * @throws SQLException if an error is generated in the SQL request. */ + public static List getListOfUUIDs(final ResultSet rs, final int iii, final String separator) throws SQLException { + final String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + final List out = new ArrayList<>(); + final String[] elements = trackString.split(separator); + for (final String elem : elements) { + final UUID tmp = UUID.fromString(elem); + out.add(tmp); + } + return out; + } + protected static void setValuedb(final Class type, final T data, final CountInOut iii, final Field field, final PreparedStatement ps) throws Exception { if (type == UUID.class) { final Object tmp = field.get(data); @@ -930,7 +949,11 @@ public class DataAccess { final List asyncActions = new ArrayList<>(); for (final Field field : asyncFieldUpdate) { final DataAccessAddOn addOn = findAddOnforField(field); - addOn.asyncInsert(tableName, uniqueSQLID, field, field.get(data), asyncActions); + if (uniqueSQLID != null) { + addOn.asyncInsert(tableName, uniqueSQLID, field, field.get(data), asyncActions); + } else if (uniqueSQLUUID != null) { + addOn.asyncInsert(tableName, uniqueSQLUUID, field, field.get(data), asyncActions); + } } for (final LazyGetter action : asyncActions) { action.doRequest(); diff --git a/src/org/kar/archidata/dataAccess/DataAccessAddOn.java b/src/org/kar/archidata/dataAccess/DataAccessAddOn.java index a2d5c77..80acfad 100644 --- a/src/org/kar/archidata/dataAccess/DataAccessAddOn.java +++ b/src/org/kar/archidata/dataAccess/DataAccessAddOn.java @@ -61,8 +61,17 @@ public interface DataAccessAddOn { * @param createDrop * @param fieldId * @throws Exception */ - void createTables(String tableName, Field field, StringBuilder mainTableBuilder, List preActionList, List postActionList, boolean createIfNotExist, boolean createDrop, int fieldId) - throws Exception; + void createTables(// + String tableName, // + final Field primaryField, // + Field field, // + StringBuilder mainTableBuilder, // + List preActionList, // + List postActionList, // + boolean createIfNotExist, // + boolean createDrop, // + int fieldId // + ) throws Exception; /** Some action must be done asynchronously for update or remove element * @param field diff --git a/src/org/kar/archidata/dataAccess/DataFactory.java b/src/org/kar/archidata/dataAccess/DataFactory.java index ef44808..6a3ac22 100644 --- a/src/org/kar/archidata/dataAccess/DataFactory.java +++ b/src/org/kar/archidata/dataAccess/DataFactory.java @@ -339,6 +339,7 @@ public class DataFactory { LOGGER.debug("===> TABLE `{}`", tableName); final List primaryKeys = new ArrayList<>(); + final Field primaryField = AnnotationTools.getPrimaryKeyField(clazz); for (final Field elem : clazz.getFields()) { // DEtect the primary key (support only one primary key right now... if (AnnotationTools.isPrimaryKey(elem)) { @@ -373,7 +374,7 @@ public class DataFactory { final DataAccessAddOn addOn = DataAccess.findAddOnforField(elem); LOGGER.trace("Create type for: {} ==> {} (ADD-ON)", AnnotationTools.getFieldName(elem), elem.getType()); if (addOn != null) { - addOn.createTables(tableName, elem, tmpOut, preActionList, postActionList, createIfNotExist, createDrop, fieldId); + addOn.createTables(tableName, primaryField, elem, tmpOut, preActionList, postActionList, createIfNotExist, createDrop, fieldId); } else { throw new DataAccessException( "Element matked as add-on but add-on does not loaded: table:" + tableName + " field name=" + AnnotationTools.getFieldName(elem) + " type=" + elem.getType()); diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java b/src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java index c655d72..afbda00 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnDataJson.java @@ -141,8 +141,17 @@ public class AddOnDataJson implements DataAccessAddOn { } @Override - public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, - final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { + public void createTables(// + final String tableName, // + final Field primaryField, // + final Field field, // + final StringBuilder mainTableBuilder, // + final List preActionList, // + final List postActionList, // + final boolean createIfNotExist, // + final boolean createDrop, // + final int fieldId // + ) throws Exception { DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, JsonValue.class); } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java index ed782f4..c84e038 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java @@ -7,6 +7,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.dataAccess.CountInOut; @@ -18,7 +19,10 @@ import org.kar.archidata.dataAccess.QueryAnd; import org.kar.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryInList; import org.kar.archidata.dataAccess.QueryOptions; -import org.kar.archidata.dataAccess.addOn.model.LinkTable; +import org.kar.archidata.dataAccess.addOn.model.LinkTableLongLong; +import org.kar.archidata.dataAccess.addOn.model.LinkTableLongUUID; +import org.kar.archidata.dataAccess.addOn.model.LinkTableUUIDLong; +import org.kar.archidata.dataAccess.addOn.model.LinkTableUUIDUUID; import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.OverrideTableName; import org.kar.archidata.exception.DataAccessException; @@ -32,7 +36,8 @@ import jakarta.validation.constraints.NotNull; public class AddOnManyToMany implements DataAccessAddOn { static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); - static final String SEPARATOR = "-"; + static final String SEPARATOR_LONG = "-"; + static final String SEPARATOR_UUID = "_"; @Override public Class getAnnotationClass() { @@ -62,7 +67,15 @@ public class AddOnManyToMany implements DataAccessAddOn { @Override public boolean canRetrieve(final Field field) { - return true; + if (field.getType() != List.class) { + return false; + } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + if (objectClass == Long.class || objectClass == UUID.class) { + return true; + } else { + return false; + } } public static String generateLinkTableNameField(final String tableName, final Field field) throws Exception { @@ -78,21 +91,39 @@ public class AddOnManyToMany implements DataAccessAddOn { return tableName + "_link_" + localName; } - public void generateConcatQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, - @NotNull final String name, @NotNull final CountInOut elemCount, final QueryOptions options) { - + public void generateConcatQuerry( // + @NotNull final String tableName, // + @NotNull final Field field, // + @NotNull final StringBuilder querrySelect, // + @NotNull final StringBuilder querry, // + @NotNull final String name, // + @NotNull final CountInOut elemCount, // + final QueryOptions options// + ) { final String linkTableName = generateLinkTableName(tableName, name); + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; final String tmpVariable = "tmp_" + Integer.toString(elemCount.value); querrySelect.append(" (SELECT GROUP_CONCAT("); - querrySelect.append(tmpVariable); - querrySelect.append(".object2Id "); + if (objectClass == Long.class) { + querrySelect.append(tmpVariable); + querrySelect.append(".object2Id "); + } else { + querrySelect.append("BIN_TO_UUID("); + querrySelect.append(tmpVariable); + querrySelect.append(".object2Id) "); + } if ("sqlite".equals(ConfigBaseVariable.getDBType())) { querrySelect.append(", "); } else { querrySelect.append("SEPARATOR "); } querrySelect.append("'"); - querrySelect.append(SEPARATOR); + if (objectClass == Long.class) { + querrySelect.append(SEPARATOR_LONG); + } else { + querrySelect.append(SEPARATOR_UUID); + + } querrySelect.append("') FROM "); querrySelect.append(linkTableName); querrySelect.append(" "); @@ -118,13 +149,20 @@ public class AddOnManyToMany implements DataAccessAddOn { } @Override - public void generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull final String name, - @NotNull final CountInOut elemCount, final QueryOptions options) throws Exception { + public void generateQuerry( // + @NotNull final String tableName, // + @NotNull final Field field, // + @NotNull final StringBuilder querrySelect, // + @NotNull final StringBuilder querry, // + @NotNull final String name, // + @NotNull final CountInOut elemCount, // + final QueryOptions options // + ) throws Exception { if (field.getType() != List.class) { return; } final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; - if (objectClass == Long.class) { + if (objectClass == Long.class || objectClass == UUID.class) { generateConcatQuerry(tableName, field, querrySelect, querry, name, elemCount, options); } final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class); @@ -141,20 +179,29 @@ public class AddOnManyToMany implements DataAccessAddOn { } @Override - public void fillFromQuerry(final ResultSet rs, final Field field, final Object data, final CountInOut count, final QueryOptions options, final List lazyCall) throws Exception { + public void fillFromQuerry( // + final ResultSet rs, // + final Field field, // + final Object data, // + final CountInOut count, // + final QueryOptions options, // + final List lazyCall // + ) throws Exception { if (field.getType() != List.class) { LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName()); return; } final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; if (objectClass == Long.class) { - final List idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR); + final List idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG); + field.set(data, idList); + count.inc(); + return; + } else if (objectClass == UUID.class) { + final List idList = DataAccess.getListOfUUIDs(rs, count.value, SEPARATOR_UUID); field.set(data, idList); count.inc(); return; - // } else { - // LOGGER.error("Can not ManyToMany with other than List Model: List<{}>", objectClass.getCanonicalName()); - // return; } final ManyToMany decorators = field.getDeclaredAnnotation(ManyToMany.class); if (decorators == null) { @@ -163,8 +210,8 @@ public class AddOnManyToMany implements DataAccessAddOn { if (objectClass == decorators.targetEntity()) { if (decorators.fetch() == FetchType.EAGER) { throw new DataAccessException("EAGER is not supported for list of element..."); - } else { - final List idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR); + } else if (objectClass == Long.class) { + final List idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR_LONG); // field.set(data, idList); count.inc(); if (idList != null && idList.size() > 0) { @@ -182,6 +229,25 @@ public class AddOnManyToMany implements DataAccessAddOn { }; lazyCall.add(lambda); } + } else if (objectClass == UUID.class) { + final List idList = DataAccess.getListOfUUIDs(rs, count.value, SEPARATOR_UUID); + // field.set(data, idList); + count.inc(); + if (idList != null && idList.size() > 0) { + final String idField = AnnotationTools.getFieldName(AnnotationTools.getIdField(objectClass)); + // In the lazy mode, the request is done in asynchronous mode, they will be done after... + final LazyGetter lambda = () -> { + final List childs = new ArrayList<>(idList); + // TODO: update to have get with abstract types .... + @SuppressWarnings("unchecked") + final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), new Condition(new QueryInList<>(idField, childs))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } } } } @@ -197,12 +263,38 @@ public class AddOnManyToMany implements DataAccessAddOn { LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName()); return; } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + objectClass.getCanonicalName() + ">"); + } final String columnName = AnnotationTools.getFieldName(field); final String linkTableName = generateLinkTableName(tableName, columnName); - actions.add(() -> { - DataAccess.deleteWhere(LinkTable.class, new OverrideTableName(linkTableName), new Condition(new QueryCondition("object1Id", "=", localKey))); - }); - asyncInsert(tableName, localKey, field, data, actions); + + if (localKey instanceof final Long localKeyLong) { + if (objectClass == Long.class) { + actions.add(() -> { + DataAccess.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName), new Condition(new QueryCondition("object1Id", "=", localKeyLong))); + }); + asyncInsert(tableName, localKey, field, data, actions); + } else { + actions.add(() -> { + DataAccess.deleteWhere(LinkTableLongUUID.class, new OverrideTableName(linkTableName), new Condition(new QueryCondition("object1Id", "=", localKeyLong))); + }); + asyncInsert(tableName, localKey, field, data, actions); + } + } else if (localKey instanceof final UUID localKeyUUID) { + if (objectClass == Long.class) { + actions.add(() -> { + DataAccess.deleteWhere(LinkTableUUIDLong.class, new OverrideTableName(linkTableName), new Condition(new QueryCondition("object1Id", "=", localKeyUUID))); + }); + asyncInsert(tableName, localKey, field, data, actions); + } else { + actions.add(() -> { + DataAccess.deleteWhere(LinkTableUUIDUUID.class, new OverrideTableName(linkTableName), new Condition(new QueryCondition("object1Id", "=", localKeyUUID))); + }); + asyncInsert(tableName, localKey, field, data, actions); + } + } } @Override @@ -219,56 +311,142 @@ public class AddOnManyToMany implements DataAccessAddOn { LOGGER.error("Can not ManyToMany with other than List Model: {}", field.getType().getCanonicalName()); return; } + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + objectClass.getCanonicalName() + ">"); + } final String columnName = AnnotationTools.getFieldName(field); final String linkTableName = generateLinkTableName(tableName, columnName); - final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; - if (objectClass != Long.class) { - LOGGER.error("Can not ManyToMany with other than List Model: List<{}>", objectClass.getCanonicalName()); - return; - } - @SuppressWarnings("unchecked") - final List dataCasted = (List) data; - if (dataCasted.size() == 0) { - return; - } - final List insertElements = new ArrayList<>(); - for (final Long remoteKey : dataCasted) { - if (remoteKey == null) { - throw new DataAccessException("Try to insert remote key with null value"); - } - if (localKey instanceof final Long localKeyLong) { - insertElements.add(new LinkTable(localKeyLong, remoteKey)); + if (localKey instanceof final Long localKeyLong) { + if (objectClass == Long.class) { + // ======================================================== + // == Link a "Long" primary Key with List + // ======================================================== + @SuppressWarnings("unchecked") + final List dataCasted = (List) data; + if (dataCasted.size() == 0) { + return; + } + final List insertElements = new ArrayList<>(); + for (final Long remoteKey : dataCasted) { + if (remoteKey == null) { + throw new DataAccessException("Try to insert remote key with null value"); + } + insertElements.add(new LinkTableLongLong(localKeyLong, remoteKey)); + } + if (insertElements.size() == 0) { + LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); + return; + } + actions.add(() -> { + DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + }); } else { - throw new DataAccessException("Not manage access of remte key like ManyToMany other than Long: " + localKey.getClass().getCanonicalName()); + // ======================================================== + // == Link a "Long" primary Key with List + // ======================================================== + @SuppressWarnings("unchecked") + final List dataCasted = (List) data; + if (dataCasted.size() == 0) { + return; + } + final List insertElements = new ArrayList<>(); + for (final UUID remoteKey : dataCasted) { + if (remoteKey == null) { + throw new DataAccessException("Try to insert remote key with null value"); + } + insertElements.add(new LinkTableLongUUID(localKeyLong, remoteKey)); + } + if (insertElements.size() == 0) { + LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); + return; + } + actions.add(() -> { + DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + }); } + } else if (localKey instanceof final UUID localKeyUUID) { + if (objectClass == Long.class) { + // ======================================================== + // == Link a "UUID" primary Key with List + // ======================================================== + @SuppressWarnings("unchecked") + final List dataCasted = (List) data; + if (dataCasted.size() == 0) { + return; + } + final List insertElements = new ArrayList<>(); + for (final Long remoteKey : dataCasted) { + if (remoteKey == null) { + throw new DataAccessException("Try to insert remote key with null value"); + } + insertElements.add(new LinkTableUUIDLong(localKeyUUID, remoteKey)); + } + if (insertElements.size() == 0) { + LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); + return; + } + actions.add(() -> { + DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + }); + } else { + // ======================================================== + // == Link a "UUID" primary Key with List + // ======================================================== + @SuppressWarnings("unchecked") + final List dataCasted = (List) data; + if (dataCasted.size() == 0) { + return; + } + final List insertElements = new ArrayList<>(); + for (final UUID remoteKey : dataCasted) { + if (remoteKey == null) { + throw new DataAccessException("Try to insert remote key with null value"); + } + insertElements.add(new LinkTableUUIDUUID(localKeyUUID, remoteKey)); + } + if (insertElements.size() == 0) { + LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); + return; + } + actions.add(() -> { + DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); + }); + } + } else { + throw new DataAccessException("Not manage access of remte key like ManyToMany other than Long or UUID: " + localKey.getClass().getCanonicalName()); } - if (insertElements.size() == 0) { - LOGGER.warn("Insert multiple link without any value (may have null in the list): {}", dataCasted); - return; - } - actions.add(() -> { - DataAccess.insertMultiple(insertElements, new OverrideTableName(linkTableName)); - }); + } @Override public void drop(final String tableName, final Field field) throws Exception { final String columnName = AnnotationTools.getFieldName(field); final String linkTableName = generateLinkTableName(tableName, columnName); - DataAccess.drop(LinkTable.class, new OverrideTableName(linkTableName)); + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + objectClass.getCanonicalName() + ">"); + } + DataAccess.drop(LinkTableLongLong.class, new OverrideTableName(linkTableName)); } @Override public void cleanAll(final String tableName, final Field field) throws Exception { final String columnName = AnnotationTools.getFieldName(field); final String linkTableName = generateLinkTableName(tableName, columnName); - DataAccess.cleanAll(LinkTable.class, new OverrideTableName(linkTableName)); + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + objectClass.getCanonicalName() + ">"); + } + DataAccess.cleanAll(LinkTableLongLong.class, new OverrideTableName(linkTableName)); } public static void addLink(final Class clazz, final long localKey, final String column, final long remoteKey) throws Exception { final String tableName = AnnotationTools.getTableName(clazz); final String linkTableName = generateLinkTableName(tableName, column); - final LinkTable insertElement = new LinkTable(localKey, remoteKey); + /* final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; if (objectClass != Long.class && objectClass != UUID.class) { throw new + * DataAccessException("Can not ManyToMany with other than List or List Model: List<" + objectClass.getCanonicalName() + ">"); } */ + final LinkTableLongLong insertElement = new LinkTableLongLong(localKey, remoteKey); DataAccess.insert(insertElement, new OverrideTableName(linkTableName)); } @@ -276,16 +454,48 @@ public class AddOnManyToMany implements DataAccessAddOn { public static int removeLink(final Class clazz, final long localKey, final String column, final long remoteKey) throws Exception { final String tableName = AnnotationTools.getTableName(clazz); final String linkTableName = generateLinkTableName(tableName, column); - return DataAccess.deleteWhere(LinkTable.class, new OverrideTableName(linkTableName), + return DataAccess.deleteWhere(LinkTableLongLong.class, new OverrideTableName(linkTableName), new Condition(new QueryAnd(new QueryCondition("object1Id", "=", localKey), new QueryCondition("object2Id", "=", remoteKey)))); } @Override - public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, - final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { + public void createTables( // + final String tableName, // + final Field primaryField, // + final Field field, // + final StringBuilder mainTableBuilder, // + final List preActionList, // + final List postActionList, // + final boolean createIfNotExist, // + final boolean createDrop, // + final int fieldId// + ) throws Exception { final String linkTableName = generateLinkTableNameField(tableName, field); final QueryOptions options = new QueryOptions(new OverrideTableName(linkTableName)); - final List sqlCommand = DataFactory.createTable(LinkTable.class, options); - postActionList.addAll(sqlCommand); + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; + if (objectClass != Long.class && objectClass != UUID.class) { + throw new DataAccessException("Can not ManyToMany with other than List or List Model: List<" + objectClass.getCanonicalName() + ">"); + } + final Class primaryType = primaryField.getType(); + if (primaryType == Long.class) { + if (objectClass == Long.class) { + final List sqlCommand = DataFactory.createTable(LinkTableLongLong.class, options); + postActionList.addAll(sqlCommand); + } else { + final List sqlCommand = DataFactory.createTable(LinkTableLongUUID.class, options); + postActionList.addAll(sqlCommand); + } + } else if (primaryType == UUID.class) { + + if (objectClass == Long.class) { + final List sqlCommand = DataFactory.createTable(LinkTableUUIDLong.class, options); + postActionList.addAll(sqlCommand); + } else { + final List sqlCommand = DataFactory.createTable(LinkTableUUIDUUID.class, options); + postActionList.addAll(sqlCommand); + } + } else { + throw new DataAccessException("Can not ManyToMany with other than primary key type Long or UUID Model: " + primaryType.getCanonicalName()); + } } } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java index d28f562..c6697f6 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java @@ -32,12 +32,11 @@ public class AddOnManyToOne implements DataAccessAddOn { } @Override - public String getSQLFieldType(final Field elem) throws Exception { - final String fieldName = AnnotationTools.getFieldName(elem); + public String getSQLFieldType(final Field field) throws Exception { + final String fieldName = AnnotationTools.getFieldName(field); try { - return DataFactory.convertTypeInSQL(Long.class, fieldName); + return DataFactory.convertTypeInSQL(field.getType(), fieldName); } catch (final Exception e) { - // TODO Auto-generated catch block e.printStackTrace(); } return null; @@ -45,8 +44,7 @@ public class AddOnManyToOne implements DataAccessAddOn { @Override public boolean isCompatibleField(final Field elem) { - final ManyToOne decorators = elem.getDeclaredAnnotation(ManyToOne.class); - return decorators != null; + return elem.getDeclaredAnnotation(ManyToOne.class) != null; } @Override @@ -78,6 +76,7 @@ public class AddOnManyToOne implements DataAccessAddOn { ps.setString(iii.value, dataTyped); } else if (field.getType() == UUID.class) { final UUID dataTyped = (UUID) data; + LOGGER.info("Generate UUTD for DB: {}", dataTyped); final byte[] dataByte = UuidUtils.asBytes(dataTyped); ps.setBytes(iii.value, dataByte); } else { @@ -96,7 +95,11 @@ public class AddOnManyToOne implements DataAccessAddOn { @Override public boolean canInsert(final Field field) { - if (field.getType() == Long.class || field.getType() == Integer.class || field.getType() == Short.class || field.getType() == String.class || field.getType() == UUID.class) { + if (field.getType() == Long.class // + || field.getType() == Integer.class // + || field.getType() == Short.class // + || field.getType() == String.class // + || field.getType() == UUID.class) { return true; } final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); @@ -113,7 +116,12 @@ public class AddOnManyToOne implements DataAccessAddOn { @Override public boolean canRetrieve(final Field field) { - if (field.getType() == Long.class || field.getType() == Integer.class || field.getType() == Short.class || field.getType() == String.class || field.getType() == UUID.class) { + final Class classType = field.getType(); + if (classType == Long.class // + || classType == Integer.class // + || classType == Short.class // + || classType == String.class // + || classType == UUID.class) { return true; } final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); @@ -124,9 +132,20 @@ public class AddOnManyToOne implements DataAccessAddOn { } @Override - public void generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querrySelect, @NotNull final StringBuilder querry, @NotNull final String name, - @NotNull final CountInOut elemCount, final QueryOptions options) throws Exception { - if (field.getType() == Long.class || field.getType() == Integer.class || field.getType() == Short.class || field.getType() == String.class || field.getType() == UUID.class) { + public void generateQuerry( // + @NotNull final String tableName, // + @NotNull final Field field, // + @NotNull final StringBuilder querrySelect, // + @NotNull final StringBuilder querry, // + @NotNull final String name, // + @NotNull final CountInOut elemCount, // + final QueryOptions options// + ) throws Exception { + if (field.getType() == Long.class // + || field.getType() == Integer.class // + || field.getType() == Short.class // + || field.getType() == String.class // + || field.getType() == UUID.class) { querrySelect.append(" "); querrySelect.append(tableName); querrySelect.append("."); @@ -242,8 +261,27 @@ public class AddOnManyToOne implements DataAccessAddOn { // TODO : refacto this table to manage a generic table with dynamic name to be serialisable with the default system @Override - public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, - final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { - DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, Long.class); + public void createTables(// + final String tableName, // + final Field primaryField, // + final Field field, // + final StringBuilder mainTableBuilder, // + final List preActionList, // + final List postActionList, // + final boolean createIfNotExist, // + final boolean createDrop, // + final int fieldId // + ) throws Exception { + final Class classType = field.getType(); + if (classType == Long.class // + || classType == Integer.class // + || classType == Short.class // + || classType == String.class // + || classType == UUID.class) { + DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, classType); + } else { + LOGGER.error("Support only the Long remote field of ecternal primary keys..."); + DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, Long.class); + } } } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java b/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java index 1b9655c..be8deae 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java @@ -125,8 +125,17 @@ public class AddOnOneToMany implements DataAccessAddOn { // TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system @Override - public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, - final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { + public void createTables(// + final String tableName, // + final Field primaryField, // + final Field field, // + final StringBuilder mainTableBuilder, // + final List preActionList, // + final List postActionList, // + final boolean createIfNotExist, // + final boolean createDrop, // + final int fieldId // + ) throws Exception { DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, Long.class); } } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java b/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java index a50a9dc..0485004 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java @@ -105,8 +105,17 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn { } @Override - public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, - final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { + public void createTables(// + final String tableName, // + final Field primaryField, // + final Field field, // + final StringBuilder mainTableBuilder, // + final List preActionList, // + final List postActionList, // + final boolean createIfNotExist, // + final boolean createDrop, // + final int fieldId // + ) throws Exception { // TODO Auto-generated method stub DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, String.class); diff --git a/src/org/kar/archidata/dataAccess/addOn/model/LinkTable.java b/src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongLong.java similarity index 75% rename from src/org/kar/archidata/dataAccess/addOn/model/LinkTable.java rename to src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongLong.java index 15dcd5b..b5ef1f6 100644 --- a/src/org/kar/archidata/dataAccess/addOn/model/LinkTable.java +++ b/src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongLong.java @@ -5,12 +5,12 @@ import org.kar.archidata.model.GenericData; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.Column; -public class LinkTable extends GenericData { - public LinkTable() { +public class LinkTableLongLong extends GenericData { + public LinkTableLongLong() { // nothing to do... } - public LinkTable(final long object1Id, final long object2Id) { + public LinkTableLongLong(final long object1Id, final long object2Id) { this.object1Id = object1Id; this.object2Id = object2Id; } diff --git a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongUUID.java b/src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongUUID.java new file mode 100644 index 0000000..8f76c49 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOn/model/LinkTableLongUUID.java @@ -0,0 +1,27 @@ +package org.kar.archidata.dataAccess.addOn.model; + +import java.util.UUID; + +import org.kar.archidata.model.GenericData; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.persistence.Column; + +public class LinkTableLongUUID extends GenericData { + public LinkTableLongUUID() { + // nothing to do... + } + + public LinkTableLongUUID(final long object1Id, final UUID object2Id) { + this.object1Id = object1Id; + this.object2Id = object2Id; + } + + @Schema(description = "Object reference 1") + @Column(nullable = false) + public Long object1Id; + @Schema(description = "Object reference 2") + @Column(nullable = false) + public UUID object2Id; + +} diff --git a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDLong.java b/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDLong.java new file mode 100644 index 0000000..944f20f --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDLong.java @@ -0,0 +1,27 @@ +package org.kar.archidata.dataAccess.addOn.model; + +import java.util.UUID; + +import org.kar.archidata.model.GenericData; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.persistence.Column; + +public class LinkTableUUIDLong extends GenericData { + public LinkTableUUIDLong() { + // nothing to do... + } + + public LinkTableUUIDLong(final UUID object1Id, final long object2Id) { + this.object1Id = object1Id; + this.object2Id = object2Id; + } + + @Schema(description = "Object reference 1") + @Column(nullable = false) + public UUID object1Id; + @Schema(description = "Object reference 2") + @Column(nullable = false) + public Long object2Id; + +} diff --git a/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDUUID.java b/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDUUID.java new file mode 100644 index 0000000..0f2b396 --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOn/model/LinkTableUUIDUUID.java @@ -0,0 +1,27 @@ +package org.kar.archidata.dataAccess.addOn.model; + +import java.util.UUID; + +import org.kar.archidata.model.GenericData; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.persistence.Column; + +public class LinkTableUUIDUUID extends GenericData { + public LinkTableUUIDUUID() { + // nothing to do... + } + + public LinkTableUUIDUUID(final UUID object1Id, final UUID object2Id) { + this.object1Id = object1Id; + this.object2Id = object2Id; + } + + @Schema(description = "Object reference 1") + @Column(nullable = false) + public UUID object1Id; + @Schema(description = "Object reference 2") + @Column(nullable = false) + public UUID object2Id; + +} diff --git a/src/org/kar/archidata/dataAccess/options/CheckJPA.java b/src/org/kar/archidata/dataAccess/options/CheckJPA.java index db3baf7..f790786 100644 --- a/src/org/kar/archidata/dataAccess/options/CheckJPA.java +++ b/src/org/kar/archidata/dataAccess/options/CheckJPA.java @@ -9,6 +9,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.regex.Pattern; import org.kar.archidata.annotation.AnnotationTools; @@ -125,7 +126,6 @@ public class CheckJPA implements CheckFunctionInterface { } } else if (type == Integer.class || type == int.class) { - final Long maxValueRoot = AnnotationTools.getConstraintsMax(field); if (maxValueRoot != null) { final int maxValue = maxValueRoot.intValue(); @@ -167,6 +167,20 @@ public class CheckJPA implements CheckFunctionInterface { } }); } + } else if (type == UUID.class) { + final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field); + if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) { + add(fieldName, (final String baseName, final T data) -> { + final Object elem = field.get(data); + if (elem == null) { + return; + } + final long count = DataAccess.count(annotationManyToOne.targetEntity(), elem); + if (count == 0) { + throw new InputException(baseName + fieldName, "Foreign element does not exist in the DB:" + elem); + } + }); + } } else if (type == Boolean.class || type == boolean.class) { } else if (type == Float.class || type == float.class) {