Skip to content

Commit 3b6a157

Browse files
committed
📚 example: Add simple CRUD demonstration app - Complete Product entity with JPA annotations - ProductRepository extending BaseRepository - ProductController with @crud annotation and custom method - SimpleCrudApp showing full setup and usage - Comprehensive README with API examples and curl commands
1 parent 22e3b50 commit 3b6a157

File tree

5 files changed

+363
-0
lines changed

5 files changed

+363
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Simple CRUD Example
2+
3+
This example demonstrates how to use the Jazzy Framework's @Crud annotation in the simplest way possible.
4+
5+
## 📁 File Structure
6+
7+
```
8+
simpleCrud/
9+
├── Product.java # Entity class (JPA entity)
10+
├── ProductRepository.java # Repository interface
11+
├── ProductRepositoryImpl.java # Repository implementation
12+
├── ProductController.java # Controller (one method overridden)
13+
├── SimpleCrudApp.java # Main application
14+
└── README.md # This file
15+
```
16+
17+
## 🎯 Features
18+
19+
### ✅ Automatic CRUD Operations
20+
- `GET /api/products/{id}` - Get product by ID
21+
- `POST /api/products` - Create new product
22+
- `PUT /api/products/{id}` - Update product
23+
- `DELETE /api/products/{id}` - Delete product
24+
- `GET /api/products/search?name=laptop` - Search products
25+
26+
### 🎨 Customized Method
27+
- `GET /api/products` - **Overridden!** Shows only products in stock
28+
29+
## 🔧 How It Works?
30+
31+
### 1. @Crud Annotation
32+
```java
33+
@Crud(
34+
entity = Product.class,
35+
endpoint = "/api/products",
36+
enablePagination = true,
37+
enableSearch = true,
38+
searchableFields = {"name", "description"}
39+
)
40+
public class ProductController {
41+
// ...
42+
}
43+
```
44+
45+
### 2. Overridden Method
46+
```java
47+
@CrudOverride(value = "Custom findAll that filters out-of-stock products", operation = "findAll")
48+
public Response findAll(Request request) {
49+
// Return only products in stock
50+
var inStockProducts = allProducts.stream()
51+
.filter(product -> product.getStock() != null && product.getStock() > 0)
52+
.toList();
53+
// ...
54+
}
55+
```
56+
57+
### 3. Manual Route Registration
58+
```java
59+
// Manual registration required for overridden methods!
60+
router.GET("/api/products", "findAll", ProductController.class);
61+
```
62+
63+
## 🚀 Running the Application
64+
65+
```bash
66+
# Compile and run with Maven
67+
mvn compile exec:java -Dexec.mainClass="examples.simple_crud.SimpleCrudApp"
68+
69+
# Or run SimpleCrudApp.main() method from your IDE
70+
```
71+
72+
## 🧪 Test Commands
73+
74+
### Create Product
75+
```bash
76+
curl -X POST -H "Content-Type: application/json" \
77+
-d '{"name":"Gaming Laptop","description":"High-performance gaming laptop","price":1299.99,"stock":5}' \
78+
"http://localhost:8080/api/products"
79+
```
80+
81+
### List In-Stock Products (Overridden)
82+
```bash
83+
curl "http://localhost:8080/api/products"
84+
```
85+
86+
### Get Product by ID (Automatic)
87+
```bash
88+
curl "http://localhost:8080/api/products/1"
89+
```
90+
91+
### Search Products (Automatic)
92+
```bash
93+
curl "http://localhost:8080/api/products/search?name=laptop"
94+
```
95+
96+
### Update Product (Automatic)
97+
```bash
98+
curl -X PUT -H "Content-Type: application/json" \
99+
-d '{"name":"Updated Laptop","description":"Updated description","price":1199.99,"stock":3}' \
100+
"http://localhost:8080/api/products/1"
101+
```
102+
103+
### Delete Product (Automatic)
104+
```bash
105+
curl -X DELETE "http://localhost:8080/api/products/1"
106+
```
107+
108+
## 💡 Important Notes
109+
110+
1. **Overridden Methods**: Manual route registration is required for overridden methods
111+
2. **Automatic Methods**: All other CRUD operations are automatically generated
112+
3. **Repository Pattern**: A repository extending BaseRepository interface is required
113+
4. **DI Integration**: All components are automatically connected via dependency injection
114+
115+
## 📝 Example Response
116+
117+
### Successful Response
118+
```json
119+
{
120+
"success": true,
121+
"message": "In-stock products retrieved successfully",
122+
"data": [
123+
{
124+
"id": 1,
125+
"name": "Gaming Laptop",
126+
"description": "High-performance gaming laptop",
127+
"price": 1299.99,
128+
"stock": 5
129+
}
130+
],
131+
"timestamp": "2023-12-07T10:30:00",
132+
"metadata": {
133+
"totalProducts": 3,
134+
"inStockCount": 1,
135+
"outOfStockCount": 2
136+
}
137+
}
138+
```
139+
140+
This example demonstrates the power and ease of the @Crud annotation - maximum functionality with minimum code!
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package examples.simple_crud;
2+
3+
import examples.simple_crud.controller.ProductController;
4+
import jazzyframework.core.Config;
5+
import jazzyframework.core.Server;
6+
import jazzyframework.routing.Router;
7+
8+
/**
9+
* Simple CRUD demonstration application.
10+
*
11+
* This example shows how to use @Crud annotation with minimal setup:
12+
* - Product entity with basic fields
13+
* - ProductController with @Crud annotation
14+
* - One overridden method (findAll) with custom logic
15+
* - All other CRUD operations auto-generated
16+
*
17+
* Available endpoints:
18+
* - GET /api/products (custom - shows only in-stock products)
19+
* - GET /api/products/{id} (auto-generated)
20+
* - POST /api/products (auto-generated)
21+
* - PUT /api/products/{id} (auto-generated)
22+
* - DELETE /api/products/{id} (auto-generated)
23+
* - GET /api/products/search?name=laptop (auto-generated search)
24+
*/
25+
public class SimpleCrudApp {
26+
27+
public static void main(String[] args) {
28+
Config config = new Config();
29+
config.setServerPort(8080);
30+
31+
Router router = new Router();
32+
33+
// Manual route registration for overridden method
34+
// This is IMPORTANT: When we override a CRUD method, we need to manually register its route
35+
router.GET("/api/products", "findAll", ProductController.class);
36+
37+
Server server = new Server(router, config);
38+
39+
printStartupInfo();
40+
41+
server.start(config.getServerPort());
42+
}
43+
44+
private static void printStartupInfo() {
45+
System.out.println("✨ Simple CRUD Demo");
46+
System.out.println("🎯 Demonstrating basic @Crud annotation with method override");
47+
System.out.println();
48+
System.out.println("📡 Server starting on port 8080");
49+
System.out.println();
50+
System.out.println("🔄 Auto-generated CRUD endpoints (by @Crud annotation):");
51+
System.out.println(" GET /api/products/{id} - Find product by ID");
52+
System.out.println(" POST /api/products - Create new product");
53+
System.out.println(" PUT /api/products/{id} - Update product");
54+
System.out.println(" DELETE /api/products/{id} - Delete product");
55+
System.out.println(" GET /api/products/search - Search products (?name=...)");
56+
System.out.println();
57+
System.out.println("🎨 Custom overridden endpoint:");
58+
System.out.println(" GET /api/products - Get in-stock products only (custom logic)");
59+
System.out.println();
60+
System.out.println("🧪 Example commands:");
61+
System.out.println(" curl \"http://localhost:8080/api/products\"");
62+
System.out.println(" curl -X POST -H \"Content-Type: application/json\" \\");
63+
System.out.println(" -d '{\"name\":\"Laptop\",\"description\":\"Gaming laptop\",\"price\":1299.99,\"stock\":5}' \\");
64+
System.out.println(" \"http://localhost:8080/api/products\"");
65+
System.out.println(" curl \"http://localhost:8080/api/products/1\"");
66+
System.out.println(" curl \"http://localhost:8080/api/products/search?name=laptop\"");
67+
System.out.println();
68+
System.out.println("💡 Key Feature: Only the overridden findAll method needed manual registration!");
69+
System.out.println("💡 All other CRUD methods are automatically generated by @Crud annotation!");
70+
System.out.println();
71+
}
72+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package examples.simple_crud.controller;
2+
3+
import examples.simple_crud.entity.Product;
4+
import examples.simple_crud.repository.ProductRepository;
5+
import jazzyframework.data.annotations.Crud;
6+
import jazzyframework.data.annotations.CrudOverride;
7+
import jazzyframework.di.annotations.Component;
8+
import jazzyframework.http.ApiResponse;
9+
import jazzyframework.http.Request;
10+
import jazzyframework.http.Response;
11+
12+
/**
13+
* Product controller demonstrating @Crud annotation with method override.
14+
*
15+
* This controller will automatically have these endpoints generated:
16+
* - GET /api/products (findAll - but overridden)
17+
* - GET /api/products/{id} (findById - auto-generated)
18+
* - POST /api/products (create - auto-generated)
19+
* - PUT /api/products/{id} (update - auto-generated)
20+
* - DELETE /api/products/{id} (delete - auto-generated)
21+
*
22+
* - GET /api/products/search?name=laptop (enableSearch = true)
23+
* - GET /api/products/exists/{id} (enableExists = true)
24+
*/
25+
@Component
26+
@Crud(
27+
entity = Product.class,
28+
endpoint = "/api/products",
29+
enablePagination = true,
30+
enableSearch = true,
31+
searchableFields = {"name", "description"},
32+
enableExists = true
33+
)
34+
public class ProductController {
35+
36+
private final ProductRepository productRepository;
37+
38+
public ProductController(ProductRepository productRepository) {
39+
this.productRepository = productRepository;
40+
}
41+
42+
/**
43+
* Custom implementation of findAll method.
44+
* This overrides the auto-generated findAll method.
45+
* Only returns products that are in stock.
46+
*
47+
* @CrudOverride is a custom annotation that if you want to remember override method name, you can use it.
48+
*
49+
* You can use like this:
50+
* @CrudOverride(value = "Custom findAll that returns all products", operation = "findAll")
51+
* or like this:
52+
* @CrudOverride
53+
*/
54+
@CrudOverride(value = "Custom findAll that returns all products")
55+
public Response findAll(Request request) {
56+
return Response.json(ApiResponse.success("Products retrieved successfully", productRepository.findAll()));
57+
}
58+
59+
// All other CRUD methods (findById, create, update, delete) will be auto-generated
60+
// You don't need to implement them - the framework handles them automatically
61+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package examples.simple_crud.entity;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.GeneratedValue;
5+
import jakarta.persistence.GenerationType;
6+
import jakarta.persistence.Id;
7+
import jakarta.persistence.Table;
8+
9+
@Entity
10+
@Table(name = "products")
11+
public class Product {
12+
@Id
13+
@GeneratedValue(strategy = GenerationType.IDENTITY)
14+
private Long id;
15+
16+
private String name;
17+
private String description;
18+
private Double price;
19+
private Integer stock;
20+
21+
// Default constructor
22+
public Product() {}
23+
24+
// Constructor
25+
public Product(String name, String description, Double price, Integer stock) {
26+
this.name = name;
27+
this.description = description;
28+
this.price = price;
29+
this.stock = stock;
30+
}
31+
32+
// Getters and Setters
33+
public Long getId() {
34+
return id;
35+
}
36+
37+
public void setId(Long id) {
38+
this.id = id;
39+
}
40+
41+
public String getName() {
42+
return name;
43+
}
44+
45+
public void setName(String name) {
46+
this.name = name;
47+
}
48+
49+
public String getDescription() {
50+
return description;
51+
}
52+
53+
public void setDescription(String description) {
54+
this.description = description;
55+
}
56+
57+
public Double getPrice() {
58+
return price;
59+
}
60+
61+
public void setPrice(Double price) {
62+
this.price = price;
63+
}
64+
65+
public Integer getStock() {
66+
return stock;
67+
}
68+
69+
public void setStock(Integer stock) {
70+
this.stock = stock;
71+
}
72+
73+
@Override
74+
public String toString() {
75+
return "Product{" +
76+
"id=" + id +
77+
", name='" + name + '\'' +
78+
", description='" + description + '\'' +
79+
", price=" + price +
80+
", stock=" + stock +
81+
'}';
82+
}
83+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package examples.simple_crud.repository;
2+
3+
import examples.simple_crud.entity.Product;
4+
import jazzyframework.data.BaseRepository;
5+
6+
public interface ProductRepository extends BaseRepository<Product, Long> {
7+
}

0 commit comments

Comments
 (0)