From 7b72b08fc06a2ebbe00bf1dfcaa62b6bee609e62 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Wed, 29 May 2024 20:16:48 +0200 Subject: [PATCH] [FEAT] permit a better support of @OneToMany --- .../kar/archidata/dataAccess/DataAccess.java | 4 +- .../dataAccess/addOn/AddOnOneToMany.java | 107 ++++++++++++-- .../AddOnSQLTableExternalForeinKeyAsList.java | 136 ------------------ src/org/kar/archidata/tools/RESTApi.java | 1 + 4 files changed, 99 insertions(+), 149 deletions(-) delete mode 100644 src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java diff --git a/src/org/kar/archidata/dataAccess/DataAccess.java b/src/org/kar/archidata/dataAccess/DataAccess.java index a10b325..75a8778 100644 --- a/src/org/kar/archidata/dataAccess/DataAccess.java +++ b/src/org/kar/archidata/dataAccess/DataAccess.java @@ -25,7 +25,7 @@ import org.kar.archidata.annotation.UpdateTimestamp; import org.kar.archidata.dataAccess.addOn.AddOnDataJson; import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.dataAccess.addOn.AddOnManyToOne; -import org.kar.archidata.dataAccess.addOn.AddOnSQLTableExternalForeinKeyAsList; +import org.kar.archidata.dataAccess.addOn.AddOnOneToMany; import org.kar.archidata.dataAccess.options.CheckFunction; import org.kar.archidata.dataAccess.options.Condition; import org.kar.archidata.dataAccess.options.DBInterfaceOption; @@ -64,7 +64,7 @@ public class DataAccess { static { addOn.add(new AddOnManyToMany()); addOn.add(new AddOnManyToOne()); - addOn.add(new AddOnSQLTableExternalForeinKeyAsList()); + addOn.add(new AddOnOneToMany()); addOn.add(new AddOnDataJson()); } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java b/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java index f682351..beb8455 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java @@ -1,28 +1,36 @@ package org.kar.archidata.dataAccess.addOn; import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; import org.kar.archidata.annotation.AnnotationTools; import org.kar.archidata.dataAccess.CountInOut; +import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccessAddOn; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.LazyGetter; +import org.kar.archidata.dataAccess.QueryCondition; import org.kar.archidata.dataAccess.QueryOptions; +import org.kar.archidata.dataAccess.options.Condition; +import org.kar.archidata.exception.DataAccessException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.persistence.FetchType; import jakarta.persistence.OneToMany; import jakarta.validation.constraints.NotNull; public class AddOnOneToMany implements DataAccessAddOn { - static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); + static final Logger LOGGER = LoggerFactory.getLogger(AddOnOneToMany.class); + static final String SEPARATOR_LONG = "-"; /** Convert the list if external id in a string '-' separated * @param ids List of value (null are removed) @@ -100,6 +108,21 @@ public class AddOnOneToMany implements DataAccessAddOn { @Override public boolean canRetrieve(final Field field) { + 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; + } + final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class); + if (decorators == null) { + return false; + } + if (decorators.targetEntity() == objectClass) { + return true; + } return false; } @@ -113,11 +136,16 @@ public class AddOnOneToMany implements DataAccessAddOn { @NotNull final String name, @NotNull final CountInOut count, final QueryOptions options) { + if (field.getType() != List.class) { + return; + } + // Force a copy of the primaryKey to permit the async retrieve of the data querySelect.append(" "); querySelect.append(tableName); querySelect.append("."); - querySelect.append(name); - count.inc(); + querySelect.append(primaryKey); + querySelect.append(" AS tmp_"); + querySelect.append(Integer.toString(count.value)); } @Override @@ -127,16 +155,74 @@ public class AddOnOneToMany implements DataAccessAddOn { final Object data, final CountInOut count, final QueryOptions options, - final List lazyCall) throws SQLException, IllegalArgumentException, IllegalAccessException { - final Long foreignKey = rs.getLong(count.value); - count.inc(); - if (!rs.wasNull()) { + final List lazyCall) throws Exception { + if (field.getType() != List.class) { + LOGGER.error("Can not OneToMany with other than List Model: {}", field.getType().getCanonicalName()); + return; + } - field.set(data, foreignKey); + Long parentIdTmp = null; + UUID parendUuidTmp = null; + try { + final String modelData = rs.getString(count.value); + parentIdTmp = Long.valueOf(modelData); + count.inc(); + } catch (final NumberFormatException ex) { + final List idList = DataAccess.getListOfRawUUIDs(rs, count.value); + parendUuidTmp = idList.get(0); + count.inc(); + } + final Long parentId = parentIdTmp; + final UUID parendUuid = parendUuidTmp; + final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class); + if (decorators == null) { + return; + } + final String mappingKey = decorators.mappedBy(); + // We get the parent ID ... ==> need to request the list of elements + + final Class objectClass = (Class) ((ParameterizedType) field.getGenericType()) + .getActualTypeArguments()[0]; + if (objectClass == Long.class) { + LOGGER.error("Need to retreive all primary key of all elements"); + //field.set(data, idList); + return; + } else if (objectClass == UUID.class) { + LOGGER.error("Need to retreive all primary key of all elements"); + //field.set(data, idList); + return; + } + if (objectClass == decorators.targetEntity()) { + if (decorators.fetch() == FetchType.EAGER) { + throw new DataAccessException("EAGER is not supported for list of element..."); + } else if (parentId != null) { + // In the lazy mode, the request is done in asynchronous mode, they will be done after... + final LazyGetter lambda = () -> { + @SuppressWarnings("unchecked") + final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), + new Condition(new QueryCondition(mappingKey, "=", parentId))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } else if (parendUuid != null) { + final LazyGetter lambda = () -> { + @SuppressWarnings("unchecked") + final Object foreignData = DataAccess.getsWhere(decorators.targetEntity(), + new Condition(new QueryCondition(mappingKey, "=", parendUuid))); + if (foreignData == null) { + return; + } + field.set(data, foreignData); + }; + lazyCall.add(lambda); + } } } - // TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system + // TODO : refacto this table to manage a generic table with dynamic name to be serialize with the default system @Override public void createTables( final String tableName, @@ -148,7 +234,6 @@ public class AddOnOneToMany implements DataAccessAddOn { final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { - DataFactory.createTablesSpecificType(tableName, primaryField, field, mainTableBuilder, preActionList, - postActionList, createIfNotExist, createDrop, fieldId, Long.class); + // This is a remote field ==> nothing to generate (it is stored in the remote object } } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java b/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java deleted file mode 100644 index 8d51d23..0000000 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.kar.archidata.dataAccess.addOn; - -import java.lang.reflect.Field; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.kar.archidata.annotation.AnnotationTools; -import org.kar.archidata.annotation.addOn.SQLTableExternalForeinKeyAsList; -import org.kar.archidata.dataAccess.CountInOut; -import org.kar.archidata.dataAccess.DataAccess; -import org.kar.archidata.dataAccess.DataAccessAddOn; -import org.kar.archidata.dataAccess.DataFactory; -import org.kar.archidata.dataAccess.LazyGetter; -import org.kar.archidata.dataAccess.QueryOptions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import jakarta.validation.constraints.NotNull; - -// TODO: maybe deprecated ==> use DataJson instead... -@Deprecated -public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn { - static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); - static final String SEPARATOR = "-"; - - /** Convert the list if external id in a string '-' separated - * @param ids List of value (null are removed) - * @return '-' string separated */ - protected static String getStringOfIds(final List ids) { - final List tmp = new ArrayList<>(ids); - return tmp.stream().map(String::valueOf).collect(Collectors.joining(SEPARATOR)); - } - - @Override - public Class getAnnotationClass() { - return SQLTableExternalForeinKeyAsList.class; - } - - @Override - public String getSQLFieldType(final Field field) throws Exception { - final String fieldName = AnnotationTools.getFieldName(field); - try { - return DataFactory.convertTypeInSQL(String.class, fieldName); - } catch (final Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; - } - - @Override - public boolean isCompatibleField(final Field field) { - final SQLTableExternalForeinKeyAsList decorators = field - .getDeclaredAnnotation(SQLTableExternalForeinKeyAsList.class); - return decorators != null; - } - - @Override - public void insertData(final PreparedStatement ps, final Field field, final Object rootObject, final CountInOut iii) - throws SQLException, IllegalArgumentException, IllegalAccessException { - final Object data = field.get(rootObject); - iii.inc(); - if (data == null) { - ps.setNull(iii.value, Types.BIGINT); - } else { - @SuppressWarnings("unchecked") - final String dataTmp = getStringOfIds((List) data); - ps.setString(iii.value, dataTmp); - } - } - - @Override - public boolean canInsert(final Field field) { - return true; - } - - @Override - public boolean isInsertAsync(final Field field) throws Exception { - return false; - } - - @Override - public boolean canRetrieve(final Field field) { - return true; - } - - @Override - public void generateQuery( - @NotNull final String tableName, - @NotNull final String primaryKey, - @NotNull final Field field, - @NotNull final StringBuilder querySelect, - @NotNull final StringBuilder query, - @NotNull final String name, - @NotNull final CountInOut count, - final QueryOptions options) { - count.inc(); - querySelect.append(" "); - querySelect.append(tableName); - querySelect.append("."); - querySelect.append(name); - } - - @Override - public void fillFromQuery( - final ResultSet rs, - final Field field, - final Object data, - final CountInOut count, - final QueryOptions options, - final List lazyCall) throws SQLException, IllegalArgumentException, IllegalAccessException { - final List idList = DataAccess.getListOfIds(rs, count.value, SEPARATOR); - field.set(data, idList); - count.inc(); - } - - @Override - 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, primaryField, field, mainTableBuilder, preActionList, - postActionList, createIfNotExist, createDrop, fieldId, String.class); - } -} diff --git a/src/org/kar/archidata/tools/RESTApi.java b/src/org/kar/archidata/tools/RESTApi.java index 3238392..11d4e25 100644 --- a/src/org/kar/archidata/tools/RESTApi.java +++ b/src/org/kar/archidata/tools/RESTApi.java @@ -196,6 +196,7 @@ public class RESTApi { return this.mapper.readValue(httpResponse.body(), clazz); } + // TODO: add an API that permit to return a value public void delete(final Class clazz, final String urlOffset) throws RESTErrorResponseExeption, IOException, InterruptedException { final HttpClient client = HttpClient.newHttpClient();