Monday, 21 July 2025

Difference between jakarta.validation-api & spring-boot-starter-validation

 

๐Ÿ”น 1. jakarta.validation-api

This provides the standard interface (API) for bean validation.
It includes annotations like:


@NotNull @Size(min = 3, max = 10) @Email @Min(1) @Max(100)

Dependency:


<dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> </dependency>

๐Ÿ”ธ But: this is only the API, not the implementation.
You still need something to run these validations (see below).


๐Ÿ”น 2. spring-boot-starter-validation

This is a Spring Boot starter that:

  • Automatically includes the jakarta.validation-api

  • Adds the actual implementation (Hibernate Validator)

  • Integrates validation into Spring Boot (like @Valid in controllers)

Dependency:


<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>

✅ So Which One Should You Use?

You should only use:


<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>

Because:

  • It already includes jakarta.validation-api

  • It also brings in Hibernate Validator

  • Works perfectly with Spring Boot MVC / REST with @Valid


✨ Example in Spring Boot:


public class UserDTO { @NotNull @Size(min = 3, max = 20) private String name; @Email private String email; }

In controller:


@PostMapping("/user") public ResponseEntity<String> createUser
(@Valid @RequestBody UserDTO userDto) { return ResponseEntity.ok("Valid user!"); }


-----------------Difference----------


๐ŸŽฏ Use in Real Projects

In Spring Boot apps, always use:


<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>

It brings:

  • Jakarta API (@NotNull, etc.)

  • Hibernate Validator engine

  • Spring integration (works with @Valid in controllers)


๐Ÿง  Tricky Interview Q&A

1. Q: If I only add jakarta.validation-api to my pom.xml, will validation work?

๐Ÿ‘‰ A: No, because jakarta.validation-api only provides interfaces and annotations.

You still need an implementation (like Hibernate Validator).


2. Q: What's the benefit of using spring-boot-starter-validation over directly

adding jakarta.validation-api and Hibernate Validator?

๐Ÿ‘‰ A: spring-boot-starter-validation bundles everything you need and

auto-configures it for Spring Boot. Less config, more productivity.


3. Q: Can I use Jakarta Validation in non-Spring Java applications?

๐Ÿ‘‰ A: Yes, but you must manually include both jakarta.validation-api and

an implementation like Hibernate Validator.


4. Q: What happens behind the scenes when I annotate a DTO with @Valid

in Spring Boot?

๐Ÿ‘‰ A: Spring uses the Hibernate Validator (from the starter) to validate the

fields based on annotations. If validation fails,

a MethodArgumentNotValidException is thrown and handled globally.


5. Q: Which validation provider is included by default in Spring Boot

Starter Validation?

๐Ÿ‘‰ A: Hibernate Validator.


Happy Learning... :)


Thursday, 17 July 2025

Solving the N+1 Query Problem in REST APIs: A Real-World Banking Example (Made Easy for Spring Boot Developers)

If you're using Spring Boot with Hibernate (JPA) and a relational database like MySQL/PostgreSQL, the N+1 Query Problem can silently hurt your API performance.

Let’s understand this issue in simple steps using a real-world banking project example, and how to fix it using Spring Boot tricks.


๐Ÿ“Œ What is the N+1 Problem?

The N+1 problem occurs when:

  • 1 SQL query fetches the main (parent) data — for example, bank accounts.

  • Then N additional SQL queries are executed for related (child) data — like each account’s transactions.

Expected: 1 smart query to fetch everything. ❌ Actual: 1 query for accounts + N queries for transactions = N+1 total queries.

This increases database load and slows down your REST APIs.


๐Ÿฆ Spring Boot Banking API Example

Say you build a banking dashboard endpoint:

@GetMapping("/api/accounts")
public List<AccountDTO> getAllAccounts() {
    List<Account> accounts = accountRepository.findAll();
    return accounts.stream()
        .map(account -> new AccountDTO(account.getId(), account.getTransactions()))
        .collect(Collectors.toList());
}

Behind the scenes:

  • findAll() runs: SELECT * FROM account;

  • Then for each account, Hibernate runs: SELECT * FROM transaction WHERE account_id = ?;

➡️ With 100 accounts, this results in 101 queries. That’s the N+1 problem.


Why Is It a Big Deal?

  • ๐Ÿšซ Bad for performance: 100 queries slow down response time.

  • ๐Ÿ”ฅ Heavy DB load: Affects scaling when users grow.

  • ๐Ÿงช Hard to debug: Looks fine in code, but performs poorly in production.


How to Fix N+1 in Spring Boot (Step-by-Step)

✅ 1. Use JOIN FETCH in JPA Query

@Query("SELECT a FROM Account a JOIN FETCH a.transactions")
List<Account> findAllWithTransactions();

✅ Fetches everything in 1 query.

✅ 2. Use JPA Entity Graphs

@EntityGraph(attributePaths = {"transactions"})
List<Account> findAll();

✅ Cleaner and better for dynamic loading.

✅ 3. Use DTO Projection (Recommended for REST)

@Query("SELECT new com.bank.dto.AccountDTO(a.id, t) 
FROM Account a JOIN a.transactions t")
List<AccountDTO> getAccountDTOs();

✅ Loads only the required data — no extra queries.

✅ 4. Use Batch Fetching (Optional)

In application.properties:

spring.jpa.properties.hibernate.default_batch_fetch_size=100

✅ Tells Hibernate to fetch child records in batches.


๐Ÿ’ก Best Practices & Tricky Interview Points

  • ๐Ÿงต Lazy vs Eager:

    • Use LAZY loading to avoid unnecessary data.

    • Use JOIN FETCH when you really need the related data.

  • ๐Ÿ›ก️ Avoid LazyInitializationException:

    • Use @Transactional in service layer if accessing lazy fields.

  • ๐Ÿงช Testing:

    • Use Hibernate query counters in tests to catch N+1 bugs.

    • Enable SQL logging: spring.jpa.show-sql=true

  • ๐Ÿง  Interview Tip:

    • Be ready to explain how you identify and fix N+1 using Spring Boot tools.


๐Ÿš€ Summary: Fixing N+1 in Spring Boot

Problem Fix
Too many queries Use JOIN FETCH
Lazy loading issues Use EntityGraph or @Transactional
Poor API performance Use DTO projections
Query explosion Use batch fetch settings

๐Ÿง  Final Thought

"The fastest code isn’t the one that runs first — it’s the one that hits the DB the least.”

If you're building REST APIs for enterprise, finance, or dashboards — fixing N+1 makes your system faster, lighter, and scalable.

Happy Learning :) 


Sunday, 13 July 2025

JWT Interview Q & A asked in MNC company

 

๐Ÿ” 1. How does Spring Security integrate with JWT-based authentication?

Answer:
Spring Security provides a flexible filter chain where you can plug in your own OncePerRequestFilter (e.g., JwtAuthenticationFilter) to intercept incoming requests and:

  • Extract the JWT from the Authorization header

  • Validate it

  • Set the Authentication object in SecurityContextHolder

➡️ This allows stateless authentication using JWT.


๐Ÿ” 2. Why do we use OncePerRequestFilter in JWT security setup?

Answer:
OncePerRequestFilter ensures your filter runs only once per request, making it ideal for:

  • Checking JWT

  • Verifying token signature

  • Setting authentication context

If used wrongly, it can cause repeated token processing.


๐Ÿ” 3. Can we disable session creation in Spring Security for JWT?

Answer:
Yes. JWT is stateless, so we must disable session creation:


http.sessionManagement()

    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);


Without this, Spring may still create sessions and defeat the purpose of using JWT.


๐Ÿ” 4. Where do you validate the JWT token in Spring Boot?

Answer:
In a custom JWT filter, before the request reaches the controller:

  • You extract the token from Authorization header

  • Validate the signature and expiration

  • Fetch user details (optional)

  • Set Authentication in SecurityContext


๐Ÿ” 5. What happens if the JWT token is expired?

Answer:
When a JWT token is expired, it throws a specific exception — most commonly:


io.jsonwebtoken.ExpiredJwtException


In your custom JWT filter (usually extending OncePerRequestFilter), you should catch this exception and return a proper HTTP response:


try {

    // validate token logic

} catch (ExpiredJwtException e) {

    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

    response.getWriter().write("Token expired. Please login again or use refresh token.");

    return;

}


๐Ÿ“Œ HTTP Response:


401 Unauthorized  

Body: Token expired. Please login again or use refresh token.


๐Ÿ”„ Best Practice: Use a refresh token mechanism so that expired tokens can be refreshed without forcing the user to re-login every time.


๐Ÿ” 6. How do you handle JWT in microservices architecture with Spring Security?

Answer:
In microservices, the best approach is to delegate all authentication to a central Auth Service. Here's the flow:

  1. User logs in via Auth Service → receives access token and refresh token.

  2. Access token is then passed in the Authorization: Bearer <token> header for every request to other services.

  3. Each service:

    • Validates the token using a shared secret or public key (if using asymmetric signing like RS256).

    • Authorizes the request based on roles in token claims.

  4. No session state is stored; each service is stateless.

Optional best practice:

  • Use Spring Cloud Gateway or an API Gateway to centralize token validation so individual services don't have to repeat it.


๐Ÿ” 7. Is it safe to keep user roles in JWT?

