Spring Boot Course · Reference
The vocabulary of Spring Boot, grouped by the lesson that introduces each term. Terms here are used consistently across every lesson. Bookmark this; it grows over time.
spring-boot-starter-*. E.g. spring-boot-starter-webmvc (called spring-boot-starter-web before Spring Boot 4) pulls in everything needed to build a web/REST app, at compatible versions.sdk install java 21-tem and switch versions per project with sdk use — no manual PATH/JAVA_HOME editing.sdk install springboot) whose spring init command generates a project from the terminal — the CLI front-end to Spring Initializr.pom.xml file. (Gradle is the common alternative.)mvnw)mvnw / mvnw.cmd) that downloads and runs the exact Maven version the project needs, so contributors don't have to install Maven themselves. Run goals with it, e.g. ./mvnw spring-boot:run.@SpringBootApplication@RestController@GetMapping (and friends)@GetMapping("/books") handles GET /books; siblings are @PostMapping, @PutMapping, @DeleteMapping./api/books. Endpoints are organised around resources.com.example.library.book holds the book's controller, service, repository, model). The alternative is package-by-layer (separate controller/service/… packages). Either way, keep everything under the main class's package so component scanning finds it.11111111-1111-1111-1111-111111111111). We use it as the Book id: it can be generated by the app, isn't sequentially guessable, and stays unique across systems. The common alternative is an auto-incremented numeric Long. Jackson serialises a UUID as a JSON string.spring-boot-starter-webmvc. It reads an object's accessors to serialise it to JSON, and builds objects from incoming JSON. You rarely call it directly — Spring does.Content-Type: application/json.@ResponseBody@RestController, which is why every method there returns data.@RequestMapping@GetMapping, etc.) are specialised forms of it.@Service)@Service marks the class as a Spring-managed bean. The controller delegates the real work to it.@Component is the base; @Service, @Repository, and @Controller/@RestController are specialised forms that also document the class's architectural role.final, missing dependencies fail fast, the dependencies are explicit, and the class can be instantiated in a plain test without Spring. With a single constructor, no @Autowired is needed.@AutowiredPOST (create), GET (read), PUT (update/replace), DELETE (delete).@RequestBody@PathVariable@GetMapping("/{id}"), @PathVariable UUID id captures the {id} segment and converts it to the declared type.ResponseEntity200 OK (e.g. 201 Created, 204 No Content, 404 Not Found).2xx success (200 OK, 201 Created, 204 No Content), 4xx client error (400 Bad Request, 404 Not Found, 415 Unsupported Media Type), 5xx server error. Choosing the right one is part of designing a good API.Location header201 Created response sets it to the newly created resource's address; ResponseEntity.created(uri) sets both the status and this header.GET, PUT, and DELETE are idempotent; POST is not (each call creates another resource). A key reason create is POST and replace is PUT.@Entity, @Id, …) describing how Java objects map to database rows. It defines the contract; it doesn't run any SQL itself.JpaRepository and Spring Data generates the implementation at runtime.@Entity@IdUUID.JpaRepositoryJpaRepository<Book, UUID> supplies save, findById, findAll, deleteById, count, and more, with no implementation written by you.findByAuthor becomes WHERE author = ?. Keywords like Containing, IgnoreCase, GreaterThanEqual, and OrderBy…Desc compose into the SQL — no method body required.uuid column type that maps cleanly to the entity's UUID id.compose.yaml). Here it declares the Postgres container the app needs. With spring-boot-docker-compose on the classpath, Spring Boot starts that container on boot, reads its credentials, and auto-configures the datasource — no JDBC URL to write by hand.ddl-autospring.jpa.hibernate.ddl-auto) controlling how the schema is managed at startup: create-drop/update (dev convenience), or validate/none (production). We use validate — Hibernate only checks the entities match the schema; Liquibase owns the schema itself. Never let Hibernate rewrite a production schema.db/changelog/db.changelog-master.yaml), applying any not-yet-run changesets. The common alternative is Flyway.id + author. Liquibase records applied changesets in a tracking table and never re-runs them — so an applied changeset is immutable: to change the schema you append a new one.equals/hashCode) from annotations at compile time. Safe on entities: @Getter, @Setter, @NoArgsConstructor, id-only @EqualsAndHashCode. Avoid on entities: @Data, all-fields @EqualsAndHashCode, and unguarded @ToString.@RequestParam?, e.g. ?author=Bloch) to a method parameter. Use it for filtering, sorting, or paging a collection — as opposed to @PathVariable, which identifies a single resource in the path.UUID.randomUUID() is v4 (fully random, poor index locality).INSERT … SELECT in a sql change), contract (drop the old ones). Dropping first loses data on every environment the migration reaches — fine on a laptop, an incident in production. A migration copies what it finds; anything that needs a human decision is done afterwards through the API.book_author.book_id is a foreign key into book.id, and book_author.author_id into author.id.@ManyToManyBook.authors is Set<Author>. Needs a join table (@JoinTable) rather than a foreign-key column, and defaults to lazy fetching.book_author(book_id, author_id). Its composite primary key is the pair, so a link can't be recorded twice.@JoinTable / @JoinColumn@JoinTable names the join table and, through joinColumns and inverseJoinColumns, which column points back at this entity and which at the other. The side carrying it writes the rows.Set for a to-many association: the links are unique and unordered, Hibernate treats an unordered List as a bag (changes rewrite the whole collection; fetching two bags together fails), and id-based equals/hashCode make a HashSet of entities safe. Impose order at the API edge, not on the entity.orphanRemovalCascadeType.ALL on Book.authors, deleting one book would delete its authors, including a co-author still attached to other books. orphanRemoval deletes a child once it's removed from the parent's collection. Powerful but sharp: this course leaves cascade off, so authors and books keep independent lifecycles and the database's foreign key guards against accidental deletes. Reach for cascade only when you've deliberately decided a child should share its parent's lifecycle.record — that shapes data crossing the API boundary, separate from your entities. A request DTO (e.g. CreateBookRequest, no id) defines what you accept; a response DTO (e.g. BookResponse) defines what you send. A related entity is nested as its own response DTO, never as the entity — a book's authors are AuthorResponse records (id + name) — which keeps lazy collections and other persistence details off the wire. A request DTO with no id field leaves nothing for a client to smuggle. DTOs decouple the wire format from the schema.spring.jpa.open-in-view=true) that keeps the persistence session open for the whole request, so lazy associations can load during JSON rendering. Convenient — it's why mapping an entity to a DTO in the controller "just works" — but it can hide N+1 queries; many teams disable it.JOIN FETCH query or an entity graph.spring-boot-starter-validation.@NotNull, @NotBlank (non-null and non-whitespace), @Size(min,max), @Positive, @Min/@Max, @Email, @Pattern. Placed on the request DTO — the boundary shape — not the entity.@Valid@RequestBody parameter it tells Spring to check the object's constraints before the handler runs; a violation throws MethodArgumentNotValidException. Without it, constraints are ignored.MethodArgumentNotValidException@Valid body fails its constraints. Its BindingResult holds the per-field errors; a handler reads them to build a response. Maps naturally to 400 Bad Request.@ControllerAdvice / @RestControllerAdvice@ExceptionHandler methods apply across every controller — one central place to turn exceptions into HTTP responses. The @RestController variant writes return values to the response body (as JSON), like @RestController does.@ExceptionHandler@RestControllerAdvice it catches that exception from any controller and returns the error response to send. Spring picks the most specific handler, so a method for a precise type out-ranks a catch-all @ExceptionHandler(Exception.class).ResponseEntityExceptionHandlerProblemDetail-shaped handling for every standard Spring MVC exception (malformed JSON, type mismatch, unsupported method/media type, validation, …). You override individual methods (e.g. handleMethodArgumentNotValid) to customize, add @ExceptionHandlers for your own exceptions, and rely on specificity so a catch-all only fires for the truly unexpected.type, title, status, detail, instance, plus custom members. Spring's ProblemDetail class produces it; returning one sets the application/problem+json content type and the status. A single consistent error shape across the whole API.409 Conflict404, the client can fix it: change the state (delete or re-author the books) and the same request succeeds. The service checks and throws a ConflictException; the foreign key underneath remains the real guarantee.LIMIT and OFFSET down to the database. Bounds the work done by the database, server, and client regardless of table size. Pages are zero-based (page 0 is the first).Pageablepage, size, and sort query parameters — no @RequestParam needed — and handed to a repository method.Page / SlicePage<T> holds the slice of rows plus metadata (totalElements, totalPages, current number, size) — it runs an extra COUNT query to know the totals. Slice<T> skips the count and only knows whether a next page exists (cheaper; good for "load more"). Page.map(...) transforms each element to a DTO while preserving the metadata.@PageableDefaultsize and sort applied when a request omits them, e.g. @PageableDefault(size = 20, sort = "title"). Without it, an unparameterized request falls back to Spring's global default (20 rows, unsorted).PagedModel / serialization-mode=via_dtoPagedModel is Spring Data's small, stable representation of a page (content plus a page object with size, number, totalElements, totalPages). Turn it on with the property spring.data.web.pageable.serialization-mode=via_dto. The reference docs also show @EnableSpringDataWebSupport(pageSerializationMode = VIA_DTO), but on Spring Boot that annotation replaces Boot's auto-configuration and silently disables the spring.data.web.pageable.* properties (including max-page-size) — so the property is the form this course uses.@ManyToMany defaults to lazy fetching, which is the right default for a collection — but every lazy touch is a potential query, which is how the N+1 problem arises.@EntityGraph@EntityGraph(attributePaths = "authors"). The go-to fix for N+1 — the association is LEFT JOINed in rather than lazily loaded per row. Safe with pagination for to-one associations (a join adds columns, not rows); for to-many collections the query is more involved (modern Hibernate paginates the parents in a subquery first).JOIN FETCH)select b from Book b join fetch b.authors. The hand-written equivalent of @EntityGraph — reach for it inside a custom @Query.LazyInitializationExceptionCould not initialize proxy … no session). Common once spring.jpa.open-in-view=false: it turns a hidden lazy load into a loud failure, signalling exactly where you must fetch the association deliberately (a fetch join or @EntityGraph).@BatchSize / batch fetchinghibernate.default_batch_fetch_size = N (or @BatchSize(size = N)) collapses N per-row lazy loads into a few WHERE id IN (?, ?, …) queries — turning 1 + N into roughly 1 + (N / batchSize). Needs an open session when the collection is accessed.when(repo.findById(id)).thenReturn(...)); a mock also records interactions so you can assert they happened (verify(repo).save(...)). In Mockito a single @Mock object does both jobs: it implements the type but runs none of its code, returns defaults (null, 0/false, an empty Optional or collection) until stubbed, and records every call. @ExtendWith(MockitoExtension.class) puts a new one in each @Mock field before every test.@Test methods, lifecycle hooks (@BeforeEach), @DisplayName, and an extension model (@ExtendWith) that plugs in tools like Mockito. Ships with Spring Boot's test starter.@Mock creates a test double; when(...).thenReturn(...) stubs its answers; verify(...) asserts it was (or, with never(), wasn't) called; an ArgumentCaptor grabs the exact argument passed to a mock so you can assert on it. Enabled in JUnit 5 via @ExtendWith(MockitoExtension.class), which runs in strict-stubbing mode.assertThat(x).isEqualTo(y), isSameAs, assertThatThrownBy(() -> …).isInstanceOf(...).hasMessageContaining(...). Reads left-to-right and gives rich failure messages. The assertion style used throughout this course.@WebMvcTest@ControllerAdvice beans, converters, filters and Spring MVC's configuration; leaves out @Service, @Repository and other @Component beans, so no database is needed. Auto-configures MockMvc and, with AssertJ present, MockMvcTester.@MockitoBean@Mock, for when Spring builds the class under test. Creates a Mockito mock and registers it in the test's Spring context as the bean of that type — replacing the real bean, or creating it if the context has none — so it is injected wherever that type is needed: in a @WebMvcTest, into the controller. Reset after each test. Replaces Spring Boot's @MockBean, removed in Spring Boot 4.0.MockMvc / MockMvcTesterDispatcherServlet without starting a server: routing, conversion, validation, exception handling and JSON all run, on in-memory requests and responses. MockMvcTester is its AssertJ face — assertThat(mvc.get().uri(...)).hasStatusOk() — and the one this course uses; the older style is mockMvc.perform(...).andExpect(...).$ is the root, $.title a field, $.errors.name a nested field, $.content[0] an array element. Used in tests with extractingPath(...).@DataJpaTestDataSource and Liquibase; leaves out services, controllers and other @Component beans. Every test runs in a transaction that is rolled back at the end.PostgreSQLContainer.@ServiceConnection@Bean) as the connection for a Spring Boot service: Boot reads the address, user and password from the running container and configures, for a database, the DataSource from them. No spring.datasource.* properties needed.clear() empties it, so later reads go to the database.TestEntityManagerEntityManager, available in @DataJpaTest: persist to queue fixtures, flush to send the inserts, clear to empty the persistence context.SessionFactory when hibernate.generate_statistics=true — among them getPrepareStatementCount(), the number of SQL statements prepared. Reached with entityManagerFactory.unwrap(SessionFactory.class).getStatistics().JdbcTemplatequeryForObject for one value, queryForList for a column of rows). No JPA involved, so in a test it shows what the tables really hold. Doesn't flush the persistence context — flush first.@SpringBootTest@SpringBootApplication class: every bean, application.properties, Liquibase, DataSeeder. Its webEnvironment is a mock by default; RANDOM_PORT starts the embedded server on a free port.RestTestClientexchange() it, chain expectations on the status, headers and body (json(…, JsonCompareMode.STRICT)). @AutoConfigureRestTestClient points it at the server a RANDOM_PORT test started./v3/api-docs; its UI modules serve a docs page for it (Scalar at /scalar, or Swagger UI at /swagger-ui.html). Annotations (@Operation, @ApiResponse, @Schema…) add what the code can't say, and are read from interfaces too.curl) for each, and a "Test Request" button that sends it. Swagger UI is the older, widespread alternative.components, and used elsewhere through a $ref such as #/components/responses/BookNotFound. In springdoc, @ApiResponse(ref = "BookNotFound") points an operation at one.@ParameterObjectPageable, it documents page, size and sort instead of one object.