Vibe Codex для Spring Boot: контроллеры, JPA, тесты
Java — это язык, где правильное «скучное» решение всегда длиннее, чем хочется. Хорошо, когда писать его не приходится.
Spring Boot — это конструктор, где 70% кода — это слой, в котором ничего не происходит: DTO, мапперы, репозитории, конфигурации. Vibe Codex закрывает этот слой за минуты, а человек остаётся в зоне ответственности за бизнес-логику и архитектурные решения.
REST-контроллер с валидацией
$ vibe-codex "REST-контроллер /api/v1/orders, \
POST: create — принимает CreateOrderRequest, \
GET: list с пагинацией, \
GET: by id, \
использует Jakarta Validation"
[plan] 5 files:
+ controller/OrderController.java
+ dto/CreateOrderRequest.java
+ dto/OrderResponse.java
+ service/OrderService.java
+ service/OrderServiceImpl.java
// controller/OrderController.java
@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
@Validated
public class OrderController {
private final OrderService orderService;
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public OrderResponse create(@Valid @RequestBody CreateOrderRequest request,
@AuthenticationPrincipal User user) {
return orderService.create(request, user);
}
@GetMapping
public Page<OrderResponse> list(@PageableDefault(size = 20) Pageable pageable,
@AuthenticationPrincipal User user) {
return orderService.list(user, pageable);
}
@GetMapping("/{id}")
public OrderResponse byId(@PathVariable @Positive Long id,
@AuthenticationPrincipal User user) {
return orderService.byId(id, user);
}
}
Заметьте: @AuthenticationPrincipal — потому что в проекте Spring Security, а не «передавайте userId в query». Vibe Codex прочитал конфиг и подсмотрел.
JPA-репозиторий с проекциями
$ vibe-codex "проекция OrderSummary (id, total, status, createdAt) \
для OrderRepository, метод findSummaryByUserId"
public interface OrderRepository extends JpaRepository<Order, Long> {
interface OrderSummary {
Long getId();
BigDecimal getTotal();
OrderStatus getStatus();
Instant getCreatedAt();
}
Page<OrderSummary> findSummaryByUserId(Long userId, Pageable pageable);
}
Никаких SELECT *, никаких @Query там, где справляется derived query.
MapStruct без копипасты
В Spring-проектах маппер — самое скучное, что можно представить. Vibe Codex генерирует интерфейс с правильными @Mapping, проверяет, что все поля DTO покрыты, и предупреждает, если нет.
$ vibe-codex "MapStruct маппер Order → OrderResponse, \
total из BigDecimal в строку с двумя знаками, \
createdAt в ISO-8601"
[mapping] 7/7 fields covered
[warn] поле customerEmail в DTO отсутствует — пропустить или добавить?
Тесты: JUnit 5 + Testcontainers
$ vibe-codex "интеграционный тест OrderControllerIT, \
Testcontainers с Postgres, проверяет POST /orders и \
GET /orders/{id}"
@SpringBootTest
@AutoConfigureMockMvc
@Testcontainers
class OrderControllerIT {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16")
.withDatabaseName("test")
.withUsername("test")
.withPassword("test");
@DynamicPropertySource
static void props(DynamicPropertyRegistry r) {
r.add("spring.datasource.url", postgres::getJdbcUrl);
r.add("spring.datasource.username", postgres::getUsername);
r.add("spring.datasource.password", postgres::getPassword);
}
@Autowired MockMvc mvc;
@Test
void createAndFetchOrder() throws Exception {
var location = mvc.perform(post("/api/v1/orders")
.contentType(APPLICATION_JSON)
.content("""
{ "items": [{ "sku": "SKU-1", "qty": 2 }] }
"""))
.andExpect(status().isCreated())
.andReturn().getResponse().getHeader("Location");
mvc.perform(get(location))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value("CREATED"));
}
}
Flyway-миграции
Vibe Codex знает Flyway-конвенцию V{version}__description.sql и не позволяет себе писать миграции «в файле V1, дольше менять».
$ vibe-codex "миграция: добавить колонку customer_email \
в orders, индекс по email, заполнить из join с users"
[plan] 1 file: db/migration/V20260512_01__order_customer_email.sql
[plan] downgrade: V20260512_01__order_customer_email_down.sql
«В Spring Boot стиль и порядок ценнее изящества. Хороший AI-ассистент даёт ровно то, что ревьюер хотел бы увидеть, без обсуждений».
Острые края
- Vibe Codex не пишет в JPA-запросах PG-операторы вроде
?для jsonb — это крашит Hibernate. Используетjsonb_extract_path. - Не использует
@Transactionalвнутри тестов с Testcontainers без чёткой причины. - Кладёт DTO и Entity в разные пакеты — никаких «универсальных классов на всё».
- На
--strictдобавляет@NonNull/@Nullableаннотации.
Когда переключаться на reasoning
Один контроллер — быстрая модель. Архитектурное «как разнести модуль на три bounded context» — Claude Opus 4.7 или GPT 5.2 Codex с --explain. План сначала, код потом.
Spring Boot хорош тем, что в нём всё на своих местах. Vibe Codex это уважает: не изобретает «как удобнее», а делает «как принято в вашем проекте». Ревьюеру не за что зацепиться, кроме самой логики — на ней и сосредоточиться.
Готов попробовать?
brew tap xrouter-chat/tap && brew install vibe-codex — и за 30 секунд ты в деле.
Поставить Vibe Codex →