-
Notifications
You must be signed in to change notification settings - Fork 96
[EDM] Add New Templates with Decorators #5575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
| let projectFile = { | ||
| "guid": parameters.projectName, | ||
| "actions": [] | ||
| } |
Check notice
Code scanning / CodeQL
Semicolon insertion Note
the enclosing function
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
In general, to fix this kind of issue, you add an explicit semicolon at the end of statements that currently depend on JavaScript’s automatic semicolon insertion. This makes the statement boundaries explicit and avoids subtle parsing differences if the code is refactored or minified.
For this specific case, the let projectFile = { ... } declaration in components/template/template-application-dao-v2/src/main/resources/META-INF/dirigible/template-application-dao-v2/project.json.mjs should be terminated with a semicolon immediately after the closing } of the object literal. Concretely, change line 9 from } to };. No other logic, imports, or definitions are needed, and this will not alter runtime behavior.
-
Copy modified line R9
| @@ -6,7 +6,7 @@ | ||
| let projectFile = { | ||
| "guid": parameters.projectName, | ||
| "actions": [] | ||
| } | ||
| }; | ||
| const newProjectFile = JSON.stringify(projectFile); | ||
|
|
||
| let currenctWorkspace = workspace.getWorkspace(parameters.workspaceName); |
| try (Session session = getSessionFactory().openSession()) { | ||
| Transaction transaction = session.beginTransaction(); | ||
| Object id = session.save(type, object); | ||
| Object id = session.save(type, data); |
Check notice
Code scanning / CodeQL
Deprecated method or constructor invocation Note
Session.save
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
In general, the way to fix this is to stop using the deprecated Session.save method and switch to a non-deprecated alternative that preserves the same behavior. For Hibernate, the common replacement for save is saveOrUpdate (which will insert when the entity is transient and update when it is detached), or persist if you know you are always inserting new instances. Since this method is used for generic “save” semantics and returns the identifier, the closest drop-in without changing higher-level behavior is session.saveOrUpdate, followed by retrieving the identifier from the session via session.getIdentifier.
Concretely, in DataStore.save(String type, Map<String, Object> object), on line 155 we should remove the call to session.save(type, data) and replace it with a session.saveOrUpdate(type, data) call. Because saveOrUpdate returns void (unlike save), we then need to obtain the identifier of the persisted entity by calling session.getIdentifier(data) after saveOrUpdate. We keep the transaction boundaries and method signature unchanged so that callers still receive the identifier object as before. No new imports are required, as we are still using the same Session and Transaction types.
-
Copy modified lines R155-R156
| @@ -152,7 +152,8 @@ | ||
| Map<String, Object> data = JsonTypeConverter.normalizeForEntity(object, type); | ||
| try (Session session = getSessionFactory().openSession()) { | ||
| Transaction transaction = session.beginTransaction(); | ||
| Object id = session.save(type, data); | ||
| session.saveOrUpdate(type, data); | ||
| Object id = session.getIdentifier(data); | ||
| transaction.commit(); | ||
| return id; | ||
| } |
| try (Session session = getSessionFactory().openSession()) { | ||
| Transaction transaction = session.beginTransaction(); | ||
| session.saveOrUpdate(type, object); | ||
| session.saveOrUpdate(type, data); |
Check notice
Code scanning / CodeQL
Deprecated method or constructor invocation Note
Session.saveOrUpdate
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
In general, the way to fix this issue is to replace calls to the deprecated Session.saveOrUpdate(...) API with the non-deprecated alternative recommended by Hibernate, typically Session.merge(...) (or other state transition methods like persist/update where appropriate). This preserves semantics while avoiding reliance on deprecated methods that might be removed.
For this specific code, upsert(String type, Map object) takes normalized entity data as a Map<String, Object> and then invokes session.saveOrUpdate(type, data). In Hibernate 5.2+ and 6.x, Session.merge(String entityName, Object object) is the non-deprecated analogue which either saves or updates the entity and returns the managed instance. To keep behavior the same and avoid deprecated APIs, we should change line 294 to call session.merge(type, data) instead of session.saveOrUpdate(type, data). The return value of merge is not used here, so we can ignore it. No additional imports are required since merge is already part of org.hibernate.Session. All other logic in the method (starting a transaction, committing, etc.) can remain unchanged.
Concretely:
- In
components/data/data-store/src/main/java/org/eclipse/dirigible/components/data/store/DataStore.java, locate theupsert(String type, Map object)method. - Replace
session.saveOrUpdate(type, data);withsession.merge(type, data);. - No other code or imports need to be changed.
-
Copy modified line R294
| @@ -291,7 +291,7 @@ | ||
|
|
||
| try (Session session = getSessionFactory().openSession()) { | ||
| Transaction transaction = session.beginTransaction(); | ||
| session.saveOrUpdate(type, data); | ||
| session.merge(type, data); | ||
| transaction.commit(); | ||
| } | ||
| } |
| try (Session session = getSessionFactory().openSession()) { | ||
| Transaction transaction = session.beginTransaction(); | ||
| session.update(type, object); | ||
| session.update(type, data); |
Check notice
Code scanning / CodeQL
Deprecated method or constructor invocation Note
Session.update
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
In general, to fix this issue you should stop calling the deprecated Session.update(String entityName, Object) method and instead either work with actual entity instances and call the non-deprecated Session.update(Object) or use another non-deprecated persistence mechanism (e.g., JPA EntityManager or explicit SQL). In this class, the store is designed around dynamic Map<String, Object> data and an entity-name string, which makes direct replacement with Session.update(Object) impractical without a larger redesign. The most targeted fix is to replace the deprecated call with an explicit native SQL UPDATE constructed from the data map and executed via Session.createNativeQuery, while still using the existing ParametersSetter utility for binding parameters.
Concretely, in DataStore.update(String type, Map object), instead of session.update(type, data), we will:
- Extract the
"id"(or primary key) fromdataand throw an exception if it is missing. - Build a
StringBuilderfor a statement likeUPDATE {type} SET col1 = :col1, col2 = :col2 ... WHERE id = :id. - Use
session.createNativeQuery(sql)to create aNativeQuery<?>. - Use
ParametersSetterto bind all non-id fields and the id field. - Execute the update via
executeUpdate()and commit the transaction.
This preserves the existing semantics of “update these fields for the given id” using the same normalized map, but no longer relies on the deprecated Hibernate method. It requires only modifying the body of the update(String type, Map object) method in DataStore.java and does not need new imports, since NativeQuery and ParametersSetter are already imported.
-
Copy modified lines R319-R342 -
Copy modified lines R345-R360
| @@ -316,9 +316,48 @@ | ||
| public void update(String type, Map object) { | ||
| Map<String, Object> data = JsonTypeConverter.normalizeForEntity(object, type); | ||
|
|
||
| // Expecting primary key under key "id" | ||
| Object idValue = data.get("id"); | ||
| if (idValue == null) { | ||
| throw new IllegalArgumentException("Missing primary key 'id' in data for update of type: " + type); | ||
| } | ||
|
|
||
| StringBuilder sqlBuilder = new StringBuilder(); | ||
| sqlBuilder.append("UPDATE ").append(type).append(" SET "); | ||
|
|
||
| boolean first = true; | ||
| for (String key : data.keySet()) { | ||
| if ("id".equals(key)) { | ||
| continue; | ||
| } | ||
| if (!first) { | ||
| sqlBuilder.append(", "); | ||
| } | ||
| sqlBuilder.append(key).append(" = :").append(key); | ||
| first = false; | ||
| } | ||
| sqlBuilder.append(" WHERE id = :id"); | ||
|
|
||
| String sql = sqlBuilder.toString(); | ||
|
|
||
| try (Session session = getSessionFactory().openSession()) { | ||
| Transaction transaction = session.beginTransaction(); | ||
| session.update(type, data); | ||
| NativeQuery<?> query = session.createNativeQuery(sql); | ||
|
|
||
| // Bind parameters for all fields except id | ||
| Map<String, Object> params = new HashMap<>(); | ||
| for (Map.Entry<String, Object> entry : data.entrySet()) { | ||
| String key = entry.getKey(); | ||
| if ("id".equals(key)) { | ||
| continue; | ||
| } | ||
| params.put(key, entry.getValue()); | ||
| } | ||
| // Bind id parameter | ||
| params.put("id", idValue); | ||
|
|
||
| ParametersSetter.setParameters(query, params); | ||
| query.executeUpdate(); | ||
| transaction.commit(); | ||
| } | ||
| } |
|
|
||
| String precisionValue = extractValue.apply(argText, "precision"); | ||
| if (precisionValue != null) | ||
| columnDetails.setPrecision(Integer.valueOf(precisionValue)); |
Check notice
Code scanning / CodeQL
Missing catch of NumberFormatException Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
In general, to fix this kind of problem, any conversion from a string to an integer (such as Integer.parseInt or Integer.valueOf) that operates on data derived from external or free-form input should be surrounded by a try/catch (NumberFormatException e) block, or otherwise validated before parsing. This allows the code to handle malformed values gracefully instead of throwing an uncaught runtime exception.
For this specific case in EntityParser.java, the best fix without changing existing functionality is to mirror the existing handling used for length. That is:
- Wrap
columnDetails.setPrecision(Integer.valueOf(precisionValue));in atry/catch (NumberFormatException e)block. - On failure, log or print a warning (consistent with the
lengthhandling), and skip setting the precision. - Do the same for
scaleValueandcolumnDetails.setScale(Integer.valueOf(scaleValue));, since it has the same risk and comes from the same source.
This can be implemented entirely within the shown method body; no new imports are strictly necessary if we keep using System.err.println as with the existing length parsing. Concretely, within components/data/data-store/src/main/java/org/eclipse/dirigible/components/data/store/parser/EntityParser.java, around lines 453–459, replace the direct calls to Integer.valueOf(...) with try/catch blocks that log a warning and avoid throwing.
-
Copy modified lines R454-R460 -
Copy modified lines R463-R469
| @@ -451,12 +451,22 @@ | ||
| columnDetails.setDefaultValue(defaultValue); | ||
|
|
||
| String precisionValue = extractValue.apply(argText, "precision"); | ||
| if (precisionValue != null) | ||
| columnDetails.setPrecision(Integer.valueOf(precisionValue)); | ||
| if (precisionValue != null) { | ||
| try { | ||
| columnDetails.setPrecision(Integer.valueOf(precisionValue)); | ||
| } catch (NumberFormatException e) { | ||
| System.err.println("Warning: Could not parse precision value: " + precisionValue); | ||
| } | ||
| } | ||
|
|
||
| String scaleValue = extractValue.apply(argText, "scale"); | ||
| if (scaleValue != null) | ||
| columnDetails.setScale(Integer.valueOf(scaleValue)); | ||
| if (scaleValue != null) { | ||
| try { | ||
| columnDetails.setScale(Integer.valueOf(scaleValue)); | ||
| } catch (NumberFormatException e) { | ||
| System.err.println("Warning: Could not parse scale value: " + scaleValue); | ||
| } | ||
| } | ||
| } | ||
| } else if ("OneToMany".equals(decoratorName)) { | ||
| // Expects @OneToMany(() => OrderItem, { table: '...', joinColumn: '...', ... }) |
|
|
||
| String scaleValue = extractValue.apply(argText, "scale"); | ||
| if (scaleValue != null) | ||
| columnDetails.setScale(Integer.valueOf(scaleValue)); |
Check notice
Code scanning / CodeQL
Missing catch of NumberFormatException Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
To fix the problem, the calls that convert precisionValue and scaleValue from String to Integer should handle potential NumberFormatException in the same manner as the existing length conversion: wrap the conversion in a try/catch and handle invalid values gracefully (for example by logging a warning and skipping the assignment). This preserves current functionality for valid input while safely ignoring malformed numeric metadata instead of failing the entire parse.
Concretely, in EntityParser.java around lines 453–459, modify the blocks:
-
For
precisionValue, change:if (precisionValue != null) columnDetails.setPrecision(Integer.valueOf(precisionValue));
to:
if (precisionValue != null && !precisionValue.isEmpty()) { try { columnDetails.setPrecision(Integer.parseInt(precisionValue)); } catch (NumberFormatException e) { System.err.println("Warning: Could not parse precision value: " + precisionValue); } }
-
For
scaleValue, change:if (scaleValue != null) columnDetails.setScale(Integer.valueOf(scaleValue));
to:
if (scaleValue != null && !scaleValue.isEmpty()) { try { columnDetails.setScale(Integer.parseInt(scaleValue)); } catch (NumberFormatException e) { System.err.println("Warning: Could not parse scale value: " + scaleValue); } }
This mirrors the existing pattern used for length, introduces no new dependencies, and keeps behavior for valid numbers unchanged. No additional imports or methods are required.
-
Copy modified lines R454-R460 -
Copy modified lines R463-R469
| @@ -451,12 +451,22 @@ | ||
| columnDetails.setDefaultValue(defaultValue); | ||
|
|
||
| String precisionValue = extractValue.apply(argText, "precision"); | ||
| if (precisionValue != null) | ||
| columnDetails.setPrecision(Integer.valueOf(precisionValue)); | ||
| if (precisionValue != null && !precisionValue.isEmpty()) { | ||
| try { | ||
| columnDetails.setPrecision(Integer.parseInt(precisionValue)); | ||
| } catch (NumberFormatException e) { | ||
| System.err.println("Warning: Could not parse precision value: " + precisionValue); | ||
| } | ||
| } | ||
|
|
||
| String scaleValue = extractValue.apply(argText, "scale"); | ||
| if (scaleValue != null) | ||
| columnDetails.setScale(Integer.valueOf(scaleValue)); | ||
| if (scaleValue != null && !scaleValue.isEmpty()) { | ||
| try { | ||
| columnDetails.setScale(Integer.parseInt(scaleValue)); | ||
| } catch (NumberFormatException e) { | ||
| System.err.println("Warning: Could not parse scale value: " + scaleValue); | ||
| } | ||
| } | ||
| } | ||
| } else if ("OneToMany".equals(decoratorName)) { | ||
| // Expects @OneToMany(() => OrderItem, { table: '...', joinColumn: '...', ... }) |
TODO:
Fixes: #5574