-
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 14 days 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
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 days ago
In general, the fix is to stop using the deprecated Session.save(String entityName, Object object) overload and instead use a non-deprecated persistence method such as persist(Object entity) combined with retrieval of the identifier via session.getIdentifier(entity). This aligns with modern Hibernate/JPA semantics and avoids the string-based overload that has been deprecated.
In this specific method, we have type (the Hibernate entity name) and data (a Map<String, Object> normalized for that entity). The call currently is:
Object id = session.save(type, data);To avoid the deprecated overload while preserving functionality (returning the generated identifier), we can:
- Replace
session.save(type, data)withsession.persist(data);. - After persisting, obtain the identifier with
session.getIdentifier(data)and assign it toid.
This keeps the transaction semantics identical (same session and transaction handling) and still returns the identifier to the caller. For dynamic-map entities, Hibernate supports using a Map instance directly as the entity, provided it’s associated with a dynamic-map entity name in the mapping. Using persist in this way is the recommended pattern, and getIdentifier is non-deprecated and works for persistent instances. No new imports are required because Session already provides persist and getIdentifier, and we are not changing any types or introducing any new classes.
Concretely, in components/data/data-store/src/main/java/org/eclipse/dirigible/components/data/store/DataStore.java, in the save(String type, Map<String, Object> object) method, change the line with session.save(type, data) to the two-step sequence of session.persist(data); followed by Object id = session.getIdentifier(data);. The rest of the method remains the same.
-
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.persist(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
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 days ago
Generally, the fix is to stop using the deprecated Session.saveOrUpdate(String entityName, Object object) and replace it with a non-deprecated persistence operation that preserves the existing behavior. For transient entities use persist/save, for detached ones use merge or update; for dynamic entity-name use, the closest non-deprecated alternative is session.merge(String entityName, Object object) or session.persist(String entityName, Object object) depending on semantics.
In this specific method:
public void upsert(String type, Map object) {
Map<String, Object> data = JsonTypeConverter.normalizeForEntity(object, type);
try (Session session = getSessionFactory().openSession()) {
Transaction transaction = session.beginTransaction();
session.saveOrUpdate(type, data);
transaction.commit();
}
}the intention is clearly “upsert” (insert if new, update if existing). The best non-deprecated Hibernate operation that implements this semantic in one call is Session.merge(String entityName, Object object), which will insert if there is no row and update otherwise, and is not deprecated. So we should replace session.saveOrUpdate(type, data); with session.merge(type, data); while leaving the rest of the logic intact. No new imports are required because merge is a method on org.hibernate.Session, which is already imported; only the line with the deprecated call needs to change in components/data/data-store/src/main/java/org/eclipse/dirigible/components/data/store/DataStore.java.
-
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
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 days ago
In general, the fix is to stop using the deprecated Session.update(String entityName, Object object) overload and switch to a non‑deprecated API that has equivalent behavior. For plain Hibernate code, the most direct replacement is session.bySimpleNaturalId(entityClass).load(id) for natural IDs or session.update(Object) for entities already associated with a proper type; however, in this code the entity is represented as a Map<String, Object> and the entity name is passed explicitly as type. To maintain that behavior, the best like‑for‑like replacement is to obtain an EntityPersister for the given entity name from the SessionFactory and use its non‑deprecated update style operations. But that is more invasive and relies on internal APIs. A simpler and still valid approach in recent Hibernate is to use Session.merge(String entityName, Object object), which is not deprecated and supports passing an entity name as a string while handling both transient and detached instances. Since this update method is used within an explicit transaction and the object is detached (built as a Map via JsonTypeConverter.normalizeForEntity), merge is an appropriate replacement that preserves functionality while avoiding the deprecated update overload.
Concretely, in DataStore.java, in the update(String type, Map object) method, replace session.update(type, data); with session.merge(type, data);. This uses the non‑deprecated Session.merge(String entityName, Object object) method, which is available on the same Session type already imported, so no additional imports are needed and no other code paths need to change. The upsert and delete methods also use string‑entity overloads (saveOrUpdate(type, data) and delete(type, object)), but the CodeQL issue you asked about is specifically for update, so we will only change that line.
-
Copy modified line R321
| @@ -318,7 +318,7 @@ | ||
|
|
||
| try (Session session = getSessionFactory().openSession()) { | ||
| Transaction transaction = session.beginTransaction(); | ||
| session.update(type, data); | ||
| session.merge(type, data); | ||
| 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
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 14 days 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
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 14 days 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:
// TODOcommentsFixes: #5574