eva4j 1.0.12 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,311 +1,335 @@
1
- # Command `generate record` (alias: `g record`)
2
-
3
- ## 📋 Description
4
-
5
- Generates a Java Record class with immutable data structure, ideal for DTOs, value objects, or simple data carriers.
6
-
7
- ## 🎯 Purpose
8
-
9
- Quickly create immutable data classes using Java Records (Java 14+), reducing boilerplate code for simple data structures.
10
-
11
- ## 📝 Syntax
12
-
13
- ```bash
14
- eva4j generate record <RecordName>
15
- eva4j g record <RecordName> # Short alias
16
- ```
17
-
18
- ### Parameters
19
-
20
- | Parameter | Required | Description |
21
- |-----------|----------|-------------|
22
- | `RecordName` | Yes | Name of the record (PascalCase, e.g., CustomerDto, OrderSummary) |
23
-
24
- ## 💡 Examples
25
-
26
- ### Example 1: Simple DTO
27
-
28
- ```bash
29
- eva4j g record CustomerDto
30
- ```
31
-
32
- **Generates:**
33
- ```java
34
- package com.example.project.customer.application.dtos;
35
-
36
- /**
37
- * CustomerDto - Immutable data transfer object
38
- */
39
- public record CustomerDto(
40
- // Add your fields here
41
- ) {
42
- }
43
- ```
44
-
45
- ### Example 2: Value Object
46
-
47
- ```bash
48
- eva4j g record Address
49
- ```
50
-
51
- ### Example 3: API Response
52
-
53
- ```bash
54
- eva4j g record ApiResponse
55
- ```
56
-
57
- ## 📦 Generated Code Structure
58
-
59
- **Location:** `<module>/application/dtos/<RecordName>.java`
60
-
61
- **Basic Template:**
62
- ```java
63
- package com.example.project.customer.application.dtos;
64
-
65
- /**
66
- * CustomerDto - Immutable data transfer object
67
- */
68
- public record CustomerDto(
69
- // Add your fields here
70
- Long id,
71
- String name,
72
- String email
73
- ) {
74
- }
75
- ```
76
-
77
- ## Features
78
-
79
- ### Java Records Benefits
80
- - ✅ **Immutable by default** - All fields are final
81
- - **Automatic getters** - `record.id()`, `record.name()`
82
- - ✅ **Automatic equals/hashCode** - Based on all fields
83
- - **Automatic toString()** - Human-readable representation
84
- - **Compact syntax** - Less boilerplate than classes
85
- - ✅ **Type-safe** - Compile-time field validation
86
-
87
- ### Common Use Cases
88
- - Data Transfer Objects (DTOs)
89
- - API Responses
90
- - Configuration objects
91
- - Event payloads
92
- - Query results
93
- - Value Objects (simple ones)
94
-
95
- ## 🔧 Customization Examples
96
-
97
- ### Add Fields
98
-
99
- ```java
100
- public record CustomerDto(
101
- Long id,
102
- String firstName,
103
- String lastName,
104
- String email,
105
- LocalDateTime createdAt
106
- ) {
107
- }
108
- ```
109
-
110
- ### Add Validation
111
-
112
- ```java
113
- import jakarta.validation.constraints.*;
114
-
115
- public record CreateCustomerDto(
116
- @NotBlank
117
- @Size(max = 100)
118
- String firstName,
119
-
120
- @NotBlank
121
- @Size(max = 100)
122
- String lastName,
123
-
124
- @Email
125
- @NotBlank
126
- String email
127
- ) {
128
- }
129
- ```
130
-
131
- ### Add Custom Methods
132
-
133
- ```java
134
- public record CustomerDto(
135
- Long id,
136
- String firstName,
137
- String lastName,
138
- String email
139
- ) {
140
- // Custom method
141
- public String fullName() {
142
- return firstName + " " + lastName;
143
- }
144
-
145
- // Compact constructor with validation
146
- public CustomerDto {
147
- if (firstName == null || firstName.isBlank()) {
148
- throw new IllegalArgumentException("First name is required");
149
- }
150
- }
151
- }
152
- ```
153
-
154
- ### Nested Records
155
-
156
- ```java
157
- public record OrderDto(
158
- Long id,
159
- CustomerDto customer,
160
- List<OrderItemDto> items,
161
- BigDecimal total
162
- ) {
163
- }
164
-
165
- public record OrderItemDto(
166
- Long productId,
167
- String productName,
168
- Integer quantity,
169
- BigDecimal price
170
- ) {
171
- }
172
- ```
173
-
174
- ## 🎯 Record vs Class
175
-
176
- ### Use Record When:
177
- - ✅ Data is immutable
178
- - Simple data carrier without complex behavior
179
- - ✅ DTOs for API requests/responses
180
- - ✅ Value objects with few fields
181
- - ✅ Event payloads
182
-
183
- ### Use Class When:
184
- - ❌ Need mutability (setters)
185
- - ❌ Complex business logic
186
- - ❌ Inheritance required
187
- - Need lazy loading
188
- - JPA entities (use `@Entity` classes)
189
-
190
- ## 📚 Common Patterns
191
-
192
- ### Request DTO
193
-
194
- ```java
195
- public record CreateOrderRequest(
196
- @NotNull Long customerId,
197
- @NotEmpty List<OrderItemRequest> items,
198
- @Size(max = 500) String notes
199
- ) {
200
- }
201
- ```
202
-
203
- ### Response DTO
204
-
205
- ```java
206
- public record OrderResponse(
207
- Long id,
208
- String orderNumber,
209
- CustomerSummary customer,
210
- BigDecimal total,
211
- OrderStatus status,
212
- LocalDateTime createdAt
213
- ) {
214
- }
215
- ```
216
-
217
- ### Page Response
218
-
219
- ```java
220
- public record PageResponse<T>(
221
- List<T> content,
222
- int pageNumber,
223
- int pageSize,
224
- long totalElements,
225
- int totalPages
226
- ) {
227
- }
228
- ```
229
-
230
- ### Error Response
231
-
232
- ```java
233
- public record ErrorResponse(
234
- String message,
235
- String code,
236
- LocalDateTime timestamp
237
- ) {
238
- public ErrorResponse(String message, String code) {
239
- this(message, code, LocalDateTime.now());
240
- }
241
- }
242
- ```
243
-
244
- ## 🚀 Next Steps
245
-
246
- After generating a record:
247
-
248
- 1. **Add fields:**
249
- ```java
250
- public record CustomerDto(
251
- Long id,
252
- String name,
253
- String email
254
- ) {
255
- }
256
- ```
257
-
258
- 2. **Use in controllers:**
259
- ```java
260
- @PostMapping
261
- public ResponseEntity<CustomerDto> create(@Valid @RequestBody CustomerDto dto) {
262
- // Process DTO
263
- }
264
- ```
265
-
266
- 3. **Create mappers:**
267
- ```java
268
- public class CustomerMapper {
269
- public static CustomerDto toDto(Customer entity) {
270
- return new CustomerDto(
271
- entity.getId(),
272
- entity.getName(),
273
- entity.getEmail()
274
- );
275
- }
276
- }
277
- ```
278
-
279
- ## ⚠️ Prerequisites
280
-
281
- - Java 17+ (Records require Java 14+, but project uses 21+)
282
- - Be in a project created with `eva4j create`
283
- - Module must exist
284
-
285
- ## 🔍 Validations
286
-
287
- The command validates:
288
- - Valid eva4j project
289
- - ✅ Record name is in PascalCase
290
- - ✅ Module exists
291
- - ✅ Java version supports records
292
-
293
- ## 📚 See Also
294
-
295
- - [generate-entities](./GENERATE_ENTITIES.md) - Generate full entities
296
- - [generate-usecase](./GENERATE_USECASE.md) - Create use cases that use records
297
- - [generate-resource](./GENERATE_RESOURCE.md) - Create controllers
298
-
299
- ## 🐛 Troubleshooting
300
-
301
- **Error: "Records not supported"**
302
- - Solution: Ensure your project uses Java 17+ (configured during `eva4j create`)
303
-
304
- **Validation annotations not working**
305
- - Solution: Add Jakarta Validation dependency and `@Valid` annotation
306
-
307
- **Cannot modify record fields**
308
- - Solution: Records are immutable by design. Create new instances instead of modifying existing ones
309
-
310
- **JPA errors with records**
311
- - Solution: Don't use records for JPA entities. Use regular classes with `@Entity` annotation
1
+ # Command `generate record` (alias: `g record`)
2
+
3
+ ---
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Description and purpose](#1-description-and-purpose)
8
+ 2. [Syntax](#2-syntax)
9
+ 3. [How it works](#3-how-it-works)
10
+ 4. [Interactive prompts](#4-interactive-prompts)
11
+ 5. [JSON type inference](#5-json-type-inference)
12
+ 6. [Nested records](#6-nested-records)
13
+ 7. [Generation modes](#7-generation-modes)
14
+ 8. [Suffix by target folder](#8-suffix-by-target-folder)
15
+ 9. [Generated output](#9-generated-output)
16
+ 10. [Complete examples](#10-complete-examples)
17
+ 11. [Prerequisites and common errors](#11-prerequisites-and-common-errors)
18
+
19
+ ---
20
+
21
+ ## 1. Description and purpose
22
+
23
+ `generate record` creates Java Record classes by **reading a JSON structure from the clipboard** and automatically inferring Java types. It handles nested objects and arrays by generating additional nested records.
24
+
25
+ It is designed for quickly scaffolding:
26
+ - Response DTOs
27
+ - Request/Command DTOs
28
+ - Query objects
29
+ - Event payloads
30
+
31
+ ---
32
+
33
+ ## 2. Syntax
34
+
35
+ ```bash
36
+ eva generate record
37
+ eva g record # short alias
38
+ ```
39
+
40
+ No positional arguments. The record name and module are provided interactively.
41
+
42
+ ### Passing JSON directly
43
+
44
+ ```bash
45
+ eva g record '{"id":"123","name":"John"}'
46
+ ```
47
+
48
+ When a string is passed as the first argument, it is treated as inline JSON instead of reading from the clipboard.
49
+
50
+ ---
51
+
52
+ ## 3. How it works
53
+
54
+ 1. Reads JSON from the **clipboard** (or from the inline argument)
55
+ 2. Shows a preview of the parsed JSON
56
+ 3. Asks interactive questions (record name, module, target folder)
57
+ 4. Infers Java types for every field
58
+ 5. Detects nested objects and arrays and generates additional nested records
59
+ 6. Asks for generation mode when nested records exist
60
+ 7. Writes the generated `.java` files to the application layer of the selected module
61
+
62
+ ---
63
+
64
+ ## 4. Interactive prompts
65
+
66
+ | Prompt | Description |
67
+ |--------|-------------|
68
+ | **Record name** | Base name for the main record (e.g., `OrderResponse`) |
69
+ | **Target module** | One of the existing modules in the project |
70
+ | **Target folder** | `dtos`, `commands`, `queries`, or `events` |
71
+ | **Generation mode** | Only shown when nested records exist (see [section 7](#7-generation-modes)) |
72
+
73
+ ---
74
+
75
+ ## 5. JSON type inference
76
+
77
+ The generator maps JSON values to Java types using the following rules:
78
+
79
+ | JSON value | Java type |
80
+ |------------|-----------|
81
+ | `"hello"` | `String` |
82
+ | `"2024-01-15T10:30:00"` | `LocalDateTime` |
83
+ | `"2024-01-15"` | `LocalDate` |
84
+ | `"10:30:00"` | `LocalTime` |
85
+ | `"550e8400-e29b-41d4-a716..."` | `UUID` |
86
+ | `42` (integer) | `Integer` |
87
+ | `3.14` (decimal) | `Double` |
88
+ | `true` / `false` | `Boolean` |
89
+ | `null` | `Object` |
90
+ | `{ ... }` (object) | Nested Record |
91
+ | `[{ ... }]` (array of objects) | `List<NestedRecord>` |
92
+ | `["a", "b"]` (array of strings) | `List<String>` |
93
+ | `[1, 2]` (array of integers) | `List<Integer>` |
94
+
95
+ String detection for dates, times, and UUIDs is based on pattern matching against the value itself.
96
+
97
+ ---
98
+
99
+ ## 6. Nested records
100
+
101
+ When the JSON contains nested objects or arrays of objects, the generator automatically creates additional records for each nested type:
102
+
103
+ ```json
104
+ {
105
+ "id": "abc-123",
106
+ "customer": {
107
+ "id": 1,
108
+ "name": "John"
109
+ },
110
+ "items": [
111
+ {
112
+ "productId": "PROD-1",
113
+ "quantity": 2,
114
+ "price": 9.99
115
+ }
116
+ ]
117
+ }
118
+ ```
119
+
120
+ From this JSON, with record name `Order` and target folder `dtos`, the generator detects:
121
+
122
+ - **`OrderDto`** — main record
123
+ - **`CustomerDto`** — from the nested `customer` object
124
+ - **`ItemDto`** — from the `items` array (name is singularized automatically)
125
+
126
+ ---
127
+
128
+ ## 7. Generation modes
129
+
130
+ When nested records are detected, the generator asks how to write them:
131
+
132
+ | Mode | Description |
133
+ |------|-------------|
134
+ | **Separate files** | One `.java` file per record (default) |
135
+ | **Nested structure** | A single `.java` file with inner records declared inside the main record |
136
+
137
+ ### Separate files (default)
138
+
139
+ ```
140
+ application/dtos/
141
+ ├── OrderDto.java
142
+ ├── CustomerDto.java
143
+ └── ItemDto.java
144
+ ```
145
+
146
+ ### Nested structure
147
+
148
+ ```
149
+ application/dtos/
150
+ └── OrderDto.java ← contains CustomerDto and ItemDto as inner records
151
+ ```
152
+
153
+ ---
154
+
155
+ ## 8. Suffix by target folder
156
+
157
+ The selected target folder determines the suffix automatically appended to each record name:
158
+
159
+ | Target folder | Suffix | Example |
160
+ |---------------|--------|---------|
161
+ | `dtos` | `Dto` | `OrderDto` |
162
+ | `commands` | `Command` | `OrderCommand` |
163
+ | `queries` | `Query` | `OrderQuery` |
164
+ | `events` | `Event` | `OrderEvent` |
165
+
166
+ The suffix is applied to all records, including nested ones.
167
+
168
+ ---
169
+
170
+ ## 9. Generated output
171
+
172
+ **Location:**
173
+
174
+ ```
175
+ src/main/java/{package}/{module}/application/{targetFolder}/{RecordName}{Suffix}.java
176
+ ```
177
+
178
+ **Example generated file** (`OrderDto.java`):
179
+
180
+ ```java
181
+ package com.example.myapp.orders.application.dtos;
182
+
183
+ import java.util.List;
184
+ import java.util.UUID;
185
+
186
+ /**
187
+ * OrderDto record
188
+ * Generated from JSON
189
+ */
190
+ public record OrderDto(
191
+ UUID id,
192
+ CustomerDto customer,
193
+ List<ItemDto> items
194
+ ) {
195
+ }
196
+ ```
197
+
198
+ Imports for `java.time.*`, `java.util.UUID`, and `java.util.List` are added automatically when needed.
199
+
200
+ ---
201
+
202
+ ## 10. Complete examples
203
+
204
+ ### Example 1: Simple DTO from clipboard
205
+
206
+ Copy this JSON to your clipboard:
207
+
208
+ ```json
209
+ {
210
+ "id": "550e8400-e29b-41d4-a716-446655440000",
211
+ "orderNumber": "ORD-001",
212
+ "customerId": "CUST-123",
213
+ "totalAmount": 149.99,
214
+ "orderDate": "2024-01-15T10:30:00",
215
+ "status": "CONFIRMED"
216
+ }
217
+ ```
218
+
219
+ Run:
220
+
221
+ ```bash
222
+ eva g record
223
+ ```
224
+
225
+ Prompts:
226
+ - Record name: `OrderResponse`
227
+ - Module: `orders`
228
+ - Target folder: `dtos`
229
+
230
+ Generated `OrderResponseDto.java`:
231
+
232
+ ```java
233
+ package com.example.myapp.orders.application.dtos;
234
+
235
+ import java.time.LocalDateTime;
236
+ import java.util.UUID;
237
+
238
+ /**
239
+ * OrderResponseDto record
240
+ * Generated from JSON
241
+ */
242
+ public record OrderResponseDto(
243
+ UUID id,
244
+ String orderNumber,
245
+ String customerId,
246
+ Double totalAmount,
247
+ LocalDateTime orderDate,
248
+ String status
249
+ ) {
250
+ }
251
+ ```
252
+
253
+ ---
254
+
255
+ ### Example 2: Nested objects
256
+
257
+ Copy this JSON:
258
+
259
+ ```json
260
+ {
261
+ "id": 1,
262
+ "customer": {
263
+ "id": 42,
264
+ "name": "John Doe",
265
+ "email": "john@example.com"
266
+ },
267
+ "items": [
268
+ {
269
+ "productId": "PROD-1",
270
+ "quantity": 2,
271
+ "unitPrice": 9.99
272
+ }
273
+ ],
274
+ "createdAt": "2024-01-15T10:30:00"
275
+ }
276
+ ```
277
+
278
+ Run:
279
+
280
+ ```bash
281
+ eva g record
282
+ ```
283
+
284
+ Prompts:
285
+ - Record name: `Order`
286
+ - Module: `orders`
287
+ - Target folder: `dtos`
288
+ - Generation mode: `Separate files`
289
+
290
+ Generated files:
291
+
292
+ ```
293
+ application/dtos/
294
+ ├── OrderDto.java
295
+ ├── CustomerDto.java
296
+ └── ItemDto.java
297
+ ```
298
+
299
+ `OrderDto.java`:
300
+ ```java
301
+ public record OrderDto(
302
+ Integer id,
303
+ CustomerDto customer,
304
+ List<ItemDto> items,
305
+ LocalDateTime createdAt
306
+ ) {
307
+ }
308
+ ```
309
+
310
+ ---
311
+
312
+ ### Example 3: Inline JSON
313
+
314
+ ```bash
315
+ eva g record '{"id":1,"name":"Product A","price":29.99}'
316
+ ```
317
+
318
+ ---
319
+
320
+ ## 11. Prerequisites and common errors
321
+
322
+ ### Prerequisites
323
+
324
+ - Project created with `eva create`
325
+ - At least one module created (`eva add module <name>`)
326
+ - Valid JSON in the clipboard (or passed as the first argument)
327
+
328
+ ### Common errors
329
+
330
+ | Error | Cause | Solution |
331
+ |-------|-------|----------|
332
+ | `Failed to read or parse JSON from clipboard` | Clipboard is empty or contains invalid JSON | Copy valid JSON to clipboard before running the command |
333
+ | `Cannot generate record from empty array` | JSON is an empty array `[]` | Use an array with at least one element as template |
334
+ | `No modules found in project` | No modules exist yet | Run `eva add module <name>` first |
335
+ | `Module not found in filesystem` | Module is in config but missing on disk | Recreate the module with `eva add module <name>` |
@@ -5,7 +5,7 @@
5
5
  aggregates:
6
6
  - name: Evaluation
7
7
  entities:
8
- - name: evaluation
8
+ - name: Evaluation
9
9
  isRoot: true
10
10
  tableName: evaluations
11
11
  auditable: true
@@ -28,7 +28,7 @@ aggregates:
28
28
  cascade: [ PERSIST, MERGE, REMOVE ]
29
29
  fetch: LAZY
30
30
 
31
- - name: evaluationDoctor
31
+ - name: EvaluationDoctor
32
32
  auditable: true
33
33
  tableName: evaluation_doctors
34
34
  fields:
@@ -50,7 +50,7 @@ aggregates:
50
50
  type: List<Degrees>
51
51
 
52
52
 
53
- - name: evaluationBranch
53
+ - name: EvaluationBranch
54
54
  tableName: evaluation_branchs
55
55
  auditable: true
56
56
  fields: