81. What is the concept of Eager vs Lazy fetching in Hibernate/JPA?
- Eager loading is only for collections; lazy loading is only for single entity references
- Eager fetching loads the associated entities immediately when the parent is loaded; Lazy fetching delays loading until the association is actually accessed — reducing unnecessary database queries
- Eager fetching is always faster and should always be used for better performance
- Lazy loading requires a special @LazyLoad annotation on every field that uses it
Answer : B Explanation: FetchType controls when related entities are loaded from the database. FetchType.EAGER: associated data loaded immediately with the parent in the same query (or additional query). Default for: @ManyToOne, @OneToOne. @ManyToOne(fetch=FetchType.EAGER) — fetching User also fetches their Department immediately. Risk: causes performance problems when you have multiple EAGER associations. FetchType.LAZY: associated data loaded only when you access it (first access triggers a query). Default for: @OneToMany, @ManyToMany. @OneToMany(fetch=FetchType.LAZY) — fetching Order does NOT load OrderItems until you call order.getItems(). Must still have an open Session when accessing lazy collections. LazyInitializationException: accessing a lazy collection after the Session is closed causes this exception. Solutions: Open Session in View pattern (not recommended — keeps session open for the entire request), @Transactional on service method ensures session stays open, JOIN FETCH in JPQL eagerly loads for specific queries, @EntityGraph for query-level eager loading. Best practice: keep all associations LAZY by default. Use JOIN FETCH or @EntityGraph in specific queries where you know you need the data. This gives maximum control and avoids N+1 problems and unnecessary data loading.
82. What is the difference between @OneToMany and @ManyToMany in JPA?
- @OneToMany is for parent-child relationships within the same Java class
- @OneToMany maps a one-to-many relationship (one Order has many OrderItems) stored as a foreign key in the child table; @ManyToMany maps a many-to-many relationship (many Students have many Courses) requiring a join table with foreign keys to both entities
- @ManyToMany can only be used with List; @OneToMany can only be used with Set
- Both annotations are identical — the difference is only in naming convention
Answer : B Explanation: JPA relationship annotations map object associations to database table relationships: @OneToMany: one entity (parent) has a collection of another entity (child). Database: child table has a foreign key column pointing to parent. Example: @OneToMany(mappedBy=”order”, cascade=CascadeType.ALL, fetch=FetchType.LAZY) private List<OrderItem> items. mappedBy: specifies which field in the child owns the relationship (child has @ManyToOne). The “owning” side (where the foreign key lives) is usually the @ManyToOne side. @ManyToMany: both entities can have collections of each other. Database: requires a join table (student_course) with foreign keys to both student and course tables. Example: @ManyToMany(fetch=FetchType.LAZY) @JoinTable(name=”student_course”, joinColumns=@JoinColumn(name=”student_id”), inverseJoinColumns=@JoinColumn(name=”course_id”)) private Set<Course> courses. One side is the owner (has @JoinTable), other side has mappedBy. Cascade types: CascadeType.ALL — all operations cascade. CascadeType.PERSIST — save parent also saves children. CascadeType.REMOVE — delete parent also deletes children (use carefully with @ManyToMany). Best practices: prefer Set over List for @ManyToMany (avoids duplicate join rows). For @ManyToMany with extra attributes on the join table: create a separate entity for the join table (Student, Enrollment, Course) with two @ManyToOne relationships.
83. What is Spring Security’s authentication flow for a JWT-based REST API?
- JWT authentication in Spring means storing the token in a server-side session for lookup
- JWT authentication: client sends credentials → server validates and returns a signed JWT → client includes JWT in Authorization header of subsequent requests → Spring Security filter validates the token on each request without any server-side session state
- JWT tokens are only valid for a single request and must be refreshed for every API call
- Spring Security handles JWT automatically with no custom code when spring-security is included
Answer : B Explanation: JWT (JSON Web Token) enables stateless authentication for REST APIs. JWT structure: Header.Payload.Signature (Base64 encoded, signed with secret or RSA key). Contains: userId, roles, expiration — verifiable without server-side storage. Spring Security JWT flow: Login endpoint (/api/auth/login): receives username/password. AuthenticationManager validates credentials against UserDetailsService. On success: generate JWT (using jjwt or java-jwt library). Return JWT to client. Client stores JWT (localStorage, memory). Subsequent requests: client includes: Authorization: Bearer <jwt-token>. Custom JwtAuthenticationFilter (extends OncePerRequestFilter): extracts token from Authorization header. Validates signature, checks expiry. Extracts user details from token. Sets Authentication in SecurityContextHolder. SecurityContextHolder.getContext().setAuthentication(authToken). Spring Security allows the request to proceed. Stateless: disable session management: http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS). Disable CSRF: http.csrf().disable() — JWT tokens are CSRF-safe (not sent automatically by browsers). Refresh tokens: short-lived access token (15 min) + long-lived refresh token (7 days). OAuth2/OpenID Connect: production apps often use Keycloak, Auth0, Okta instead of rolling custom JWT auth — Spring Security has built-in OAuth2 resource server support.
84. What is the role of @RequestBody and content negotiation in Spring REST?
- @RequestBody is used to send responses — it is equivalent to @ResponseBody in Spring
- @RequestBody deserializes the HTTP request body (JSON/XML) into a Java object; content negotiation determines the format for responses based on the Accept header — Spring’s HttpMessageConverters handle the conversion automatically
- @RequestBody only works with String type and cannot deserialize into complex Java objects
- Content negotiation requires manual format detection code in every controller method
Answer : B Explanation: @RequestBody deserializes HTTP request body into Java objects: @PostMapping(“/users”) public ResponseEntity<User> createUser(@RequestBody User user) { … }. Spring uses Jackson to parse the incoming JSON into a User object automatically. @Valid or @Validated can be added for Bean Validation: @PostMapping(“/users”) public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest request). Bean Validation annotations: @NotNull, @NotBlank, @Email, @Size(min=3, max=50), @Min(0), @Max(150) on fields. @ExceptionHandler(MethodArgumentNotValidException.class) handles validation errors globally. Content Negotiation: determines format of response based on client preferences. Accept: application/json — client wants JSON (default in most APIs). Accept: application/xml — client wants XML. Produces: @GetMapping(value=”/users”, produces={“application/json”,”application/xml”}) — server declares what it can produce. HttpMessageConverters: Jackson (for JSON), JAXB2 (for XML if on classpath). Spring Boot auto-configures both. ContentNegotiationManager: resolves which format to use based on: Accept header (most common), URL extension (/users.json vs /users.xml), Query parameter (?format=json). Best practice: for REST APIs, accept and return JSON only — simplifies things. Use @RequestBody for incoming data, ResponseEntity for outgoing data.
85. What is the purpose of the @SpringBootTest annotation in testing?
- @SpringBootTest is used to deploy a Spring Boot application to a test cloud environment
- @SpringBootTest loads the complete Spring ApplicationContext for integration testing — starting the actual application (including embedded server and all beans) so tests run against the full application stack
- @SpringBootTest replaces JUnit 5 and provides a completely separate testing framework
- @SpringBootTest only tests Spring Boot auto-configuration and ignores application code
Answer : B Explanation: @SpringBootTest is the foundation for Spring Boot integration tests. Full context loading: @SpringBootTest loads ALL Spring beans (real application context). @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) — starts the embedded Tomcat on a random port. For testing REST controllers end-to-end. @SpringBootTest(webEnvironment = WebEnvironment.MOCK) — default. Mocked servlet environment, no real HTTP. Used with MockMvc. Testing REST APIs: MockMvc (without actual server): @AutoConfigureMockMvc — injects MockMvc. mockMvc.perform(get(“/users”)).andExpect(status().isOk()).andExpect(jsonPath(“$.name”).value(“John”)). TestRestTemplate (with real server): @Autowired TestRestTemplate restTemplate; restTemplate.getForObject(“http://localhost:”+port+”/users”, String.class). Slicing annotations (faster — only load relevant parts): @WebMvcTest — only web layer (controllers). No database, no service layer. Use @MockBean for dependencies. @DataJpaTest — only JPA layer (repositories). Uses in-memory H2 database. No web layer. @JsonTest — only Jackson serialization. @WebFluxTest — reactive web layer. Mocking: @MockBean — Spring-managed mock (Mockito under the hood). Replaces real bean in ApplicationContext. @Mock (Mockito) — used without Spring context. Best practice: unit tests with mocks (fast), integration tests with @SpringBootTest for key flows (slower).
86. What is the Java Reflection API and how is it used in frameworks?
- Java Reflection is a mirror-like debugging tool that reflects code back to developers for review
- Java Reflection API allows programs to inspect and manipulate the structure of classes, methods, fields, and annotations at runtime — used by Spring, Hibernate, JUnit, and other frameworks to implement DI, ORM, and testing without modifying application code
- Java Reflection is a compile-time feature that only works during the build process
- Reflection only works on public classes and cannot access private fields or methods
Answer : B Explanation: Java Reflection (java.lang.reflect) enables runtime introspection and manipulation of classes. Key operations: Get Class object: MyClass.class, obj.getClass(), Class.forName(“com.example.MyClass”). Inspect: clazz.getDeclaredFields() — all fields (including private). clazz.getDeclaredMethods() — all methods. clazz.getDeclaredAnnotations() — annotations. clazz.getDeclaredConstructors(). Manipulate: field.setAccessible(true) — bypass private access. field.set(obj, value) — set field value. method.invoke(obj, args) — call method. constructor.newInstance(args) — create instance. Read annotations: method.isAnnotationPresent(MyAnnotation.class), method.getAnnotation(Transactional.class). How frameworks use reflection: Spring DI: scans for @Component classes via reflection, creates instances, injects @Autowired fields (even private). Hibernate ORM: reads @Entity, @Column, @Id annotations to map Java classes to database tables without you writing the mapping code. JUnit: finds @Test, @BeforeEach methods and calls them via reflection. Jackson: reads field names and values via reflection to serialize/deserialize JSON. Performance note: reflection is slower than direct Java calls — frameworks cache reflection results. Modern alternative: annotation processors (compile-time code generation) — Lombok uses this to avoid runtime reflection overhead.
87. What is the difference between JDK, JRE, and JVM?
- JDK, JRE, and JVM are three different Java programming languages for different use cases
- JVM (Java Virtual Machine) executes bytecode; JRE (Java Runtime Environment) = JVM + standard libraries needed to run Java programs; JDK (Java Development Kit) = JRE + development tools (compiler javac, debugger, javadoc, jar)
- JDK is only needed for Java 8 — modern Java versions only require JRE
- JVM is a physical chip installed on the computer specifically for running Java programs
Answer : B Explanation: Understanding JVM/JRE/JDK is a fundamental Java question: JVM (Java Virtual Machine): the runtime engine that executes Java bytecode. Platform-specific implementation (JVM for Windows differs from JVM for Linux). Provides: memory management, garbage collection, JIT compilation, bytecode verification. Enables Java’s “Write Once, Run Anywhere” portability — bytecode runs on any JVM. JRE (Java Runtime Environment): JVM + the Java Class Library (standard library classes — java.lang, java.util, java.io etc.). Everything needed to RUN Java applications. End users who just run Java apps need JRE. JDK (Java Development Kit): JRE + development tools. javac — Java compiler (compiles .java to .class bytecode). java — JVM launcher. javadoc — documentation generator. jar — archive tool. jdb — debugger. jshell (Java 9+) — interactive REPL. Developers need JDK. JDK relationship: JDK ⊃ JRE ⊃ JVM (each is a superset of the next). Modern note: since Java 11, Oracle no longer distributes a separate JRE — only JDK. Distributions: Oracle JDK (commercial for production use in recent versions), OpenJDK (free, open-source — most common), Amazon Corretto, Eclipse Temurin (Adoptium), GraalVM (with native compilation). Spring Boot applications: need JDK to build, JRE/JDK to run. Docker containers typically use OpenJDK-based images.
88. What is Hibernate’s Second Level Cache and how is it configured?
- Second Level Cache in Hibernate refers to the L2 processor cache of the CPU
- Hibernate’s Second Level Cache is an optional, session-factory-scoped cache that stores entities across multiple sessions — reducing database hits for frequently accessed data — configured using providers like EHCache or Redis
- The second level cache stores only SQL query results and not entity objects
- Second Level Cache is automatically enabled in all Hibernate configurations with no setup needed
Answer : B Explanation: Hibernate has two cache levels: First Level Cache (Session Cache): always enabled, automatic. Scoped to a Session (single transaction). Entities fetched within the same session are cached — second fetch doesn’t hit DB. session.get(User.class, 1) twice in same session → only one DB query. Cleared when session closes. Second Level Cache (SessionFactory Cache): optional, shared across all Sessions. Must be explicitly configured. Entities that are @Cacheable are stored here. Second session.get(User.class, 1) → hits second-level cache, not DB. Persists until cache expires or invalidated. Configuration: Add EHCache dependency: spring-boot-starter-cache + ehcache. application.properties: spring.jpa.properties.hibernate.cache.use_second_level_cache=true, spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory. Annotate entity: @Entity @Cache(usage=CacheConcurrencyStrategy.READ_WRITE) public class User { … }. Cache concurrency strategies: READ_ONLY — immutable data. NONSTRICT_READ_WRITE — rarely updated. READ_WRITE — frequently updated (uses soft locks). TRANSACTIONAL — JTA environments. Query Cache: spring.jpa.properties.hibernate.cache.use_query_cache=true. @QueryHints({@QueryHint(name=HINT_CACHEABLE, value=”true”)}) — cache query results. Redis as second-level cache provider: used in distributed environments where multiple JVM instances share cache.
89. What are Java Design Patterns most commonly used in Spring applications?
- Spring applications only use the Singleton pattern — all other patterns are irrelevant
- Spring applications heavily use Singleton (bean scope), Factory (ApplicationContext creating beans), Proxy (AOP, @Transactional), Template (JdbcTemplate, RestTemplate), Observer (ApplicationEvents), and Front Controller (DispatcherServlet) patterns
- Design patterns are only for academic study and are not used in real Spring applications
- Spring replaces all design patterns with its own proprietary Spring-specific coding patterns
Answer : B Explanation: Spring is built on design patterns — recognizing them deepens your understanding: Singleton Pattern: Spring beans are singleton by default — one instance per ApplicationContext. @Scope(“singleton”) is the default scope. Factory Pattern: ApplicationContext (BeanFactory) creates beans based on configuration. @Bean methods are factory methods. The container is the factory. Proxy Pattern: Spring AOP creates proxies for @Transactional, @Cacheable, @Async beans. The proxy intercepts method calls, applies advice, delegates to the real object. Template Method Pattern: JdbcTemplate, RestTemplate, HibernateTemplate — template defines algorithm skeleton, subclasses (or lambda callbacks) fill in specific steps. Eliminates boilerplate while maintaining control. Observer Pattern: ApplicationEventPublisher / @EventListener. @Component publishes events, other @Components listen. Loose coupling between components. Front Controller Pattern: DispatcherServlet is the single front controller for all Spring MVC requests. Routes to specific handlers based on URL mapping. Decorator Pattern: @Cacheable wraps methods with caching behavior. Security proxy wraps beans. Strategy Pattern: different AuthenticationProvider implementations. Different DataSource configurations for different environments. Dependency Injection itself: enables Strategy, Decorator, and Observer patterns cleanly by injecting different implementations.
90. What is Apache Tomcat’s connection between Spring Boot and deployment?
- Spring Boot applications cannot use Tomcat — they must use Jetty or Undertow instead
- Spring Boot embeds Tomcat inside the application JAR — the application starts its own server with a simple java -jar command, eliminating the need for an external application server deployment and making the application fully self-contained
- Apache Tomcat must always be installed separately even when using Spring Boot applications
- Spring Boot’s embedded Tomcat only works in development — production requires external Tomcat
Answer : B Explanation: Traditional vs Spring Boot Deployment: Traditional WAR deployment: develop app → build WAR file → install Tomcat separately → copy WAR to webapps/ → start Tomcat → app is running. Multiple apps can share one Tomcat. Complex deployment process. Spring Boot embedded server: spring-boot-starter-web includes embedded Tomcat. Build: mvn package → creates executable JAR (fat JAR) containing application classes + all dependencies including Tomcat. Run: java -jar myapp-1.0.jar → Tomcat starts, app deploys automatically. Port: default 8080, change with server.port in application.properties. This is the recommended Spring Boot deployment model. Changing the embedded server: exclude Tomcat: <exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions>. Add Jetty: spring-boot-starter-jetty. Add Undertow: spring-boot-starter-undertow. Deploying to external Tomcat (traditional WAR): extend SpringBootServletInitializer, change packaging to WAR. Needed when organization mandates a shared app server. Docker deployment (modern standard): FROM openjdk:17-jre-slim, COPY target/app.jar app.jar, ENTRYPOINT [“java”,”-jar”,”/app.jar”]. Each Spring Boot JAR runs in its own Docker container — self-contained, portable, independently scalable.