Answer:
Yes — if the JWT is signed properly using a secure algorithm (HS256, RS256) and a strong secret/private key.

You can embed roles in the JWT payload like this:


{

  "sub": "user1",

  "roles": ["ROLE_ADMIN", "ROLE_USER"],

  "exp": 1723489234

}


๐Ÿ“Œ In your Spring Boot filter, you extract these roles and convert them to GrantedAuthority:


UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(

    username, null, authoritiesFromToken

);


⚠️ Do not trust claims blindly if the signature is invalid or token is tampered.

✅ Signed tokens = safe to use for roles
❌ Unsigned (alg: none) or weak key = huge security risk


๐Ÿ” 8. What is the best way to store JWT tokens on the frontend?

Answer:

  • Access token: HttpOnly Secure Cookie (to avoid XSS)

  • Refresh token: also in HttpOnly cookie or encrypted local storage

❌ Avoid storing in localStorage or sessionStorage — vulnerable to XSS attacks.


๐Ÿ” 9. Can we use Spring Security with both Session and JWT?

Answer:
Not advisable. Choose one:

  • Use Session + CSRF for monoliths or UI-driven apps

  • Use JWT (stateless) for REST APIs and microservices

Mixing both often leads to confusion and security holes.


๐Ÿ” 10. How do you implement role-based access with JWT + Spring Security?

Answer:

  1. Encode roles into JWT claims.

  2. In your filter, extract and set GrantedAuthority in Authentication.

  3. Then use:

@PreAuthorize("hasRole('ADMIN')")


or


http.authorizeHttpRequests().requestMatchers("/admin/**").hasRole("ADMIN")


✅ Don’t forget to prefix roles with "ROLE_".


Wednesday, 16 April 2025

๐Ÿ”ฎ Understanding Future in Java (With Simple Example)

 In Java, working with multithreading and asynchronous programming is made much easier with the help of the java.util.concurrent package. One of the key components in this package is the Future interface.

If you’ve ever needed to run a task in the background and retrieve the result once it's done — without blocking your entire program — then Future is your friend.


๐Ÿš€ What is Future?

A Future represents the result of an asynchronous computation. It acts like a placeholder for a value that will eventually be available after a long-running task completes.

In simple terms, when you submit a task to a thread pool (using an ExecutorService), instead of immediately getting the result, you get a Future object that promises to hold the result once the task finishes.


๐Ÿงต Why Use Future?

  • Perform background operations without blocking the main thread.

  • Check if a task is done with .isDone().

  • Cancel a running task with .cancel(true).

  • Get the result later using .get() (blocks if the result isn't ready).


๐Ÿง‘‍๐Ÿ’ป Basic Example: Using Future with Callable

Here’s a beginner-friendly example showing how to use Future in Java:


import java.util.concurrent.*; public class FutureExample { public static void main(String[] args) throws Exception { // Step 1: Create a thread pool (ExecutorService) ExecutorService executor =
Executors.newSingleThreadExecutor(); // Step 2: Submit a Callable task to the executor Future<Integer> future = executor.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { // Simulate long-running task (e.g., network call, calculation) Thread.sleep(2000); // 2 seconds delay return 10 + 20; } }); System.out.println("Task submitted... Doing other work while waiting"); // Step 3: Do something else while the task runs // Step 4: Get the result (this will block if the task is not finished) Integer result = future.get(); // Step 5: Print the result System.out.println("Result from background task: " + result); // Step 6: Shutdown the executor executor.shutdown(); } }

๐Ÿ–จ️ Output:


Task submitted... Doing other work while waiting Result from background task: 30

๐Ÿ” Explanation:

ExecutorService executor = Executors.newSingleThreadExecutor();

Creates a thread pool with a single thread that will run the submitted tasks.

Future<Integer> future = executor.submit(...)

Submits a Callable task (which returns a value), and returns a Future object.

future.get();

Waits for the task to complete and returns the result. If the task isn’t done yet, it blocks the current thread until it is.

executor.shutdown();

Always shut down the executor to avoid memory leaks or keeping the app running unnecessarily.


๐Ÿ“Œ Additional Tips

  • future.isDone() → returns true if the task is completed.

  • future.cancel(true) → cancels the task if it's not finished yet.

  • Callable<V> vs Runnable: use Callable if you need to return a value or throw exceptions.


๐Ÿค” When Should You Use Future?

Use Future when you:

  • Need to perform background tasks (like file I/O or API calls).

  • Want to run multiple tasks in parallel and wait for results.

  • Want the ability to cancel a task if it’s taking too long.


๐Ÿ’ก Bonus: Want More Power? Try CompletableFuture

If you’re looking for even more flexibility (like chaining tasks, handling errors, async pipelines), check out CompletableFuture. It’s the modern alternative introduced in Java 8.