package com.ankurm.hibernatedemo.proxy; import static org.assertj.core.api.Assertions.assertThat; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.test.web.server.LocalServerPort; /** * Backs docs/11-proxies-and-lazy-initialization.md, chapter "OSIV: the default, its warning, and what it actually * masks". Deliberately does NOT set {@code spring.jpa.open-in-view} -- Boot's own default * (true) is what is under test here, including the startup warning Boot prints because you * didn't set it explicitly. * *

Needs a real servlet request (see {@link OsivBookController}, {@link OsivBookService}): * open-in-view is implemented by {@code OpenEntityManagerInViewInterceptor}, which only exists * for actual web applications -- the base app here runs with * {@code spring.main.web-application-type=none}, so this test overrides that to {@code servlet} * and spins up a random-port embedded Tomcat just for itself. */ @ExtendWith(OutputCaptureExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { // A dedicated config file that has NO spring.jpa.open-in-view key at all -- the shared // src/main/resources/application.yml sets it to false explicitly, which would hide // both the warning and the masking behaviour under test here. "spring.config.name=osiv-default-test" }) class OsivDefaultWarningTest { private static final Logger DEMO = LoggerFactory.getLogger("DEMO"); @Autowired private EntityManagerFactory emf; @LocalServerPort private int port; private Long seedBookWithReview() { EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); ProxyPublisher publisher = new ProxyPublisher("OSIV Default Press"); em.persist(publisher); ProxyBook book = new ProxyBook("OSIV Default Book", publisher); em.persist(book); ProxyReview review = new ProxyReview("Rendered fine", book); em.persist(review); em.getTransaction().commit(); Long id = book.getId(); em.close(); return id; } @Test void defaultOpenInView_printsStartupWarning_andMasksLazyLoadingDuringSerialization(CapturedOutput output) throws Exception { DEMO.info("checked at context-startup time: {}", output.toString().contains("open-in-view") ? "the OSIV warning line is present in the captured log" : "NOT FOUND"); assertThat(output.toString()) .as("Boot must print its open-in-view default warning verbatim when the property is left unset") .contains("spring.jpa.open-in-view is enabled by default"); Long id = seedBookWithReview(); HttpClient client = HttpClient.newHttpClient(); HttpResponse response = client.send( HttpRequest.newBuilder(URI.create("http://localhost:" + port + "/osiv/books/" + id)).GET().build(), HttpResponse.BodyHandlers.ofString()); DEMO.info("default OSIV (true): GET /osiv/books/{} -> status {}, body {}", id, response.statusCode(), response.body()); // With OSIV on, the session/EntityManager is still bound to the request thread while // Jackson serializes the response, so getReviews() initializes successfully instead of // throwing -- the exception is masked, not fixed. assertThat(response.statusCode()).isEqualTo(200); assertThat(response.body()).contains("Rendered fine"); } }