Skip to content

Commit 2237844

Browse files
Enhance AbstractCrudServiceRestController to support class validation and caching
1 parent bd3aaed commit 2237844

1 file changed

Lines changed: 36 additions & 10 deletions

File tree

platform/app/src/main/java/tools/dynamia/app/controllers/AbstractCrudServiceRestController.java

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
import io.swagger.v3.oas.annotations.tags.Tag;
55
import org.springframework.http.ResponseEntity;
66
import org.springframework.web.bind.annotation.*;
7+
import tools.dynamia.commons.SimpleCache;
78
import tools.dynamia.commons.StringPojoParser;
89
import tools.dynamia.domain.ValidationError;
910
import tools.dynamia.domain.query.QueryParameters;
1011
import tools.dynamia.domain.services.CrudService;
12+
import tools.dynamia.integration.Containers;
13+
import tools.dynamia.viewers.ViewDescriptorFactory;
1114
import tools.jackson.core.JacksonException;
1215
import tools.jackson.databind.json.JsonMapper;
1316

@@ -46,8 +49,11 @@ public abstract class AbstractCrudServiceRestController {
4649
*/
4750
private final JsonMapper mapper = StringPojoParser.createJsonMapper();
4851

52+
private SimpleCache<String, Class> allowedClasses = new SimpleCache<>();
53+
4954
/**
5055
* Constructs a new {@code CrudServiceRestController} with the given CRUD service.
56+
*
5157
* @param crudService the CRUD service to use
5258
*/
5359
public AbstractCrudServiceRestController(CrudService crudService) {
@@ -56,8 +62,9 @@ public AbstractCrudServiceRestController(CrudService crudService) {
5662

5763
/**
5864
* Creates or updates an entity of the specified class.
65+
*
5966
* @param className the fully qualified class name of the entity
60-
* @param json the JSON representation of the entity
67+
* @param json the JSON representation of the entity
6168
* @return the persisted entity
6269
*/
6370
@RequestMapping(method = {RequestMethod.POST, RequestMethod.PUT})
@@ -69,8 +76,9 @@ public ResponseEntity<Object> createOrSave(@PathVariable String className, @Requ
6976

7077
/**
7178
* Deletes an entity by its class name and ID.
79+
*
7280
* @param className the fully qualified class name of the entity
73-
* @param id the entity ID
81+
* @param id the entity ID
7482
* @return the deleted entity ID if successful, or 404 if not found
7583
*/
7684
@DeleteMapping("/{id}")
@@ -87,8 +95,9 @@ public ResponseEntity<Object> delete(@PathVariable String className, @PathVariab
8795

8896
/**
8997
* Retrieves an entity by its class name and ID.
98+
*
9099
* @param className the fully qualified class name of the entity
91-
* @param id the entity ID
100+
* @param id the entity ID
92101
* @return the entity if found, or 404 if not found
93102
*/
94103
@GetMapping("/{id}")
@@ -103,7 +112,8 @@ public ResponseEntity<Object> get(@PathVariable String className, @PathVariable
103112

104113
/**
105114
* Finds entities by query parameters.
106-
* @param className the fully qualified class name of the entity
115+
*
116+
* @param className the fully qualified class name of the entity
107117
* @param parameters the query parameters
108118
* @return the list of matching entities
109119
*/
@@ -116,7 +126,8 @@ public ResponseEntity<List<Object>> find(@PathVariable String className, @Reques
116126

117127
/**
118128
* Gets the ID of an entity by query parameters.
119-
* @param className the fully qualified class name of the entity
129+
*
130+
* @param className the fully qualified class name of the entity
120131
* @param parameters the query parameters
121132
* @return the entity ID
122133
*/
@@ -129,8 +140,9 @@ public ResponseEntity<Object> getId(@PathVariable String className, @RequestBody
129140

130141
/**
131142
* Parses a JSON string into an entity object of the specified class.
143+
*
132144
* @param className the fully qualified class name
133-
* @param json the JSON string
145+
* @param json the JSON string
134146
* @return the entity object
135147
* @throws ValidationError if parsing fails
136148
*/
@@ -145,15 +157,29 @@ private Object parseJson(String className, String json) {
145157

146158
/**
147159
* Loads a class by its fully qualified name.
160+
*
148161
* @param className the class name
149162
* @return the {@link Class} object
150163
* @throws ValidationError if the class is not found
151164
*/
152165
private Class loadClass(String className) {
153-
try {
154-
return Class.forName(className);
155-
} catch (ClassNotFoundException e) {
156-
throw new ValidationError("Class not found " + className + " - " + e.getMessage(), e);
166+
initAllowedClasses();
167+
Class entityClass = allowedClasses.get(className);
168+
if (entityClass == null) {
169+
throw new ValidationError("Class not allowed: " + className);
170+
}
171+
return entityClass;
172+
}
173+
174+
private void initAllowedClasses() {
175+
if (allowedClasses == null || allowedClasses.isEmpty()) {
176+
ViewDescriptorFactory viewDescriptorFactory = Containers.get().findObject(ViewDescriptorFactory.class);
177+
if (viewDescriptorFactory != null) {
178+
viewDescriptorFactory.findDescriptorsByType("crud").forEach(d -> {
179+
var entityClass = d.getKey();
180+
allowedClasses.add(entityClass.getName(), entityClass);
181+
});
182+
}
157183
}
158184
}
159185
}

0 commit comments

Comments
 (0)