Response
I don't need to write files for this — the ask is to print the source in my reply. Here it is, following the house conventions (constructor injection, record DTOs in a holder class, `@Valid` validation, `ApiResponse` wrapping):
```java
package com.acme.billing;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Size;
import java.time.Instant;
public final class InvoiceDtos {
private InvoiceDtos() {
}
public record CreateInvoiceRequest(
@NotNull @Positive Long customerId,
@NotNull @Min(1) Long amountCents,
@Size(max = 200) String note
) {
}
public record InvoiceResponse(
long id,
long customerId,
long amountCents,
String note,
Instant createdAt
) {
}
}
```
```java
package com.acme.billing;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.acme.billing.InvoiceDtos.CreateInvoiceRequest;
import com.acme.billing.InvoiceDtos.InvoiceResponse;
@RestController
@RequestMapping("/api/billing")
public class InvoiceController {
private final InvoiceService invoiceService;
public InvoiceController(InvoiceService invoiceService) {
this.invoiceService = invoiceService;
}
@PostMapping("/invoices")
@ResponseStatus(HttpStatus.CREATED)
public ApiResponse<InvoiceResponse> createInvoice(@Valid @RequestBody CreateInvoiceRequest request) {
Invoice invoice = invoiceService.create(
request.customerId(),
request.amountCents(),
request.note()
);
InvoiceResponse body = new InvoiceResponse(
invoice.id(),
invoice.customerId(),
invoice.amountCents(),
invoice.note(),
invoice.createdAt()
);
return ApiResponse.ok(body);
}
}
```
Notes:
- Assumed `InvoiceService.create` returns an `Invoice` domain object exposing `id()`, `customerId()`, `amountCents()`, `note()`, `createdAt()` accessors — adjust the mapping if its actual shape differs.
- Applied house conventions: constructor injection (no Lombok/field injection), DTOs as records in an `InvoiceDtos` holder, `jakarta.validation` annotations on the request, and the response wrapped in `ApiResponse.ok(...)` rather than returned raw; validation errors are left to the existing `@RestControllerAdvice` rather than handled in the controller.