Add library-management module: console app evolved into a Spring Boot 4 REST API
Stage 2 console classes and the shared LoanPolicy, then a Spring Boot 4.1.2 + JPA API (H2, @Version optimistic locking, problem+json errors). Tests write output/ transcripts while asserting the same numbers; scripts regenerate everything. Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_017ic4b4DPL6dtpFg4U4LHc2
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
> add-book 978-0134685991|Effective Java|Joshua Bloch|2
|
||||
Added book: Effective Java (2 copies)
|
||||
> add-book 978-0596009205|Head First Java|Kathy Sierra|1
|
||||
Added book: Head First Java (1 copy)
|
||||
> add-book 978-0134685991|Effective Java|Joshua Bloch|2
|
||||
ERROR: ISBN 978-0134685991 already exists
|
||||
> add-member Asha
|
||||
Added member #1: Asha
|
||||
> add-member Ravi
|
||||
Added member #2: Ravi
|
||||
> borrow 978-0596009205 1 2026-11-01
|
||||
Loan #1: Asha borrowed 'Head First Java', due 2026-11-15
|
||||
> borrow 978-0596009205 2 2026-11-01
|
||||
ERROR: no copies of 'Head First Java' are available
|
||||
> borrow 978-0134685991 1 2026-11-01
|
||||
Loan #2: Asha borrowed 'Effective Java', due 2026-11-15
|
||||
> report
|
||||
Effective Java by Joshua Bloch: 1 available
|
||||
Head First Java by Kathy Sierra: 0 available
|
||||
ON LOAN #1: 'Head First Java' -> Asha, due 2026-11-15
|
||||
ON LOAN #2: 'Effective Java' -> Asha, due 2026-11-15
|
||||
> return 1 2026-11-20
|
||||
Loan #1 returned on 2026-11-20, fine Rs 10
|
||||
> return 1 2026-11-21
|
||||
ERROR: loan #1 was already returned on 2026-11-20
|
||||
> borrow 978-0596009205 2 2026-11-21
|
||||
Loan #3: Ravi borrowed 'Head First Java', due 2026-12-05
|
||||
> report
|
||||
Effective Java by Joshua Bloch: 1 available
|
||||
Head First Java by Kathy Sierra: 0 available
|
||||
ON LOAN #2: 'Effective Java' -> Asha, due 2026-11-15
|
||||
ON LOAN #3: 'Head First Java' -> Ravi, due 2026-12-05
|
||||
> quit
|
||||
@@ -0,0 +1,6 @@
|
||||
borrowed 2026-11-01, due 2026-11-15 (14 days)
|
||||
returned 2026-11-12 ( -3 days vs due) -> fine Rs 0
|
||||
returned 2026-11-15 ( +0 days vs due) -> fine Rs 0
|
||||
returned 2026-11-16 ( +1 days vs due) -> fine Rs 2
|
||||
returned 2026-11-20 ( +5 days vs due) -> fine Rs 10
|
||||
returned 2026-12-15 (+30 days vs due) -> fine Rs 60
|
||||
@@ -0,0 +1,57 @@
|
||||
> POST /api/books {"isbn":"978-0134685991","title":"Effective Java","author":"Joshua Bloch","copies":2}
|
||||
< 201 {"id":1,"isbn":"978-0134685991","title":"Effective Java","author":"Joshua Bloch","totalCopies":2,"availableCopies":2}
|
||||
|
||||
> POST /api/books {"isbn":"978-0134685991","title":"Effective Java","author":"Joshua Bloch","copies":2}
|
||||
< 409 {"detail":"ISBN 978-0134685991 already exists","instance":"/api/books","status":409,"title":"Conflict"}
|
||||
|
||||
> POST /api/books {"isbn":"978-0000000000","title":"","author":"Nobody","copies":0}
|
||||
< 400 {"detail":"request body failed validation","instance":"/api/books","status":400,"title":"Bad Request","errors":{"copies":"must be greater than or equal to 1","title":"must not be blank"}}
|
||||
|
||||
> POST /api/books {"isbn":"978-0596009205","title":"Head First Java","author":"Kathy Sierra","copies":1}
|
||||
< 201 {"id":2,"isbn":"978-0596009205","title":"Head First Java","author":"Kathy Sierra","totalCopies":1,"availableCopies":1}
|
||||
|
||||
> POST /api/books {"isbn":"978-0132350884","title":"Clean Code","author":"Robert Martin","copies":1}
|
||||
< 201 {"id":3,"isbn":"978-0132350884","title":"Clean Code","author":"Robert Martin","totalCopies":1,"availableCopies":1}
|
||||
|
||||
> POST /api/books {"isbn":"978-0321356680","title":"Effective Java 2e","author":"Joshua Bloch","copies":1}
|
||||
< 201 {"id":4,"isbn":"978-0321356680","title":"Effective Java 2e","author":"Joshua Bloch","totalCopies":1,"availableCopies":1}
|
||||
|
||||
> POST /api/members {"name":"Asha","email":"[email protected]"}
|
||||
< 201 {"id":1,"name":"Asha","email":"[email protected]"}
|
||||
|
||||
> POST /api/members {"name":"Ravi","email":"[email protected]"}
|
||||
< 201 {"id":2,"name":"Ravi","email":"[email protected]"}
|
||||
|
||||
> POST /api/loans {"memberId":1,"bookId":2}
|
||||
< 201 {"id":1,"bookTitle":"Head First Java","memberName":"Asha","borrowedOn":"2026-11-01","dueOn":"2026-11-15","returnedOn":null,"fine":0}
|
||||
|
||||
> POST /api/loans {"memberId":2,"bookId":2}
|
||||
< 409 {"detail":"no copies of 'Head First Java' are available","instance":"/api/loans","status":409,"title":"Conflict"}
|
||||
|
||||
> POST /api/loans {"memberId":99,"bookId":1}
|
||||
< 404 {"detail":"no member with id 99","instance":"/api/loans","status":404,"title":"Not Found"}
|
||||
|
||||
> POST /api/loans/1/return {"returnedOn":"2026-11-20"}
|
||||
< 200 {"id":1,"bookTitle":"Head First Java","memberName":"Asha","borrowedOn":"2026-11-01","dueOn":"2026-11-15","returnedOn":"2026-11-20","fine":10}
|
||||
|
||||
> POST /api/loans/1/return {"returnedOn":"2026-11-21"}
|
||||
< 409 {"detail":"loan 1 was already returned on 2026-11-20","instance":"/api/loans/1/return","status":409,"title":"Conflict"}
|
||||
|
||||
> POST /api/loans {"memberId":1,"bookId":1}
|
||||
< 201 {"id":2,"bookTitle":"Effective Java","memberName":"Asha","borrowedOn":"2026-11-01","dueOn":"2026-11-15","returnedOn":null,"fine":0}
|
||||
|
||||
> POST /api/loans {"memberId":1,"bookId":3}
|
||||
< 201 {"id":3,"bookTitle":"Clean Code","memberName":"Asha","borrowedOn":"2026-11-01","dueOn":"2026-11-15","returnedOn":null,"fine":0}
|
||||
|
||||
> POST /api/loans {"memberId":1,"bookId":4}
|
||||
< 201 {"id":4,"bookTitle":"Effective Java 2e","memberName":"Asha","borrowedOn":"2026-11-01","dueOn":"2026-11-15","returnedOn":null,"fine":0}
|
||||
|
||||
> POST /api/loans {"memberId":1,"bookId":2}
|
||||
< 422 {"detail":"Asha already has 3 active loans (max 3)","instance":"/api/loans","status":422,"title":"Unprocessable Content"}
|
||||
|
||||
> GET /api/books
|
||||
< 200 [{"id":1,"isbn":"978-0134685991","title":"Effective Java","author":"Joshua Bloch","totalCopies":2,"availableCopies":1},{"id":2,"isbn":"978-0596009205","title":"Head First Java","author":"Kathy Sierra","totalCopies":1,"availableCopies":1},{"id":3,"isbn":"978-0132350884","title":"Clean Code","author":"Robert Martin","totalCopies":1,"availableCopies":0},{"id":4,"isbn":"978-0321356680","title":"Effective Java 2e","author":"Joshua Bloch","totalCopies":1,"availableCopies":0}]
|
||||
|
||||
> GET /api/loans
|
||||
< 200 [{"id":1,"bookTitle":"Head First Java","memberName":"Asha","borrowedOn":"2026-11-01","dueOn":"2026-11-15","returnedOn":"2026-11-20","fine":10},{"id":2,"bookTitle":"Effective Java","memberName":"Asha","borrowedOn":"2026-11-01","dueOn":"2026-11-15","returnedOn":null,"fine":0},{"id":3,"bookTitle":"Clean Code","memberName":"Asha","borrowedOn":"2026-11-01","dueOn":"2026-11-15","returnedOn":null,"fine":0},{"id":4,"bookTitle":"Effective Java 2e","memberName":"Asha","borrowedOn":"2026-11-01","dueOn":"2026-11-15","returnedOn":null,"fine":0}]
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
5 loans, each with its own book and its own member
|
||||
findAllByOrderByIdAsc() then read book title + member name: 11 SQL statements
|
||||
findAllWithDetails() (join fetch) then the same reads: 1 SQL statement
|
||||
LoanService.listLoans() as called by GET /api/loans: 1 SQL statement
|
||||
@@ -0,0 +1,6 @@
|
||||
8 threads borrow the last copy at once (Book has @Version)
|
||||
successful borrows : 1
|
||||
refused by optimistic-lock failure : 6
|
||||
refused for any other reason : 1
|
||||
loan rows in DB : 1
|
||||
availableCopies : 0
|
||||
@@ -0,0 +1,4 @@
|
||||
8 threads borrow the last copy at once (read, check, write: no @Version)
|
||||
successful borrows : 8
|
||||
loan rows in DB : 8 <- one copy, 8 loans
|
||||
availableCopies : 0 <- the counter says everything is fine
|
||||
@@ -0,0 +1,40 @@
|
||||
> POST /books {"isbn":"978-0134685991","title":"Effective Java","author":"Joshua Bloch","copies":2}
|
||||
{"id":1,"isbn":"978-0134685991","title":"Effective Java","author":"Joshua Bloch","totalCopies":2,"availableCopies":2}
|
||||
< HTTP 201
|
||||
|
||||
> POST /books {"isbn":"978-0596009205","title":"Head First Java","author":"Kathy Sierra","copies":1}
|
||||
{"id":2,"isbn":"978-0596009205","title":"Head First Java","author":"Kathy Sierra","totalCopies":1,"availableCopies":1}
|
||||
< HTTP 201
|
||||
|
||||
> POST /books {"isbn":"","title":"","author":"Nobody","copies":0}
|
||||
{"detail":"request body failed validation","instance":"/api/books","status":400,"title":"Bad Request","errors":{"copies":"must be greater than or equal to 1","isbn":"must not be blank","title":"must not be blank"}}
|
||||
< HTTP 400
|
||||
|
||||
> POST /members {"name":"Asha","email":"[email protected]"}
|
||||
{"id":1,"name":"Asha","email":"[email protected]"}
|
||||
< HTTP 201
|
||||
|
||||
> POST /members {"name":"Ravi","email":"not-an-email"}
|
||||
{"detail":"request body failed validation","instance":"/api/members","status":400,"title":"Bad Request","errors":{"email":"must be a well-formed email address"}}
|
||||
< HTTP 400
|
||||
|
||||
> POST /members {"name":"Ravi","email":"[email protected]"}
|
||||
{"id":2,"name":"Ravi","email":"[email protected]"}
|
||||
< HTTP 201
|
||||
|
||||
> POST /loans {"memberId":1,"bookId":2}
|
||||
{"id":1,"bookTitle":"Head First Java","memberName":"Asha","borrowedOn":"2026-11-14","dueOn":"2026-11-28","returnedOn":null,"fine":0}
|
||||
< HTTP 201
|
||||
|
||||
> POST /loans {"memberId":2,"bookId":2}
|
||||
{"detail":"no copies of 'Head First Java' are available","instance":"/api/loans","status":409,"title":"Conflict"}
|
||||
< HTTP 409
|
||||
|
||||
> POST /loans/1/return
|
||||
{"id":1,"bookTitle":"Head First Java","memberName":"Asha","borrowedOn":"2026-11-14","dueOn":"2026-11-28","returnedOn":"2026-11-14","fine":0}
|
||||
< HTTP 200
|
||||
|
||||
> GET /books
|
||||
[{"id":1,"isbn":"978-0134685991","title":"Effective Java","author":"Joshua Bloch","totalCopies":2,"availableCopies":2},{"id":2,"isbn":"978-0596009205","title":"Head First Java","author":"Kathy Sierra","totalCopies":1,"availableCopies":1}]
|
||||
< HTTP 200
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
WARN 2278 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
|
||||
INFO 2278 --- [ main] c.ankurm.library.api.LibraryApplication : Started LibraryApplication in 5.911 seconds (process running for 6.599)
|
||||
@@ -0,0 +1,6 @@
|
||||
select m1_0.id,m1_0.email,m1_0.name from member m1_0 where m1_0.id=?
|
||||
select b1_0.id,b1_0.author,b1_0.available_copies,b1_0.isbn,b1_0.title,b1_0.total_copies,b1_0.version from book b1_0 where b1_0.id=?
|
||||
select l1_0.id from loan l1_0 where l1_0.member_id=? and l1_0.book_id=? and l1_0.returned_on is null fetch first ? rows only
|
||||
select count(l1_0.id) from loan l1_0 where l1_0.member_id=? and l1_0.returned_on is null
|
||||
insert into loan (book_id,borrowed_on,due_on,fine,member_id,returned_on,id) values (?,?,?,?,?,?,default)
|
||||
update book set author=?,available_copies=?,isbn=?,title=?,total_copies=?,version=? where id=? and version=?
|
||||
Reference in New Issue
Block a user