0% found this document useful (0 votes)
32 views110 pages

Troubleshooting 401 Unauthorized Errors

The document discusses a 401 Unauthorized error encountered when accessing a Product service microservice via Postman, indicating issues with JWT authentication. It outlines the configuration of security settings in both User and Product services, emphasizing the need for proper JWT handling and security filter chain setup. Recommendations include ensuring JWT is sent in requests, validating the token's authenticity, and configuring the Product service to allow public access to certain endpoints while requiring authentication for others.

Uploaded by

avadhutjc
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views110 pages

Troubleshooting 401 Unauthorized Errors

The document discusses a 401 Unauthorized error encountered when accessing a Product service microservice via Postman, indicating issues with JWT authentication. It outlines the configuration of security settings in both User and Product services, emphasizing the need for proper JWT handling and security filter chain setup. Recommendations include ensuring JWT is sent in requests, validating the token's authenticity, and configuring the Product service to allow public access to certain endpoints while requiring authentication for others.

Uploaded by

avadhutjc
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

hey i'm getting on postman 401 Unauthorized

[Link] --product service microservice

I used User service another project microservice and both microservices are talking via
authentication commons.

In user service I have security file see below non of my api's are working

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import
[Link].
OAuth2AuthorizationServerConfiguration;
import
[Link].O
Auth2AuthorizationServerConfigurer;
import
[Link];
import [Link];
import [Link];
import [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

@Configuration
@EnableWebSecurity
public class SecurityConfig {
/*
private BCryptPasswordEncoder bCryptPasswordEncoder;

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 1/110
public SecurityConfig(BCryptPasswordEncoder bCryptPasswordEncoder) {
[Link] = bCryptPasswordEncoder;
}*/

@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
[Link]();

http
.securityMatcher([Link]())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.oidc([Link]()) // Enable OpenID Connect 1.0
)
// Redirect to the login page when not authenticated from the
// authorization endpoint
.exceptionHandling((exceptions) -> exceptions
.defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint("/login"),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
)
);

return [Link]();
}

// @Bean
// @Order(2)
// public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
// throws Exception {
// http
// .authorizeHttpRequests((authorize) -> authorize
// // .requestMatchers("/admin/**").hasRole("ADMIN") // Only accessible to ADMIN
// // .requestMatchers("/user/**").hasRole("USER") // Only accessible to USER
// //.requestMatchers("/users/login/**").permitAll() // Allow all to login
// //.requestMatchers("/oauth2/**").permitAll()
// // .requestMatchers("users/login").authenticated()
// .anyRequest().permitAll() // All other requests need authentication
// )
//
// // Form login handles the redirect to the login page from the
// // authorization server filter chain
// .formLogin([Link]());
//
// return [Link]();
// }

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 2/110
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> {
try {
requests
.anyRequest().permitAll()
// .requestMatchers("/product/id").authenticated() // Require
authentication for this pattern //("/product/*").authenticated()
//.anyRequest().permitAll() // Allow all other requests without
authentication
.and().cors().disable()
.csrf().disable();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
);

return [Link]();
}

// @Bean
// public UserDetailsService userDetailsService() {
// UserDetails userDetails = [Link]()
// .username("user")
// .password([Link]("password"))
// .roles("USER")
// .build();
//
// return new InMemoryUserDetailsManager(userDetails);
// }

/* @Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient oidcClient = [Link]([Link]().toString())
.clientId("oidc-client")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("[Link]
.postLogoutRedirectUri("[Link]
.scope([Link])
.scope([Link])
.clientSettings([Link]().requireAuthorizationConsent(true).build())
.build();

return new InMemoryRegisteredClientRepository(oidcClient);


}*/

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 3/110
@Bean
public JWKSource<SecurityContext> jwkSource() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) [Link]();
RSAPrivateKey privateKey = (RSAPrivateKey) [Link]();
RSAKey rsaKey = new [Link](publicKey)
.privateKey(privateKey)
.keyID([Link]().toString())
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}

private static KeyPair generateRsaKey() {


KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = [Link]("RSA");
[Link](2048);
keyPair = [Link]();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}

@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return [Link](jwkSource);
}

@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return [Link]().build();
}

Got it 👍thanks for sharing your SecurityConfig.


The 401 Unauthorized you’re seeing from Postman when calling
[Link] usually means your Product service is expecting a JWT in
the request header, but either:

You are not sending the JWT from Postman, or

The JWT you are sending is not valid (expired, wrong signing key, wrong audience, etc.), or
Your security filter chain is misconfigured (permitting/denying incorrectly).

What’s happening in your setup

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 4/110
Your User Service is acting as an Authorization Server (issuing tokens).

Your Product Service is a Resource Server (validates tokens before allowing access).
Right now, your SecurityConfig in User Service has:

java

.anyRequest().permitAll()

That means you’re not really protecting endpoints in User Service (anyone can call them).
But your Product Service must still validate a token, which is why Postman calls fail with 401.

✅ Things you need to check


1. Are you including the JWT in Postman request headers?

Example:

makefile

Authorization: Bearer <your_access_token>

If not, you’ll always get 401 Unauthorized.


2. Does Product Service have a proper Resource Server config?
In your Product Service, you need something like this:

java

@Configuration
@EnableWebSecurity
public class ProductSecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/products/allProducts").authenticated()
.anyRequest().permitAll()
)
.oauth2ResourceServer(oauth2 -> [Link]()); // enable JWT validation

return [Link]();
}
}

And in [Link] of Product Service:

yaml

spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: [Link] # URL of your User Service (auth server)

3. Is the token generated from User Service valid?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 5/110
Call your login/authorization endpoint in User Service.
Grab the issued access_token.
Use that token in Postman for calling Product Service.

🔑 Flow You Should Test in Postman


1. Call User Service /login or /oauth2/token → get access_token.
2. Call Product Service:

bash

GET [Link]
Authorization: Bearer <token_from_user_service>

3. If configs are correct, you’ll now get 200 OK.

👉 To help you debug, can you confirm:


How are you generating the JWT in your User Service? (Do you already have a /token endpoint?)

And in Product Service, do you already have a SecurityConfig or only the one you pasted from User
Service?

That way I can show you exact configs for both sides.

see this is my productcontroller

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].*;

import [Link];

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 6/110
@RestController
@RequestMapping("/products")
public class ProductController {
private final AuthenticationCommons authenticationCommons;
private final ProductService productService;
private final GlobalExceptionHandler globalExceptionHandler;

@Value("${[Link]}")
private String serverPort;

@Qualifier("eurekaRegistration")
private Registration registration;

private EurekaClient eurekaClient;

@Autowired
public ProductController(@Qualifier("fakeStoreProductService1") ProductService
productService,
AuthenticationCommons authenticationCommons,
GlobalExceptionHandler globalExceptionHandler,
@Qualifier("eurekaRegistration") Registration registration) {
[Link] = productService;
[Link] = authenticationCommons;
[Link] = globalExceptionHandler;
[Link] = registration;
}

//[Link]
@GetMapping("/allProducts")
public List<Product> getAllProducts() {
InstanceInfo instanceInfo = [Link]().getInfo();
String instanceId = (instanceInfo != null) ? [Link]() : "Unknown
Instance";

[Link]("Port Name/Instance Name registered in Eureka Server is: " +


instanceId);
[Link]("Request arrived in product service in port no. " + serverPort);
return [Link]();
}

//[Link]
@GetMapping("/{id}")
public Product getProductById(@PathVariable("id") Long id, @RequestHeader("Authorization")
String token) throws InvalidTokenException {
UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException("Invalid token");
}

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 7/110
Product product = [Link](id);
[Link]("Check do Api requests are load balanced in product service");
return product;
}

//[Link]
@PostMapping("/all")
public Product postAllProducts(@RequestBody CreateProductRequestDto
createProductRequestDto) {
return [Link](
[Link](),
[Link](),
[Link](),
[Link](),
[Link]()
);
}

@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody
CreateProductRequestDto createProductRequestDto) {
return [Link](id, createProductRequestDto);
}

/* @GetMapping("/products1")
public List<ProductIdAndTitleProjection> getProductsByCategoryTitle(@RequestParam("title")
String title) {
return [Link](title);
}*/

//[Link]
@GetMapping("/categories/{title}")
public List<ProductIdAndTitleProjection>
getProductTitlesByCategoryTitle(@PathVariable("title") String categoryTitle) {
return [Link](categoryTitle);
}

//[Link]
@GetMapping("/categories/{title}/{id}")
public Product getFindNameOfProductByCategoryTitleAndProdId(@PathVariable("title")
String title, @PathVariable("id") Long id) {
return [Link](title, id);
}

@GetMapping("/allPrice")
public List<ProductPriceProjection> getPriceFromProduct() {
return [Link]();
}

/*
public ResponseEntity<Product> updateProduct(@PathVariable Long id, @RequestBody
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 8/110
Product updatedProduct) {
Product updatedProductResult = [Link](id, updatedProduct);
return new ResponseEntity<>(updatedProductResult, [Link]);
}

*/

Perfect 👌 thanks for sharing your ProductController.


Now it’s clear why you’re hitting 401 Unauthorized on Postman. Let’s break it down:

🔎 What your ProductController is doing

/products/allProducts → no authentication required (you don’t check token here).

/products/{id} → explicitly requires a token (@RequestHeader("Authorization") String token) and


validates it using your [Link](token).

So:

If you call /products/allProducts, the 401 is not coming from controller (because you don’t check
token there).
It must be coming from Spring Security filter chain in Product Service.

If you call /products/{id}, then the 401 will come from your manual check if token is
missing/invalid.

🚩 Likely problem
Right now, you haven’t shown me the SecurityConfig in Product Service.
If you copied something like from User Service or left defaults, Spring Boot security by default will
secure everything (every endpoint needs authentication). That explains the 401.

✅ Fix
In your Product Service you need a SecurityConfig like this:

java

@Configuration
@EnableWebSecurity
public class ProductSecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> [Link]())
.cors(cors -> [Link]())
.authorizeHttpRequests(auth -> auth
// allow public product list
.requestMatchers("/products/allProducts").permitAll()
// secure product by id (must pass Authorization header)
.requestMatchers("/products/**").authenticated()

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 9/110
// anything else -> permit
.anyRequest().permitAll()
)
.oauth2ResourceServer(oauth2 -> [Link]()); // enables JWT validation

return [Link]();
}
}

And in [Link] of Product Service:

yaml

spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: [Link] # URL of your User Service (auth server)

🔑 How the flow will work


1. Call User Service (/token or /login) to get a JWT.

2. Call Product Service:

http

GET [Link]

(works without token).

3. Call Product Service:

http

GET [Link]
Authorization: Bearer <token_from_user_service>

(works only with token, otherwise 401).

👉 Quick question for you:


Do you want all endpoints in Product Service secured by JWT, or only specific ones like
/products/{id}?

That will decide whether we configure permitAll() only for /allProducts or lock down everything by
default.

hey wait whatever required thing i will paste from product service wait

Got it 👍 paste me the Product Service SecurityConfig (or any other related config classes/yml) and I’ll
line it up with your ProductController so we can fix the 401 Unauthorized.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 10/110
package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

@Component
public class AuthenticationCommons {
private final RestTemplate restTemplate;

public AuthenticationCommons(RestTemplate restTemplate) {


[Link] = restTemplate;
}

public UserDto validateToken(String token) {


if (token == null) {
return null;
}

HttpHeaders headers = new HttpHeaders();


[Link]("Authorization", token);

// Create HttpEntity with headers


HttpEntity<String> entity = new HttpEntity<>(headers);

// Use exchange method to make the request with headers


ResponseEntity<UserDto> response = [Link](
//"[Link] //calling user service to validate token from a
Product service project
// "[Link] SERVICE TOKEN AND JWT/users/validate", //won't work if you have
space in the url
// "[Link] //if you have
space in the url then it won't work instead change "[Link]=" i.e. project name
without any spaces
"[Link]
[Link],
entity,
[Link]
);
// [Link]("Check do Api requests are load balanced in product service");
return [Link]();
}
}

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 11/110
package [Link];

import [Link];
import [Link];
import [Link];
import [Link];

@Configuration
public class RestTemplateConfig {

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

# Application Name and Server Configuration


[Link]=Product-Service
[Link]=TRACE
#mysql data accessing driver
[Link]-auto=update
[Link]=jdbc:mysql://:3306/local1891
#[Link]=jdbc:mysql://localhost:3306/selfProductServiceDB
[Link]=root
[Link]=0000
[Link]-class-name=[Link]
[Link]-sql=false
# Eureka Server Configuration
#[Link]=[Link]

[Link]-with-eureka=true
[Link]-registry=true

# this is an environment variable port number for product service


[Link] = ${PRODUCT_SERVICE_PORT}
#[Link] = 5555

[Link]=DEBUG
[Link]=DEBUG

#disable all logs


#[Link]=OFF

Thanks 🙌 now it’s clearer.


In your Product Service you’re not using Spring Security’s built-in JWT validation at all. Instead you’re
doing manual token validation via:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 12/110
[Link](token) → calls User Service at

pgsql

[Link]

(through Eureka + RestTemplate)


and returns a UserDto if the token is valid.

🔎 Why you’re getting 401 Unauthorized

Right now, your Product Service doesn’t have a custom SecurityConfig.


Without one, Spring Security’s default filter chain kicks in:
👉 all endpoints require authentication → Postman requests without credentials get 401.
That’s why even /products/allProducts is failing.

✅ Solution (two options)


Option 1: Keep manual token validation (your current approach)

Then you must tell Spring Security to not block endpoints:

java

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> [Link]())
.cors(cors -> [Link]())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/products/allProducts").permitAll() // public
.requestMatchers("/products/**").permitAll() // let controller handle
token check
.anyRequest().permitAll()
);

return [Link]();
}
}

👉 With this, Spring won’t return 401.


Instead, your controller will call [Link]() and throw InvalidTokenException
when needed.

Option 2: Use Spring Security Resource Server (recommended)

Instead of calling User Service from Product Service, you can configure Product Service as a resource
server to directly validate JWT.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 13/110
java

@Configuration
@EnableWebSecurity
public class ProductSecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> [Link]())
.cors(cors -> [Link]())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/products/allProducts").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> [Link]()); // enable JWT validation

return [Link]();
}
}

And in [Link]:

yaml

spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: [Link] # User Service Authorization Server

👉 In this case, you don’t need [Link]() anymore.


Spring Security will validate JWT automatically.

🚩 My suggestion
Since you already built AuthenticationCommons, go with Option 1 first (disable Spring Security’s default
lock and let your controller do validation).
Later, once things are working, migrate to Option 2 to use Spring Security’s resource server (cleaner &
standard).

👉 Do you want me to rewrite your Product Service SecurityConfig right now for Option 1 (manual
validation) so that Postman stops giving 401?

hey for while let's focus on this api

@GetMapping("/{id}")
public Product getProductById(@PathVariable("id") Long id, @RequestHeader("Authorization")
String token) throws InvalidTokenException {
UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException("Invalid token");
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 14/110
}

Product product = [Link](id);


[Link]("Check do Api requests are load balanced in product service");
return product;
}

Perfect 👍 let’s zoom in only on this endpoint:


java

@GetMapping("/{id}")
public Product getProductById(
@PathVariable("id") Long id,
@RequestHeader("Authorization") String token
) throws InvalidTokenException {
UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException("Invalid token");
}

Product product = [Link](id);


[Link]("Check do Api requests are load balanced in product service");
return product;
}

🔎 How it works
1. You expect the client (Postman, or another microservice) to call:

bash

GET [Link]
Authorization: Bearer <jwt-token>

2. [Link](token) makes a REST call to User Service:

pgsql

[Link]

with the same Authorization header.


3. User Service should:
Decode and validate the JWT.

Return a UserDto (user details) if valid.


Return 401/403 (or null) if invalid.
4. If UserDto is null, you throw InvalidTokenException.

🚨 Common reasons you still get 401

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 15/110
Wrong token header format:
Make sure you send Authorization: Bearer <token> in Postman.
Your code forwards the header as-is to User Service.
If you send only <token> without Bearer, validation will fail.
Spring Security default filter chain in Product Service:
If you didn’t disable it, Spring itself rejects the request with 401 before your controller runs.
(That’s why I suggested adding a SecurityConfig with .permitAll() earlier.)

User Service not exposing /users/validate correctly:


If that endpoint isn’t reachable or doesn’t return a UserDto, you’ll get null.

✅ Debug checklist
1. In Postman, call:

bash

GET [Link]
Authorization: Bearer <your_valid_token>

🔑 Make sure you actually have a valid JWT from User Service.
2. Add a log in [Link]:

java

[Link]("Validating token: " + token);

to confirm the token is being forwarded.

3. Test the validation endpoint directly in Postman:

bash

POST [Link]
Authorization: Bearer <your_valid_token>

→ Does this return a valid UserDto? If yes, Product Service should work.

👉 Question for you:


When you hit /products/{id} with a valid token in Postman, is the 401 Unauthorized coming from Product
Service filter chain (before it reaches your controller), or is it your User Service rejecting the token?

This decides whether we need to fix Product Service SecurityConfig or the validate endpoint in User
Service.

hey i have this [Link]


with "Authorization" and "value" :
"TPJvVgm7wsjHlGvsoJcaGcScfv1hu7tmIVeCVF3eqHEz50IlDiyxI6MfdTYrPo8RpsY1WDxudzDvVZG1

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 16/110
SMcFHLxkkquFm8FVYl4bBy5HSw76eBwLgd7XfYXbT9Z34jcB"

which is saved in db after user signup i generate not jwt token but random token consider i
saved it to db now when i'm login in that time i'm checking if token is present meaning user is
already sign in so below is api of user service on other project i'm having this api if token is
present in db then only product service will can check product number 6.
[Link]

package [Link];

import [Link];
import [Link];
import [Link];
import [Link].*;
import [Link];
import [Link].*;
import [Link];
import [Link];
import [Link];

@RestController
@RequestMapping("/users")
public class UserController {

private final UserService userService;

@Autowired
public UserController(UserService userService) {
[Link] = userService;
}

@PostMapping("/login")
public LoginResponseDto login(@RequestBody LoginRequestDto loginRequestDto) {
Token token = [Link]([Link](),
[Link]());

LoginResponseDto responseDto = new LoginResponseDto();


[Link](token);
return responseDto;
}

//without wrapping response into ResponseEntity


@PostMapping("/signup")
public SignUpResponseDto signUp(@RequestBody SignUpRequestDto requestDto) {
User user = [Link](
[Link](),
[Link](),
[Link]()
);

SignUpResponseDto responseDto = new SignUpResponseDto();


Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 17/110
[Link](user);
[Link]([Link]);

return responseDto;
}
/* @PostMapping("/signup")
public ResponseEntity<SignUpResponseDto> signUp(@RequestBody SignUpRequestDto
signUpRequestDto) {
User user = [Link]([Link](),
[Link](),
[Link]());

SignUpResponseDto responseDto = new SignUpResponseDto();


[Link](user);
// [Link]([Link]());
// [Link]([Link]());
[Link]([Link]); //additional Response status

ResponseEntity<SignUpResponseDto> responseEntity =
new ResponseEntity<>(responseDto, [Link](201));

return responseEntity;
}

*/

/* @PostMapping("/logout")
public ResponseEntity<Void> logout(@RequestBody LogoutRequestDto logoutRequestDto) {
[Link]([Link]());
return new ResponseEntity<>([Link]);
}*/

@PostMapping("/validate")
public UserDto validateToken(@RequestHeader("Authorization") String token) {
User user = [Link](token);
return [Link](user);
}

@PostMapping("/logout")
public ResponseEntity<String> logout(@RequestHeader("Authorization") String token) {
// Remove "Bearer" prefix if the token includes it
if ([Link]("Bearer ")) {
token = [Link](7);
}

User user = [Link](token);

if (user == null) {
// If the token was not found or already invalid, return 404 Not Found
return new ResponseEntity<>("Token not found or already logged out.",
HttpStatus.NOT_FOUND);
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 18/110
}

// If the logout was successful, return a confirmation message


return new ResponseEntity<>("User logged out successfully.", [Link]);
}
}

and also i wanted to tell you 7171 port is of api gateway and i register all microservices on
service discovery as i can see everything is working best on port [Link]

below is code for api gateway

[Link]=Api-Gateway

[Link]=7171

[Link]-with-eureka=true
[Link]-registry=true

# Route for Product Service


# Unique identifier for this route.
[Link][0].id=product-mapping
# Predicate to match the incoming request path.
[Link][0].predicates[0]=Path=/products/**
# URI for the target service to forward the request to.
[Link][0].uri=lb://PRODUCT-SERVICE

# Unique identifier for the cart route.


[Link][1].id=cart-mapping
# Predicate to match the incoming request path for cart.
[Link][1].predicates[0]=Path=/cart/**
# URI for the target cart service.
[Link][1].uri=lb://PRODUCT-SERVICE
#if there is another separate cart service running on different port, then we can use below
#[Link][1].uri=lb://CART-SERVICE (Multiple environments we need to
specify for ports same as product service)

Perfect 👍 thanks, now I have the full picture.


Let me summarize what you have:

API Gateway (7171) → forwards /products/** to PRODUCT-SERVICE (via Eureka).


User Service → issues random tokens (not JWT). On /signup it creates & stores the token in DB.

/login → checks credentials, returns token from DB.


/validate → checks if token exists in DB, returns UserDto.
/logout → removes token.

Product Service → gets requests from gateway.


Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 19/110
/products/{id} requires Authorization header.
It calls User Service /users/validate via AuthenticationCommons to check if token is valid.

So your tokens are opaque tokens (random strings), not JWT.


That means Spring Security’s OAuth2 resource server config is not needed (it expects JWT).
You are manually validating tokens by calling User Service. ✅
🔎 Why you get 401
Right now, you’re sending:

makefile

Authorization:
TPJvVgm7wsjHlGvsoJcaGcScfv1hu7tmIVeCVF3eqHEz50IlDiyxI6MfdTYrPo8RpsY1WDxudzDvVZG1SMcFHLxkkquFm8FV
Yl4bBy5HSw76eBwLgd7XfYXbT9Z34jcB

But your User Service validate API:

java

@PostMapping("/validate")
public UserDto validateToken(@RequestHeader("Authorization") String token) {
User user = [Link](token);
return [Link](user);
}

This expects the token exactly as stored in DB.


👉 No Bearer prefix is removed in this method.
So if you send Authorization: Bearer <token> it will fail.
If you send Authorization: <token> it will work.
But… in your logout API you are already handling Bearer prefix:

java

if ([Link]("Bearer ")) {
token = [Link](7);
}

That means validateToken should be updated to behave the same, otherwise it’s inconsistent.

✅ Fix 1 (make validateToken consistent with logout)


Update validate endpoint:

java

@PostMapping("/validate")
public UserDto validateToken(@RequestHeader("Authorization") String token) {
// Handle both "Bearer <token>" and "<token>"
if ([Link]("Bearer ")) {
token = [Link](7);
}

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 20/110
User user = [Link](token);
return [Link](user);
}

Now you can always call with:

makefile

Authorization: Bearer <your_random_token>

This is the standard convention, so stick with it.

✅ Fix 2 (Product Service controller stays the same)


Your Product Service controller already forwards the header:

java

UserDto userDto = [Link](token);

And in AuthenticationCommons:

java

[Link]("Authorization", token);

So if Postman sends Bearer <token>, the Product Service will forward exactly that to User Service → and
User Service will handle stripping it.

🔑 Postman Test Flow


1. Sign up a user:

bash

POST [Link]

→ You get a token stored in DB.


2. Login:

bash

POST [Link]

→ Returns token (same as stored in DB).

3. Call Product API:

bash

GET [Link]

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 21/110
Authorization: Bearer <token_from_login>

4. User Service /users/validate is called internally by Product Service → if token is valid, returns UserDto.

⚡ That should solve your 401 Unauthorized problem.


👉 Question for you:
Do you want to keep this opaque random token system, or later switch to JWT tokens so Product
Service can validate without calling User Service every time?

hey please take a look at service class too. then come to conclusion

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

import [Link];
import [Link];
import [Link];

@Service
public class UserServiceImpl implements UserService {

private final UserRepository userRepository;


private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final TokenRepository tokenRepository;
private final GlobalExceptionHandler globalExceptionHandler;

@Autowired
private UserServiceImpl(UserRepository userRepository,
BCryptPasswordEncoder bCryptPasswordEncoder,
TokenRepository tokenRepository,
GlobalExceptionHandler globalExceptionHandler) {
[Link] = userRepository;
[Link] = bCryptPasswordEncoder;
[Link] = tokenRepository;
[Link] = globalExceptionHandler;
}
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 22/110
@Override
public Token login(String email, String password) {
Optional<User> optionalUser = [Link](email);
if ([Link]()) { //if email is not present, then throw exception
[Link]();
}

User user = [Link](); //if the fronted(input) password and sign-up saved pw not
matching, then throw exception
if (![Link](password, [Link]())) {

throw new WrongPasswordException("A user entered the wrong password for the above
email.");
}

//if both email and password are matching then create token for that user and save it to db
Token token = createToken(user);
return [Link](token);
}
/* @Override
public Token login(String email, String password) {
Optional<User> userOptional = [Link](email);
if ([Link]()) {
// throw an exception or redirect user to signup
return null;
}

User user = [Link]();


if (![Link](password, [Link]())) {
// throw an exception
return null;
}

Token token = createToken(user);


return [Link](token);
}*/

private Token createToken(User user) {


Token token = new Token();
[Link](user);
[Link]([Link](128)); // Read about UUIDs

//when token got created


Date now = new Date();
[Link](now);

Date currentDate = new Date();


Calendar calendar = [Link]();
[Link](currentDate);
[Link](Calendar.DAY_OF_YEAR, 30);
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 23/110
Date date30DaysFromToday = [Link]();

[Link](date30DaysFromToday);
[Link](false);

return token;
}

@Override
public User signUp(String name, String email, String password) {
// Optional<User> userOptional = [Link](email);
//
// if ([Link]()) {
// // throw new UserAlreadyExistsException("A user with this email already exists.");
// [Link]();
// }

User user = new User();


[Link](name);
[Link](email);
//this is responsible to convert plain text password to Hashed pw
[Link]([Link](password));

//setting date for when the user is created


Date now = new Date();
[Link](now);

[Link](user);
return user;
}

@Override
public User validateToken(String token) {
[Link]("Checking do Api requests are load balanced in user service from
Product Service OR NOT ");
Optional<Token> tokenOptional = tokenRepository
.findByValueAndDeletedAndExpiryAtGreaterThan(token, false, new Date());

if ([Link]()) {
// Throw the custom exception when the token is empty,
// throw new InvalidTokenException("The provided token is invalid or expired."); //this
won't work properly
throw new InvalidTokenException();
}
// Return the user associated with the token if it is valid
return [Link]().getUser();
// return null;
}

//why we are using optional here. Is it not guarantee that we will get always token from -
>[Link] this line -> No
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 24/110
//before logout check do token existed in db or not, it might be a case token is deleted by
somebody to check this status make deleted as "false"
@Override
public User logOut(String tokenValue) {
// Attempt to find the token in the database
Optional<Token> optionalToken = [Link](tokenValue);

// If the token is not found, we return null or handle it as required


if ([Link]()) {
// Optionally, you could throw an exception here to indicate that the token was not found
throw new InvalidTokenException();
}

// If the token is found, mark it as deleted


Token token = [Link]();
//now we are deleting the already existed token by setting the status "True"
[Link](true); // Soft delete the token by setting the deleted flag to true
// Save the token back to the database
[Link](token);

// Return the user associated with the token


return [Link]();
}

Perfect 👌
thanks for sharing the UserServiceImpl.
Now I see the full flow:

1. Login → you generate a random 128-char token, save it in DB with expiry date.
2. ValidateToken → checks if that token exists in DB (deleted = false and expiry > now).
If yes → returns the User.

If no → throws InvalidTokenException.
3. Logout → sets deleted=true in DB for that token.

So your product service endpoint:

java

@GetMapping("/{id}")
public Product getProductById(
@PathVariable("id") Long id,
@RequestHeader("Authorization") String token
) throws InvalidTokenException {
UserDto userDto = [Link](token); // <---
if (userDto == null) {
throw new InvalidTokenException("Invalid token");
}
return [Link](id);
}

is failing with 401 Unauthorized because of one of these issues:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 25/110
🔎 Possible Problems
1. Header format mismatch
Right now your [Link]() expects the raw token value (the 128-char
string).
But your frontend / Postman might be sending it as:

makefile

Authorization: Bearer <token>

In that case, "Bearer " is also included in @RequestHeader("Authorization") String token and
validation fails.
✅ Fix → Strip the prefix:
java

if ([Link]("Bearer ")) {
token = [Link](7);
}

2. Token not saved / expired


If login generated the token but didn’t save properly ([Link](token) not
committed), validation fails.
Or if the DB row got deleted=true or expiryAt < now.
👉 Check DB table token after login. Do you see your token there?

3. Service call mismatch


In ProductService, you use [Link](token).

This must internally call the [Link]() (from User Service).


If authenticationCommons isn’t calling the user service properly, it will always return null.

✅ Suggested Fix
Change your controller like this:

java

@GetMapping("/{id}")
public Product getProductById(
@PathVariable("id") Long id,
@RequestHeader("Authorization") String authHeader
) throws InvalidTokenException {
// Strip Bearer prefix if present
String token = [Link]("Bearer ") ? [Link](7) : authHeader;

UserDto userDto = [Link](token);


if (userDto == null) {

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 26/110
throw new InvalidTokenException("Invalid token");
}

return [Link](id);
}

👉 To debug right now, can you tell me:


When you login and get a token, in Postman, how exactly are you sending it in the request?

Authorization: Bearer <token>

or Authorization: <token>

This will tell me whether the issue is with the "Bearer " prefix or not.

hey why are you more taking about the word "Bearer" i think i have implement in logout
functionality now this fun. is nothing to do with validate right.

Good point 👍 let’s separate the concerns so you don’t get confused:
1. Why I keep talking about Bearer

Because in your ProductController you have this:

java

@GetMapping("/{id}")
public Product getProductById(
@PathVariable("id") Long id,
@RequestHeader("Authorization") String token) throws InvalidTokenException {

UserDto userDto = [Link](token);


...
}

When the frontend or Postman calls this API, normally the HTTP header looks like:

makefile

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR...

👉 That means what you actually receive in your controller is:


arduino

"Bearer eyJhbGciOiJIUzI1NiIsInR..."

But your [Link](token) expects only the raw token string stored in DB (like
eyJhbGc...), not "Bearer eyJh...".
So if you don’t strip "Bearer " before validating, it won’t find the token in DB → you get
InvalidTokenException.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 27/110
That’s why I emphasized "Bearer".

2. Logout Functionality

Yes ✅
you’re correct — logout() has nothing to do with validation in getProductById.
Logout is only about marking a token as deleted in DB:

java

public User logOut(String tokenValue) {


Optional<Token> optionalToken = [Link](tokenValue);
...
}

This also requires raw token value, not "Bearer something".

🔑 Conclusion
Both validateToken() and logOut() work only if they get the raw token (eyJhb...).
But in real API calls, Authorization header includes "Bearer " prefix.
That’s why you need to strip it before calling your service methods.

✅ Fix in controller:
java

@GetMapping("/{id}")
public Product getProductById(@PathVariable("id") Long id,
@RequestHeader("Authorization") String token)
throws InvalidTokenException {
// Remove Bearer prefix if present
if ([Link]("Bearer ")) {
token = [Link](7);
}

UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException("Invalid token");
}

return [Link](id);
}

👉 Do you want me to also show how to centralize this stripping logic in a Spring OncePerRequestFilter,
so you don’t have to write substring(7) in every controller?

you are confusing me more. i have a clean and clear code don't focus on bearer

see the updated code


package [Link];

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 28/110
import [Link];
import [Link].*;
import [Link].*;
import [Link];
import [Link];
import [Link];
import [Link];

@RestController
@RequestMapping("/users")
public class UserController {

private final UserService userService;

@Autowired
public UserController(UserService userService) {
[Link] = userService;
}

@PostMapping("/login")
public LoginResponseDto login(@RequestBody LoginRequestDto loginRequestDto) {
Token token = [Link]([Link](),
[Link]());

LoginResponseDto responseDto = new LoginResponseDto();


[Link](token);
return responseDto;
}

//without wrapping response into ResponseEntity


@PostMapping("/signup")
public SignUpResponseDto signUp(@RequestBody SignUpRequestDto requestDto) {
User user = [Link](
[Link](),
[Link](),
[Link]()
);

SignUpResponseDto responseDto = new SignUpResponseDto();


[Link](user);
[Link]([Link]);

return responseDto;
}
/* @PostMapping("/signup")
public ResponseEntity<SignUpResponseDto> signUp(@RequestBody SignUpRequestDto
signUpRequestDto) {
User user = [Link]([Link](),
[Link](),
[Link]());

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 29/110
SignUpResponseDto responseDto = new SignUpResponseDto();
[Link](user);
// [Link]([Link]());
// [Link]([Link]());
[Link]([Link]); //additional Response status

ResponseEntity<SignUpResponseDto> responseEntity =
new ResponseEntity<>(responseDto, [Link](201));

return responseEntity;
}

*/

/* @PostMapping("/logout")
public ResponseEntity<Void> logout(@RequestBody LogoutRequestDto logoutRequestDto) {
[Link]([Link]());
return new ResponseEntity<>([Link]);
}*/

@PostMapping("/validate")
public UserDto validateToken(@RequestHeader("Authorization") String token) {
User user = [Link](token);
return [Link](user);
}

/* @PostMapping("/logout")
public ResponseEntity<String> logout(@RequestHeader("Authorization") String token) {
// Remove "Bearer" prefix if the token includes it
if ([Link]("Bearer ")) {
token = [Link](7);
}

User user = [Link](token);

if (user == null) {
// If the token was not found or already invalid, return 404 Not Found
return new ResponseEntity<>("Token not found or already logged out.",
HttpStatus.NOT_FOUND);
}

// If the logout was successful, return a confirmation message


return new ResponseEntity<>("User logged out successfully.", [Link]);
}*/
}

check from start to end of conversation then speak take time I already provided the valid
sample token which i'm passing via postamn using keyword "Authorization"

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 30/110
Thanks for the detailed dump — super helpful. I read everything end-to-end. You’re not using JWT;
you’re using an opaque random token stored in DB and validating it via /users/validate. That’s fine.
Given your code and the fact you call the Product API through the API Gateway (7171), there are only a
few places a 401 can come from:

1. Gateway security filter (if Spring Security is on the gateway classpath).


2. Product Service security filter (default Spring Security blocks everything unless you override).

3. User Service /users/validate returning 401 (e.g., token not found/expired) → your
[Link](...) will surface that back, often as a 401 or (if uncaught) a 500.

Since you’re passing the raw token in Authorization (no “Bearer ”), let’s leave that exactly as you want
and fix the real blockers.

What to change (minimal, precise)


A) Product Service: allow your controller to run (avoid default 401)

Add a simple security config so Spring doesn’t block the request before it reaches your controller:

java

// Product Service
@Configuration
@EnableWebSecurity
public class ProductSecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> [Link]())
.cors(cors -> [Link]())
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll() // you do auth manually via AuthenticationCommons
);
return [Link]();
}
}

If you already have Spring Security on the classpath and don’t provide a chain, Spring will 401
everything by default. This change is the #1 fix so your /products/{id} can actually execute
and call the User Service validator.

B) API Gateway: ensure it’s not blocking (if security is present)

If your gateway project has Spring Security in dependencies, add a permissive WebFlux security chain:

java

// API Gateway
@EnableWebFluxSecurity
public class GatewaySecurityConfig {
@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.csrf([Link]::disable)
.authorizeExchange(ex -> [Link]().permitAll())

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 31/110
.build();
}
}

If the gateway doesn’t include Spring Security at all, you can skip this.

C) Make sure the service ID is correct

Your AuthenticationCommons calls:

java

"[Link]

This must exactly match the [Link] of the User Service (Eureka normalizes to
uppercase; that’s fine). In User Service [Link] (or YAML), ensure:

ini

[Link]=USER-SERVICE-TOKEN-AND-JWT

If the name doesn’t match, the @LoadBalanced RestTemplate can’t resolve it (you’ll get 404/Name
resolution errors rather than 401). From your Eureka UI (8761) verify the APP column shows USER-
SERVICE-TOKEN-AND-JWT.

D) User Service: keep /users/validate as you wrote it

Your updated controller:

java

@PostMapping("/validate")
public UserDto validateToken(@RequestHeader("Authorization") String token) {
User user = [Link](token); // expects raw token string
return [Link](user);
}

This is fine because you’re sending the raw token in Postman and forwarding the header as-is from
Product Service. No “Bearer” discussion needed.
Just make sure your exception mapping returns 401 when invalid:

java

// User Service - example


@ResponseStatus([Link])
@ExceptionHandler([Link])
public ErrorDto handleInvalid(InvalidTokenException ex) {
return new ErrorDto("UNAUTHORIZED", "Invalid or expired token");
}

Without this, [Link](...) might bubble a 500 instead of a clean 401.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 32/110
E) Product Service: make your validator more robust to upstream 401

Right now, if /users/validate sends a 401, [Link](...) throws.


Add a tiny guard so your controller gets null and throws your InvalidTokenException cleanly (or rethrow
as you like):

java

@Component
public class AuthenticationCommons {
private final RestTemplate restTemplate;

public AuthenticationCommons(RestTemplate restTemplate) {


[Link] = restTemplate;
}

public UserDto validateToken(String token) {


if (token == null || [Link]()) return null;

HttpHeaders headers = new HttpHeaders();


[Link]("Authorization", token);
HttpEntity<String> entity = new HttpEntity<>(headers);

try {
ResponseEntity<UserDto> response = [Link](
"[Link]
[Link],
entity,
[Link]
);
return [Link]();
} catch ([Link] e) {
return null; // invalid token -> let controller throw InvalidTokenException
}
}
}

Quick test path (exactly matching your style)


1. Login to get a token (stored in DB):

perl

POST [Link]
Body: { "email": "...", "password": "..." }

2. Call product through gateway with that raw token:

pgsql

GET [Link]
Header: Authorization:
TPJvVgm7wsjHlGvsoJcaGcScfv1hu7tmIVeCVF3eqHEz50IlDiyxI6MfdTYrPo8RpsY1WDxudzDvVZG1SMcFHLxkkquFm8FV
Yl4bBy5HSw76eBwLgd7XfYXbT9Z34jcB

If the token exists, is not deleted, and not expired, Product Service will return the product. If not, you’ll
get your InvalidTokenException (which you can map to 401).

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 33/110
Two small gotchas I noticed (not 401, but worth fixing)
In ProductController#getAllProducts() you call [Link](), but
eurekaClient isn’t injected anywhere — that can cause NPEs. Either autowire it or remove that
block.
Your UserServiceImpl constructor is private. Spring can reflectively use it, but it’s unusual; consider
making it public or package-private to avoid surprises.

Bottom line

Your 401 isn’t about “Bearer” here — it’s almost certainly the default Spring Security filter in
either Product Service or Gateway blocking requests before your controller runs.
Add the permitAll security chain to Product Service (and Gateway if needed).

Keep your opaque-token flow exactly as you designed.

Do that, and GET /products/6 via 7171 with your raw Authorization header will work as intended.

{
"timestamp": "2025-08-17T[Link].358+00:00",
"path": "/products/6",
"status": 500,
"error": "Internal Server Error",
"requestId": "10c3f87e-71",
"message": "Connection refused: getsockopt: localhost/[Link]:8092",
"trace": "[Link]$AnnotatedConnectException: Connection refused:
getsockopt: localhost/[Link]:8092\r\n\tSuppressed: The stacktrace has been enhanced by
Reactor, refer to additional information below: \r\nError has been observed at the following
site(s):\r\n\t*__checkpoint ⇢
[Link]
[DefaultWebFilterChain]\r\n\t*__checkpoint ⇢ HTTP GET \"/products/6\"
[ExceptionHandlingWebHandler]\r\nOriginal Stack Trace:\r\nCaused by:
[Link]: Connection refused: getsockopt\r\n\tat
[Link]/[Link](Native Method)\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]([Link])\r\n\
tat
[Link]$[Link](AbstractNioChannel.
java:339)\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\t
at [Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link])\
r\n\tat [Link]$[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 34/110
[Link]/[Link]([Link])\r\n"
}

Perfect 👌 thanks for sharing the error JSON.


Now this is not a token / JWT / Authorization issue at all.
The error clearly says:

nginx

Connection refused: getsockopt: localhost/[Link]:8092

That means your API Gateway (or some client) is trying to forward the request to the Product Service
on port 8092, but nothing is running there.

Why this happens

You sent request to Gateway → Gateway tries to forward to [Link]


Product service is either not started or is running on a different port than 8092.
So Gateway cannot connect → 500 Internal Server Error with Connection refused.

✅ Steps to fix
1. Check your Product service port
In your [Link] or [Link] of product service:

properties

[Link]=8092

Is it 8092? Or some other port (8081, 9000, etc.)?


2. Check if product service is running
Open browser or Postman:

bash

[Link]

If you get JSON (without gateway), then Product Service is fine.

If you still get “Connection refused”, the service isn’t even up.
3. Check Gateway route config
In your [Link] (gateway project), there should be a route like:

yaml

spring:
cloud:
gateway:
routes:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 35/110
- id: product-service
uri: [Link]
predicates:
- Path=/products/**

If product service is not 8092, update uri accordingly.

👉 So your token validation and controller code is fine, the real issue is just that Product Service is
not reachable on 8092.
Would you like me to help you verify whether your product service is running on 8092 or if we need to
update the gateway config?

{
"timestamp": "2025-08-17T[Link].387+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": "[Link]: No instances available for [Link]\r\n\tat
[Link](Bl
[Link])\r\n\tat
[Link](LoadBalance
[Link])\r\n\tat
[Link]$InterceptingRequestExecution.
execute([Link])\r\n\tat
[Link](InterceptingCli
[Link])\r\n\tat
[Link](AbstractB
[Link])\r\n\tat
[Link](AbstractClientHttpRequest.j
ava:66)\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link](FakeStoreProductS
[Link])\r\n\tat
[Link]([Link])\r\
n\tat [Link]/[Link].invoke0(Native Method)\r\n\tat
[Link]/[Link]([Link]
a:77)\r\n\tat
[Link]/[Link](DelegatingMethodAccesso
[Link])\r\n\tat [Link]/[Link]([Link])\r\n\tat
[Link](InvocableHandl
[Link])\r\n\tat
[Link](Invoca
[Link])\r\n\tat
[Link]
keAndHandle([Link])\r\n\tat
[Link]
okeHandlerMethod([Link])\r\n\tat

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 36/110
[Link]
ndleInternal([Link])\r\n\tat
[Link](Abstract
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])\r\n\t
at
[Link]([Link]
14)\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link]:
108)\r\n\tat
[Link]$doFilterInternal$3(FilterChainProxy
.java:231)\r\n\tat
[Link]$FilterObservation$SimpleF
[Link]$wrap$1([Link])\r\n\tat
[Link]$AroundFilterObservation$
[Link]$wrap$1([Link])\r\n\
tat
[Link]$wrapSecured$0(O
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](AuthorizationFilt
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](ExceptionTranslati
[Link])\r\n\tat
[Link](ExceptionTranslati
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 37/110
[Link])\r\n\tat
[Link](Anon
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]
([Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](RequestCac
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]([Link]:
107)\r\n\tat
[Link]([Link]:
93)\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](HeaderWriterFilte
[Link])\r\n\tat
[Link](HeaderWriterFilte
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](SecurityContext
[Link])\r\n\tat
[Link](SecurityContext
[Link])\r\n\tat
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 38/110
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]
FilterInternal([Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](DisableEncod
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$AroundFilterObservation$
[Link]$wrap$0([Link])\r\n\
tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]([Link])\r
\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link]:
113)\r\n\tat
[Link]$createCacheFil
ter$3([Link])\r\n\tat
[Link]$[Link]([Link]:
113)\r\n\tat
[Link]([Link])\r\n\tat
[Link]
on$[Link]([Link])\r\n\tat
[Link]([Link]
a:352)\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link]:
100)\r\n\tat
[Link]([Link])\r\
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 39/110
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link](ServerHttpObserva
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link](CharacterEncodingFilte
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link])\r\n\
tat
[Link]$[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r
\n\tat
[Link]$[Link]([Link])\r
\n\tat
[Link]$[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n",
"message": "No instances available for [Link]",
"path": "/products/6"
}

Perfect, this log tells us the real problem 🚨


Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 40/110
yaml

[Link]: No instances available for [Link]

Spring Cloud LoadBalancer is trying to resolve [Link] as if it were a service ID in


Eureka/Discovery, but [Link] is just an external public API — not a registered service.

That’s why you see No instances available.

✅ How to Fix
In your FakeStoreProductService, you probably wrote something like:

java

[Link]("[Link] + id, [Link]);

But because you annotated your RestTemplate bean with @LoadBalanced, Spring thinks [Link] is
a service name to look up in discovery.

🔧 Solution Options
Option 1: Use a non-loadbalanced RestTemplate for external APIs

java

@Configuration
public class AppConfig {

@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate() {
return new RestTemplate(); // for internal microservices via discovery
}

@Bean
public RestTemplate restTemplate() {
return new RestTemplate(); // plain RestTemplate for external APIs
}
}

Then in your FakeStoreProductService:

java

@Service
public class FakeStoreProductService {

private final RestTemplate restTemplate;

@Autowired
public FakeStoreProductService(RestTemplate restTemplate) {
[Link] = restTemplate; // plain one, no @LoadBalanced
}

public Product getSingleApiProduct(Long id) {


String url = "[Link] + id;
return [Link](url, [Link]);

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 41/110
}
}

Option 2: If you want only one RestTemplate


Don’t mark it with @LoadBalanced if you never use service discovery.
But if you’re mixing microservices + external APIs, Option 1 is better.

👉 So your isn’t about JWT or Authorization anymore — it’s purely because


500 Internal Server Error
[Link] is being routed through the wrong RestTemplate.

Do you want me to refactor your FakeStoreProductService code so it cleanly separates internal service
calls (load balanced) vs external APIs (direct HTTP)?

{
"timestamp": "2025-08-17T[Link].484+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": "[Link]: I/O error on POST
request for \"[Link] USER-SERVICE-TOKEN-
AND-JWT\r\n\tat
[Link]([Link]
va:915)\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link](AuthenticationCommo
[Link])\r\n\tat
[Link]([Link])\r\
n\tat [Link]/[Link].invoke0(Native Method)\r\n\tat
[Link]/[Link]([Link]
a:77)\r\n\tat
[Link]/[Link](DelegatingMethodAccesso
[Link])\r\n\tat [Link]/[Link]([Link])\r\n\tat
[Link](InvocableHandl
[Link])\r\n\tat
[Link](Invoca
[Link])\r\n\tat
[Link]
keAndHandle([Link])\r\n\tat
[Link]
okeHandlerMethod([Link])\r\n\tat
[Link]
ndleInternal([Link])\r\n\tat
[Link](Abstract
[Link])\r\n\tat
[Link]([Link])\r\
n\tat

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 42/110
[Link]([Link])\r\n\t
at
[Link]([Link]
14)\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link]:
108)\r\n\tat
[Link]$doFilterInternal$3(FilterChainProxy
.java:231)\r\n\tat
[Link]$FilterObservation$SimpleF
[Link]$wrap$1([Link])\r\n\tat
[Link]$AroundFilterObservation$
[Link]$wrap$1([Link])\r\n\
tat
[Link]$wrapSecured$0(O
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](AuthorizationFilt
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](ExceptionTranslati
[Link])\r\n\tat
[Link](ExceptionTranslati
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](Anon
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 43/110
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]
([Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](RequestCac
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]([Link]:
107)\r\n\tat
[Link]([Link]:
93)\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](HeaderWriterFilte
[Link])\r\n\tat
[Link](HeaderWriterFilte
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](SecurityContext
[Link])\r\n\tat
[Link](SecurityContext
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 44/110
[Link]
FilterInternal([Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](DisableEncod
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$AroundFilterObservation$
[Link]$wrap$0([Link])\r\n\
tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]([Link])\r
\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link]:
113)\r\n\tat
[Link]$createCacheFil
ter$3([Link])\r\n\tat
[Link]$[Link]([Link]:
113)\r\n\tat
[Link]([Link])\r\n\tat
[Link]
on$[Link]([Link])\r\n\tat
[Link]([Link]
a:352)\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link]:
100)\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\
n\tat
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 45/110
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link](ServerHttpObserva
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link](CharacterEncodingFilte
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link])\r\n\
tat
[Link]$[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r
\n\tat
[Link]$[Link]([Link])\r
\n\tat
[Link]$[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\nCaused by: [Link]:
USER-SERVICE-TOKEN-AND-JWT\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]/[Link].<init>([Link])\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n\tat
[Link]/[Link](HttpURLConnectio
[Link])\r\n\tat
[Link]/[Link].plainConnect0([Link]
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 46/110
a:1257)\r\n\tat
[Link]/[Link]([Link]
:1143)\r\n\tat
[Link]/[Link]([Link]
2)\r\n\tat
[Link](SimpleClientHttpReq
[Link])\r\n\tat
[Link](AbstractS
[Link])\r\n\tat
[Link](AbstractClientHttpRequest.j
ava:66)\r\n\tat
[Link]([Link])\r\n\t... 123
more\r\n",
"message": "I/O error on POST request for \"[Link]
JWT/users/validate\": USER-SERVICE-TOKEN-AND-JWT",
"path": "/products/6"
}

Thanks for pasting the stacktrace 🙏 — this clears up the issue.


The root cause is here:

pgsql

Caused by: [Link]: USER-SERVICE-TOKEN-AND-JWT

That means your Product Service is trying to call

pgsql

[Link]

but Spring (or your JVM) cannot resolve the hostname USER-SERVICE-TOKEN-AND-JWT.

Why this is happening

1. Wrong base URL in your AuthenticationCommons.


You are directly calling [Link] with RestTemplate.
This only works if you have a service registry (Eureka/Consul) and are using @LoadBalanced
RestTemplate.

2. If you are not using Eureka, that name (USER-SERVICE-TOKEN-AND-JWT) must be replaced with a real
host:port like:

bash

[Link]

or

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 47/110
bash

[Link]

3. If you are using Eureka/Service Discovery, then you must configure:

java

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}

so that USER-SERVICE-TOKEN-AND-JWT will be resolved by the discovery client.

✅ Fix paths depending on setup:


Without Eureka → update your AuthenticationCommons URL:

java

String url = "[Link]

With Eureka + LoadBalanced → keep [Link] but make


sure:
Both Product Service and User Service are registered with Eureka
You inject a @LoadBalanced RestTemplate bean

👉 Question for you: are you running with Eureka/Service Discovery or just hardcoding URLs
(localhost:port)?
That will decide the correct fix.

{
"timestamp": "2025-08-17T[Link].970+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": "[Link]: No instances available for [Link]\r\n\tat
[Link](Bl
[Link])\r\n\tat
[Link](LoadBalance
[Link])\r\n\tat
[Link]$InterceptingRequestExecution.
execute([Link])\r\n\tat
[Link](InterceptingCli
[Link])\r\n\tat
[Link](AbstractB
[Link])\r\n\tat

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 48/110
[Link](AbstractClientHttpRequest.j
ava:66)\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link](FakeStoreProductS
[Link])\r\n\tat
[Link]([Link])\r\
n\tat [Link]/[Link].invoke0(Native Method)\r\n\tat
[Link]/[Link]([Link]
a:77)\r\n\tat
[Link]/[Link](DelegatingMethodAccesso
[Link])\r\n\tat [Link]/[Link]([Link])\r\n\tat
[Link](InvocableHandl
[Link])\r\n\tat
[Link](Invoca
[Link])\r\n\tat
[Link]
keAndHandle([Link])\r\n\tat
[Link]
okeHandlerMethod([Link])\r\n\tat
[Link]
ndleInternal([Link])\r\n\tat
[Link](Abstract
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])\r\n\t
at
[Link]([Link]
14)\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link]:
108)\r\n\tat
[Link]$doFilterInternal$3(FilterChainProxy
.java:231)\r\n\tat
[Link]$FilterObservation$SimpleF
[Link]$wrap$1([Link])\r\n\tat
[Link]$AroundFilterObservation$
[Link]$wrap$1([Link])\r\n\
tat
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 49/110
[Link]$wrapSecured$0(O
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](AuthorizationFilt
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](ExceptionTranslati
[Link])\r\n\tat
[Link](ExceptionTranslati
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](Anon
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]
([Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](RequestCac
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]([Link]:
107)\r\n\tat
[Link]([Link]:
93)\r\n\tat
[Link]$[Link]
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 50/110
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](HeaderWriterFilte
[Link])\r\n\tat
[Link](HeaderWriterFilte
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](SecurityContext
[Link])\r\n\tat
[Link](SecurityContext
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]
FilterInternal([Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](DisableEncod
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$AroundFilterObservation$
[Link]$wrap$0([Link])\r\n\
tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]([Link])\r
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 51/110
\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link]:
113)\r\n\tat
[Link]$createCacheFil
ter$3([Link])\r\n\tat
[Link]$[Link]([Link]:
113)\r\n\tat
[Link]([Link])\r\n\tat
[Link]
on$[Link]([Link])\r\n\tat
[Link]([Link]
a:352)\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link]:
100)\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link](ServerHttpObserva
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link](CharacterEncodingFilte
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 52/110
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link])\r\n\
tat
[Link]$[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r
\n\tat
[Link]$[Link]([Link])\r
\n\tat
[Link]$[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n",
"message": "No instances available for [Link]",
"path": "/products/7"
}

Perfect, now I see the real problem 👀.


The error:

arduino

No instances available for [Link]

tells us that your RestTemplate is trying to do service discovery lookup on [Link] as if it was a
Eureka service name, not a real external domain.

Why?

Because you’ve annotated your RestTemplate with @LoadBalanced.


When a @LoadBalanced RestTemplate is used, Spring Cloud assumes everything you pass (like
[Link]) is a service id registered in Eureka/Consul. Since [Link] isn’t registered
there → it fails.

✅ Fix
For external APIs (like [Link] never use the @LoadBalanced RestTemplate.
You need two beans:

java

@Configuration
public class RestTemplateConfig {

// For internal service-to-service calls (with Eureka)


@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate() {
return new RestTemplate();
}

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 53/110
// For external APIs (like [Link])
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

Then in your FakeStoreProductService, inject the plain one:

java

@Service
public class FakeStoreProductService {

private final RestTemplate restTemplate;

@Autowired
public FakeStoreProductService(@Qualifier("restTemplate") RestTemplate restTemplate) {
[Link] = restTemplate;
}

public Product getSingleApiProduct(Long id) {


String url = "[Link] + id;
return [Link](url, [Link]);
}
}

👉 So quick recap:
Keep @LoadBalanced RestTemplate only for microservice-to-microservice calls (like Product ↔ User
via Eureka).
Use a normal RestTemplate for external APIs ([Link]).

Do you want me to show you how to cleanly wire both into your ProductService so you can use Eureka
for User Service and call FakeStore API without conflict?

hey for this api : [Link]


it is showing error u can check in product controller i have not passed any requerst headers
then also i'm getting this error

{
"timestamp": "2025-08-17T[Link].296+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": "[Link]: Cannot invoke
\"[Link]()\" because
\"[Link]\" is null\r\n\tat
[Link]([Link])\r\n
\tat [Link](Unknown Source)\r\n\tat
[Link]/[Link](DelegatingMethodAccesso
[Link])\r\n\tat [Link]/[Link]([Link])\r\n\tat
[Link](InvocableHandl

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 54/110
[Link])\r\n\tat
[Link](Invoca
[Link])\r\n\tat
[Link]
keAndHandle([Link])\r\n\tat
[Link]
okeHandlerMethod([Link])\r\n\tat
[Link]
ndleInternal([Link])\r\n\tat
[Link](Abstract
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])\r\n\t
at
[Link]([Link]
14)\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link]:
108)\r\n\tat
[Link]$doFilterInternal$3(FilterChainProxy
.java:231)\r\n\tat
[Link]$FilterObservation$SimpleF
[Link]$wrap$1([Link])\r\n\tat
[Link]$AroundFilterObservation$
[Link]$wrap$1([Link])\r\n\
tat
[Link]$wrapSecured$0(O
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](AuthorizationFilt
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](ExceptionTranslati
[Link])\r\n\tat
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 55/110
[Link](ExceptionTranslati
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](Anon
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]
([Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](RequestCac
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]([Link]:
107)\r\n\tat
[Link]([Link]:
93)\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](HeaderWriterFilte
[Link])\r\n\tat
[Link](HeaderWriterFilte
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 56/110
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](SecurityContext
[Link])\r\n\tat
[Link](SecurityContext
[Link])\r\n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]
FilterInternal([Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link](DisableEncod
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]$[Link]
er([Link])\r\n\tat
[Link]$AroundFilterObservation$
[Link]$wrap$0([Link])\r\n\
tat
[Link]$[Link](
[Link])\r\n\tat
[Link]$[Link](
[Link])\r\n\tat
[Link]([Link])\r
\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link]:
113)\r\n\tat
[Link]$createCacheFil
ter$3([Link])\r\n\tat
[Link]$[Link]([Link]:
113)\r\n\tat
[Link]([Link])\r\n\tat
[Link]
on$[Link]([Link])\r\n\tat
[Link]([Link]
a:352)\r\n\tat
[Link]([Link])\r\
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 57/110
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link]:
100)\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link](ServerHttpObserva
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link](CharacterEncodingFilte
[Link])\r\n\tat
[Link]([Link])\r\
n\tat
[Link]([Link])
\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]$[Link]([Link])\r\n\
tat
[Link]$[Link]([Link])\r\n\tat
[Link]([Link])\r\n\tat
[Link]([Link])\r
\n\tat
[Link]$[Link]([Link])\r
\n\tat
[Link]$[Link]([Link])\r\n\tat
[Link]/[Link]([Link])\r\n",
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 58/110
"message": "Cannot invoke
\"[Link]()\" because
\"[Link]\" is null",
"path": "/products/allProducts"
}

Thanks for pasting the stacktrace 🙌 — this makes it clear.


The root cause is here:

csharp

Cannot invoke "[Link]()"


because "[Link]" is null

That means in your [Link](), you are directly calling something like:

java

[Link]()...

But eurekaClient is not injected (Spring never created it → it’s null).

🔎 Why is this happening?


In newer Spring Cloud versions, you usually don’t need to inject EurekaClient manually.
Instead, you rely on RestTemplate (with @LoadBalanced) or FeignClient to talk to other services by
their service-id.
If you really want to use EurekaClient, you must ensure that:
1. Your service has @EnableEurekaClient (or @EnableDiscoveryClient).
2. spring-cloud-starter-netflix-eureka-client is on the classpath.

3. The bean is injected properly:

java

@Autowired
private EurekaClient eurekaClient;

Right now, either you didn’t autowire it or your Spring Boot version doesn’t expose the EurekaClient
bean the same way.

✅ Fix Options
Option 1 (recommended): Don’t use EurekaClient directly

In your controller, instead of:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 59/110
java

[Link]()...

do something like:

java

@GetMapping("/allProducts")
public List<Product> getAllProducts() {
return [Link]();
}

And in ProductService, call the other service with a @LoadBalanced RestTemplate:

java

@Service
public class ProductService {

@Autowired
@Qualifier("loadBalancedRestTemplate")
private RestTemplate restTemplate;

public List<Product> getAllProducts() {


return [Link](
[Link]("[Link] Product[].class)
);
}
}

Here, USER-SERVICE is the Eureka service-id.

Option 2 (if you really want to use EurekaClient)

Make sure it’s injected:

java

@RestController
@RequestMapping("/products")
public class ProductController {

private final EurekaClient eurekaClient;

@Autowired
public ProductController(EurekaClient eurekaClient) {
[Link] = eurekaClient;
}

@GetMapping("/allProducts")
public List<Product> getAllProducts() {
Application application = [Link]("USER-SERVICE");
InstanceInfo instanceInfo = [Link]().get(0);
String url = "[Link] + [Link]() + ":" + [Link]() +
"/users/products";
return [Link](new RestTemplate().getForObject(url, Product[].class));
}
}

⚠️ This is old-school and tightly coupled. Prefer Option 1 with RestTemplate/FeignClient.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 60/110
👉 Question for you:
Do you want me to rewrite your getAllProducts() using RestTemplate (Eureka service-id) or do you
want to stick with the manual EurekaClient way?

check once this is my controller

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].*;

import [Link];

@RestController
@RequestMapping("/products")
public class ProductController {
private final AuthenticationCommons authenticationCommons;
private final ProductService productService;
private final GlobalExceptionHandler globalExceptionHandler;

@Value("${[Link]}")
private String serverPort;

@Qualifier("eurekaRegistration")
private Registration registration;

private EurekaClient eurekaClient;

@Autowired
public ProductController(@Qualifier("HeyProductService") ProductService productService,
AuthenticationCommons authenticationCommons,
GlobalExceptionHandler globalExceptionHandler,
@Qualifier("eurekaRegistration") Registration registration) {

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 61/110
[Link] = productService;
[Link] = authenticationCommons;
[Link] = globalExceptionHandler;
[Link] = registration;
}

//[Link]
@GetMapping("/allProducts")
public List<Product> getAllProducts() {
InstanceInfo instanceInfo = [Link]().getInfo();
String instanceId = (instanceInfo != null) ? [Link]() : "Unknown
Instance";

[Link]("Port Name/Instance Name registered in Eureka Server is: " +


instanceId);
[Link]("Request arrived in product service in port no. " + serverPort);
return [Link]();
}

//[Link]
@GetMapping("/{id}")
public Product getProductById(@PathVariable("id") Long id, @RequestHeader("Authorization")
String token) throws InvalidTokenException {
UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException("Invalid token");
}

Product product = [Link](id);


[Link]("Check do Api requests are load balanced in product service");
return product;
}

//[Link]
@PostMapping("/all")
public Product postAllProducts(@RequestBody CreateProductRequestDto
createProductRequestDto) {
return [Link](
[Link](),
[Link](),
[Link](),
[Link](),
[Link]()
);
}

@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody
CreateProductRequestDto createProductRequestDto) {
return [Link](id, createProductRequestDto);
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 62/110
}

/* @GetMapping("/products1")
public List<ProductIdAndTitleProjection> getProductsByCategoryTitle(@RequestParam("title")
String title) {
return [Link](title);
}*/

//[Link]
@GetMapping("/categories/{title}")
public List<ProductIdAndTitleProjection>
getProductTitlesByCategoryTitle(@PathVariable("title") String categoryTitle) {
return [Link](categoryTitle);
}

//[Link]
@GetMapping("/categories/{title}/{id}")
public Product getFindNameOfProductByCategoryTitleAndProdId(@PathVariable("title")
String title, @PathVariable("id") Long id) {
return [Link](title, id);
}

@GetMapping("/allPrice")
public List<ProductPriceProjection> getPriceFromProduct() {
return [Link]();
}

/*
public ResponseEntity<Product> updateProduct(@PathVariable Long id, @RequestBody
Product updatedProduct) {
Product updatedProductResult = [Link](id, updatedProduct);
return new ResponseEntity<>(updatedProductResult, [Link]);
}

*/

Perfect, thanks for sharing the full controller 🙌.


Now it’s 100% clear why you’re hitting the NullPointerException on
[Link]():

🔎 The issue
In your controller, you declared:

java

private EurekaClient eurekaClient;

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 63/110
…but you never injected it (@Autowired).
So Spring never sets it → it stays null.
Then, when you call:

java

InstanceInfo instanceInfo = [Link]().getInfo();

💥 NullPointerException.
✅ Fix #1 (Inject the EurekaClient properly)
Update your constructor to also inject the EurekaClient:

java

@Autowired
public ProductController(@Qualifier("HeyProductService") ProductService productService,
AuthenticationCommons authenticationCommons,
GlobalExceptionHandler globalExceptionHandler,
@Qualifier("eurekaRegistration") Registration registration,
EurekaClient eurekaClient) { // <--- added here
[Link] = productService;
[Link] = authenticationCommons;
[Link] = globalExceptionHandler;
[Link] = registration;
[Link] = eurekaClient; // <--- assign here
}

Now eurekaClient won’t be null.

✅ Fix #2 (Cleaner: Don’t use getApplicationInfoManager() at all)

If your goal in /allProducts is just to log instance/port info, you don’t need EurekaClient.
You already have it via Spring Cloud’s Registration:

java

@GetMapping("/allProducts")
public List<Product> getAllProducts() {
String instanceId = [Link](); // works with eurekaRegistration
[Link]("Port/Instance registered in Eureka Server: " + instanceId);
[Link]("Request arrived in product service in port no. " + serverPort);
return [Link]();
}

This way you can delete the EurekaClient field completely.


Much simpler, and avoids version-compatibility issues (Spring Cloud 2023+ discourages direct
EurekaClient usage).

👉 Question for you:


Do you want me to fix your controller by injecting EurekaClient (so your current code works),
or do you want me to rewrite it using only Registration (cleaner, no NullPointerException risk)?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 64/110
hey see i fix the error but wanted to know about security spring library.

in product service i have not used spring security library but in user service i used and
connection between both the services are via. authentication commons okay .

But only one api need to be authenticated from user service if token is correct then only we will
get response right. and rest of api's in product controller won't have headers and stuff. unless
and untill i have not used spring "SecurityConfig" that you gave saying i need to permitall
request then only i will be able to get responds right.

My question is i think why i need this config file in product service bcoz i have not used library in
pom file are you getting it. By the if this happens then i think conclusion will be if one
microservice is using spring security and another is just talking via anything to that
microservices whichever is using security library then other who don't use library they must
have "SecurityConfig" bcoz they are anyhow talking to another project which have security
library is this correct.

go in depth and let me know

Great question — and you’re thinking about it in exactly the right way. Here’s the clean truth, no fluff:

Do you need Spring Security in Product-Service?


No, not unless you actually include Spring Security on its classpath. Spring Security is per application. If
User-Service uses Spring Security, that has zero automatic effect on Product-Service. Each
microservice runs its own filter chain (or none).

If Product-Service has no spring-boot-starter-security dependency → no SecurityConfig


needed, and nothing is blocked by default.
If you add Spring Security later → you must provide a SecurityFilterChain (or everything gets
locked down by default).

What does matter across services is HTTP contract, not Spring Security itself:

If a downstream service (User-Service) requires authentication for the endpoint you call, you
must send whatever credentials that service expects (header, basic auth, OAuth2 client creds,
etc.).
That’s outbound client config, not a server-side SecurityConfig for Product-Service’s own
endpoints.

Your current pattern (works without Spring Security in Product-


Service)
You’re doing:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 65/110
1. Client → API Gateway → Product-Service /products/{id}
2. Product-Service extracts Authorization header
3. Product-Service calls User-Service /users/validate to check the token
4. If valid, return the product

That’s perfectly fine without Spring Security in Product-Service because you’re doing the check in code
(controller/service/interceptor). Only the User-Service needs Spring Security (if you choose), and you
typically permitAll() on /users/validate so other services can call it.

Bottom line: another project using Spring Security does not force you to add Spring Security
in this one.

If later you do add Spring Security to Product-Service


Then configure it so only the protected endpoint is secured:

java

@Bean
SecurityFilterChain security(HttpSecurity http) throws Exception {
[Link](csrf -> [Link]());
[Link](auth -> auth
.requestMatchers([Link], "/products/{id}").authenticated()
.anyRequest().permitAll()
);
// You can keep your current token validation call inside a filter
// or simply leave it in the controller as you do now.
return [Link]();
}

This way /products/allProducts etc. are open, but /products/{id} requires your custom check.

(Recommended) Alternative architecture


Many teams move auth to the API Gateway:

Gateway validates the token (locally if JWT, or by calling /users/validate), and injects user info to
headers (e.g., X-User-Id) for downstream services.
Product-Service then doesn’t care about Authorization and can stay free of Spring Security.

This reduces duplicate auth logic and network hops.

Two important fixes from your stack traces


1. “No instances available for [Link]”
You’re using a @LoadBalanced RestTemplate to call an external host. A load-balanced RestTemplate tries
to resolve every host name via Eureka → it fails for real domains.

Fix: define two RestTemplates.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 66/110
java

@Configuration
public class RestTemplates {
@Bean @LoadBalanced
public RestTemplate internalRestTemplate() { return new RestTemplate(); }

@Bean
public RestTemplate externalRestTemplate() { return new RestTemplate(); }
}

Use internalRestTemplate for [Link]


Use externalRestTemplate for [Link]

2. “UnknownHostException: USER-SERVICE-TOKEN-AND-JWT”
Happens when:

User-Service is not registered in Eureka yet, or


The service name doesn’t match [Link] of User-Service, or
You used a non-load-balanced RestTemplate for a Eureka name.

Checklist

In User-Service: [Link]=USER-SERVICE-TOKEN-AND-JWT, and Eureka client enabled.


In Product-Service: call [Link] using the @LoadBalanced
RestTemplate.

Quick rules of thumb


You do not need SecurityConfig in Product-Service unless you add the security dependency.
Security in one service doesn’t bleed into another. Each service is isolated.

Outbound calls to secured services are handled by HTTP client config (headers/credentials), not by
adding Spring Security to the caller.
Prefer JWT to avoid the network hop for validation (or add caching/circuit breaker if you keep the
DB-backed random token design).
If you keep the current design, consider Resilience4j (timeouts/retries/circuit breaker) around the
/users/validate call.

If you want, I can sketch the two-RestTemplate wiring and small changes in your AuthenticationCommons
and FakeStoreProductService so your errors disappear immediately.

No my current code won't work without SecurityConfig file i have that file

package [Link];

import [Link];

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 67/110
import [Link];
import [Link];
import [Link];

@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> {
try {
requests
//.anyRequest().permitAll()
// .requestMatchers("/product/id").authenticated() // Require
authentication for this pattern //("/product/*").authenticated()
.anyRequest().permitAll() // Allow all other requests without
authentication
.and().cors().disable()
.csrf().disable();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
);

return [Link]();
}
}

if i remove this file then i get errors non of api works also u can take a look at pom files too and
let me know

<?xml version="1.0" encoding="UTF-8"?>


<project xmlns="[Link]
xmlns:xsi="[Link]
xsi:schemaLocation="[Link]
[Link]
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>[Link]</groupId>
<artifactId>ProductService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ProductService</name>
<description>Demo project for Spring Boot</description>
<properties>
<[Link]>17</[Link]>
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 68/110
<[Link]>17</[Link]>
<[Link]>17</[Link]>
</properties>

<dependencies>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>[Link]</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>

<dependency>
<groupId>[Link]</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>

<!-- [Link] -->


<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>

<!-- To create table using @Entity Use this depen.-->


<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- <dependency>
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 69/110
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>-->

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>

<!-- [Link]
netflix-eureka-client -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>4.1.4</version>
</dependency>

<!-- &lt;!&ndash; [Link] &ndash;&gt;


<dependency>
<groupId>[Link]</groupId>
<artifactId>flyway-core</artifactId>
<version>10.13.0</version>
</dependency>

&lt;!&ndash; [Link] &ndash;&gt;


<dependency>
<groupId>[Link]</groupId>
<artifactId>flyway-mysql</artifactId>
<version>10.13.0</version>
</dependency>
-->
</dependencies>

<build>
<plugins>
<plugin>
<groupId>[Link]</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>[Link]</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 70/110
</plugin>
</plugins>

</build>

</project>

Perfect, thanks for pasting both your SecurityConfig and [Link] 🙌


Now let’s go step by step and clear the confusion:

🔎 Why your Product Service still needs SecurityConfig

1. Spring Boot auto-configures security if any Spring Security dependency is present.


In your [Link], you have spring-boot-starter-oauth2-authorization-server.
This internally brings in spring-boot-starter-security as a transitive dependency.
That’s why even though you commented out spring-boot-starter-security in your POM, Spring
Security is still on your classpath.
2. Default Spring Security behavior (without config):
If Spring Security is on the classpath, by default:
All endpoints require authentication.
CSRF is enabled.
A default login page appears (for MVC apps).
That’s why when you remove SecurityConfig, none of your APIs work → because they’re all
locked behind default security.
3. What your SecurityConfig does:

It overrides the defaults and tells Spring:

java

.anyRequest().permitAll()
.and().cors().disable()
.csrf().disable();

Which means → “allow all requests, don’t block APIs, no login page, no CSRF required.”

So even though you’re not directly using Spring Security in Product Service, the dependency you
added (OAuth2 Authorization Server) pulled it in, and that forces you to configure security.

🔎 Do all microservices need Spring Security?


No.
If a microservice never needs authentication/authorization, you don’t need spring-boot-starter-
security in its dependencies at all.
Then you also don’t need a SecurityConfig.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 71/110
In your case:
Product Service only validates tokens by calling User Service (via your authenticationCommons).
That means you don’t need Spring Security at all in Product Service.
The only reason you currently need it is because spring-boot-starter-oauth2-authorization-
server is bringing it in.

If you remove that dependency, your Product Service APIs will work fine without
SecurityConfig.

🔎 Conclusion for your setup


✅ If only User Service handles authentication:
Product Service doesn’t need Spring Security dependency.
Just remove:

xml

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>

Then remove SecurityConfig class.


Your APIs will work without security defaults.

✅ If you plan to run OAuth2 Authorization Server inside Product Service (not recommended
usually):

Then you must keep the dependency, and you’ll also need a SecurityConfig.

👉 Quick check for you: Do you really need spring-boot-starter-oauth2-authorization-server inside


Product Service? Or is it just left over from experimenting?

hey i'm using global handler let me know is this a correct way to handle exception at method
level code in project

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

@ControllerAdvice
public class GlobalExceptionHandler {
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 72/110
ErrorHandler errorHandler;

@Autowired
public GlobalExceptionHandler(ErrorHandler errorHandler) {
[Link] = errorHandler;
}

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handlerInvalidTokenException() {
[Link]("Token is null or Invalid");
[Link]("InvalidTokenException");
[Link]([Link](401).value());
return new ResponseEntity<>(errorHandler, [Link](500));
}
}

package [Link];

public class InvalidTokenException extends Exception {

public InvalidTokenException() {
super();
}
}

//check at this level in depth


@GetMapping("/{id}")
public Product getProductById(@PathVariable("id") Long id, @RequestHeader("Authorization")
String token) throws InvalidTokenException {
UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException();
}

Product product = [Link](id);


[Link]("Check do Api requests are load balanced in product service");
return product;
}

Good that you’re thinking about exception handling at method level 👍 Let’s go through your setup in
depth and refine it.

🔎 Analysis of Your Code


1. GlobalExceptionHandler

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 73/110
java

@ControllerAdvice
public class GlobalExceptionHandler {
ErrorHandler errorHandler;

@Autowired
public GlobalExceptionHandler(ErrorHandler errorHandler) {
[Link] = errorHandler;
}

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handlerInvalidTokenException() {
[Link]("Token is null or Invalid");
[Link]("InvalidTokenException");
[Link]([Link](401).value());
return new ResponseEntity<>(errorHandler, [Link](500));
}
}

✅ What’s good
You’re using @ControllerAdvice + @ExceptionHandler, which is the right approach for centralized
exception handling in Spring.
Catching your custom InvalidTokenException specifically.

⚠️ Issues
1. Reusing a single ErrorHandler bean –
You’re injecting ErrorHandler as a Spring bean and reusing it across requests. That’s not thread-safe
(imagine two requests failing at the same time → data can mix up).
👉Instead, you should create a new instance inside the handler method.
2. Wrong status code returned –
You set errorCode = 401 but return ResponseEntity(..., 500). That’s contradictory.
👉You should return [Link] (401).

2. InvalidTokenException

java

public class InvalidTokenException extends Exception {


public InvalidTokenException() {
super();
}
}

✅ Looks fine, but usually custom exceptions extend RuntimeException (unchecked) in Spring because
checked exceptions (like Exception) force you to throws everywhere.

3. Controller Method

java

@GetMapping("/{id}")
public Product getProductById(@PathVariable("id") Long id, @RequestHeader("Authorization")

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 74/110
String token) throws InvalidTokenException {
UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException();
}

Product product = [Link](id);


[Link]("Check do Api requests are load balanced in product service");
return product;
}

✅ Logic is good:
Extract token
Validate

If invalid → throw exception

⚠️ Small improvements:
Instead of directly throwing a blank exception, pass a message → throw new
InvalidTokenException("Invalid token")

✅ Improved Version
ErrorHandler class (assuming it’s a DTO)

java

public class ErrorHandler {


private String message;
private String typeOfException;
private int errorCode;

// getters, setters, constructors


}

GlobalExceptionHandler

java

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handlerInvalidTokenException(InvalidTokenException ex) {
ErrorHandler errorHandler = new ErrorHandler();
[Link]([Link]() != null ? [Link]() : "Token is null or
Invalid");
[Link]("InvalidTokenException");
[Link]([Link]());

return new ResponseEntity<>(errorHandler, [Link]);


}
}

InvalidTokenException

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 75/110
java

public class InvalidTokenException extends RuntimeException {


public InvalidTokenException(String message) {
super(message);
}
}

Controller

java

@GetMapping("/{id}")
public Product getProductById(@PathVariable("id") Long id,
@RequestHeader("Authorization") String token) {
UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException("Invalid or missing token");
}

return [Link](id);
}

🔑 Final Notes
No shared state: Always create fresh ErrorHandler objects.
Correct status codes: Match your error object’s errorCode with ResponseEntity status.
RuntimeException over checked: Keeps controller signatures cleaner.
Scalable: You can add more @ExceptionHandlers for other exceptions (e.g., EntityNotFoundException,
IllegalArgumentException).

👉 Do you want me to also show how you can return a consistent error JSON response for all
exceptions (not just InvalidTokenException) so your API has one standard error format?

you mean
public Product getProductById(@PathVariable("id") Long id, @RequestHeader("Authorization")
String token) throws InvalidTokenException => i'm throwing exception at method level in
Signature right which is called uncheck exception

Ah, small but important distinction here 👇


1. Checked vs Unchecked in Java

Checked Exception → extends Exception

Must be declared in the method signature with throws.


Compiler forces you to handle it (try/catch or throws).

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 76/110
Example: IOException, SQLException.
Unchecked Exception → extends RuntimeException
You don’t need to declare throws in method signature.
Compiler doesn’t force handling.
Example: NullPointerException, IllegalArgumentException.

2. In Your Code Right Now

java

public Product getProductById(@PathVariable("id") Long id,


@RequestHeader("Authorization") String token)
throws InvalidTokenException {
...
if (userDto == null) {
throw new InvalidTokenException();
}
...
}

Your InvalidTokenException currently extends Exception → that makes it a checked exception.


That’s why you were forced to add throws InvalidTokenException in the method signature.

3. If You Change It

java

public class InvalidTokenException extends RuntimeException {


public InvalidTokenException(String message) {
super(message);
}
}

Then you can simply write:

java

public Product getProductById(@PathVariable("id") Long id,


@RequestHeader("Authorization") String token) {
if (userDto == null) {
throw new InvalidTokenException("Invalid or missing token");
}
return [Link](id);
}

👉 Notice: No more throws InvalidTokenException in the signature, because now it’s unchecked.

4. Best Practice in Spring

Almost always, custom exceptions in Spring Boot extend RuntimeException (unchecked).


Reason:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 77/110
Cleaner controller signatures
Spring’s @ExceptionHandler and @ControllerAdvice can still catch them
You don’t clutter code with throws everywhere

✅ So to your question:
throws InvalidTokenException in signature → means it’s a checked exception (currently in
your code).
If you want it to be unchecked, extend RuntimeException instead, and you can drop it from the
method signature.

Do you want me to compare when you should actually use checked vs unchecked exceptions in a
Spring Boot project?

Almost always, **custom exceptions in Spring Boot extend `RuntimeException`** (unchecked).


can you tell me how to use this unchecked exception using global controller annotation

Perfect 👌 let’s walk through it step by step with unchecked exceptions + @ControllerAdvice in Spring
Boot.

1. Define Your Custom Exception (unchecked)

java

package [Link];

public class InvalidTokenException extends RuntimeException {


public InvalidTokenException(String message) {
super(message);
}
}

👉 Notice: now it extends RuntimeException,


so it’s unchecked.
No need to put throws InvalidTokenException in controller methods.

2. Throw Exception in Controller

java

@GetMapping("/{id}")
public Product getProductById(@PathVariable("id") Long id,
@RequestHeader("Authorization") String token) {
UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException("Token is null or invalid");
}

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 78/110
return [Link](id);
}

👉 Here, we simply throw it — no throws in method signature.

3. Global Exception Handler (@ControllerAdvice)

java

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handleInvalidTokenException(InvalidTokenException ex) {
ErrorHandler error = new ErrorHandler();
[Link]([Link]());
[Link]("InvalidTokenException");
[Link]([Link]());

return new ResponseEntity<>(error, [Link]);


}
}

👉 Key points:
@ExceptionHandler([Link]) catches all thrown InvalidTokenException
anywhere in your controllers.

ResponseEntity lets you control status code & body.


No clutter in your controllers.

4. Example Response

If client calls /products/6 with invalid token, response will be:

json

{
"message": "Token is null or invalid",
"typeOfException": "InvalidTokenException",
"errorCode": 401
}

With HTTP status 401 Unauthorized.

✅ That’s the clean Spring way:


Throw RuntimeException (unchecked) when something is wrong
Let @ControllerAdvice + @ExceptionHandler translate it into a proper HTTP response
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 79/110
Do you want me to also show how to make a generic handler that catches all runtime exceptions
(instead of writing one per exception class)?

`@ControllerAdvice public class GlobalExceptionHandler {


@ExceptionHandler([Link]) public ResponseEntity<ErrorHandler>
handleInvalidTokenException(InvalidTokenException ex) { ErrorHandler error = new ErrorHandler();
[Link]([Link]()); [Link]("InvalidTokenException");
[Link]([Link]()); return new ResponseEntity<>(error,
[Link]); } }`
@ControllerAdvice
public class GlobalExceptionHandler {
ErrorHandler errorHandler;

@Autowired
public GlobalExceptionHandler(ErrorHandler errorHandler) {
[Link] = errorHandler;
}

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handlerInvalidTokenException() {
[Link]("Token is null or Invalid");
[Link]("InvalidTokenException");
[Link]([Link](401).value());
return new ResponseEntity<>(errorHandler, [Link](500));
}

what is the difference between both code I wrote code which is clean and autowired we need
not to create multiple Error Handler objects right which is best practices

Great question 👍 you’ve spotted a subtle difference in object lifecycle and best practices. Let’s compare
your version vs the one I showed:

Your Code

java

@ControllerAdvice
public class GlobalExceptionHandler {
ErrorHandler errorHandler;

@Autowired
public GlobalExceptionHandler(ErrorHandler errorHandler) {
[Link] = errorHandler;
}

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handlerInvalidTokenException() {
[Link]("Token is null or Invalid");
[Link]("InvalidTokenException");

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 80/110
[Link]([Link](401).value());
return new ResponseEntity<>(errorHandler, [Link](500));
}
}

🔎 Key points:
ErrorHandler is injected once (singleton bean).
Every exception request mutates the same errorHandler object.
In concurrent requests (say, 2 users get invalid token at same time), both will overwrite the same
object → thread safety issues, inconsistent responses.
Also you’re returning 500 (Internal Server Error) instead of 401 (Unauthorized).

My Code

java

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handleInvalidTokenException(InvalidTokenException ex) {
ErrorHandler error = new ErrorHandler(); // new object each time
[Link]([Link]());
[Link]("InvalidTokenException");
[Link]([Link]());

return new ResponseEntity<>(error, [Link]);


}
}

🔎 Key points:
Creates new ErrorHandler object for each exception.
No shared mutable state → thread safe.
Cleaner semantics for error responses.
Status code matches the exception (401).

✅ Best Practice
Always create a fresh error object per request inside the handler.
That way:

No race conditions
Responses don’t get mixed between different requests
No accidental leaking of old error data

If you really want to reduce object creation, you could make ErrorHandler immutable (with final fields,
constructor only) and reuse constants, but in REST APIs, object-per-request is normal and negligible
cost compared to network overhead.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 81/110
👉 So: your version is not safe in concurrent environments because of shared state.
Best practice is my version → stateless @ControllerAdvice, new ErrorHandler per exception.

Do you want me to also show you how to write a generic global handler that can handle all exceptions
without repeating code for each?

how to erase bean or controller advices created in spring container bcoz i'm getting still my set
msgs although i used your code in project

Ah, I see what’s happening 👀


If you’re still seeing the old messages even after switching to my “new object” approach, it means your
old GlobalExceptionHandler (the one with @Autowired ErrorHandler) is still being picked up by Spring’s
component scan and sitting in the container alongside your new one.
Spring will happily register multiple @ControllerAdvice beans, and whichever matches the exception
may run (sometimes even multiple at once).

🔥 How to “erase” / remove old beans in Spring


1. Delete / Comment Out Old @ControllerAdvice
Make sure the old class is removed from your project or at least not annotated with
@ControllerAdvice.

Example:

java

//@ControllerAdvice // ❌Comment this out


public class GlobalExceptionHandlerOld {
...
}

2. Check Package Scanning


Spring Boot auto-scans starting from your main class’s package.
If your old handler is still under that package, it’s still being loaded.
Move the old handler out of scanned packages (or delete it).
3. Restart the Application
Spring doesn’t “hot delete” beans during runtime.
If you remove or rename a bean, you must restart your app so the container is rebuilt clean.
4. Use @Primary or @Order (if you have multiple handlers intentionally)

If you do want multiple @ControllerAdvice classes but need one to win, use:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 82/110
java

@ControllerAdvice
@Order(1) // smaller number = higher priority
public class NewGlobalExceptionHandler { ... }

Or give the preferred handler @Primary when you inject beans.


5. Double-check ErrorHandler Bean
If ErrorHandler itself is marked with @Component and Spring is managing it, you’ll still get a
singleton that holds stale state.
✅ Fix: make ErrorHandler a plain POJO (no @Component, no bean), just new ErrorHandler() inside
handlers.

⚡ Recommended Clean Setup


java

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handleInvalidTokenException(InvalidTokenException ex) {
ErrorHandler error = new ErrorHandler(); // plain POJO, no @Component
[Link]([Link]() != null ? [Link]() : "Token is null or
Invalid");
[Link]("InvalidTokenException");
[Link]([Link]());

return new ResponseEntity<>(error, [Link]);


}
}

And make sure ErrorHandler is not a Spring bean:

java

public class ErrorHandler {


private String message;
private String typeOfException;
private int errorCode;
// getters + setters
}

👉 So the root cause in your case:


Either you still have 2 @ControllerAdvice beans loaded, or
Your ErrorHandler is a singleton bean instead of a per-request object.

Would you like me to show you how to log all active @ControllerAdvice beans at startup so you can
confirm which one is still in play?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 83/110
hey i'm saying you still i'm getting my old msg:
, message=500 : "{"message":"Token empty or Invalid or does not
exists.","errorCode":401,"typeOfException":"TokenEmptyException"}", path=/products/7}]

spring is picking the same msg from its old container tell me how i should tell spring this is
updated once
package [Link];

import [Link];
import [Link];
import [Link];
import [Link];

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handleInvalidTokenException(InvalidTokenException
ex) {
ErrorHandler error = new ErrorHandler();
[Link]([Link]());
[Link]("InvalidTokenException");
[Link]([Link]());

return new ResponseEntity<>(error, [Link]);


}
}

Got it 👍 thanks for sharing the exact updated code.


The fact that you are still getting the old message ("Token empty or Invalid or does not exists.")
means one of these things is happening:

🔍 Why Spring is still using the old message


1. Another Exception Handler Class Exists
You probably still have your old GlobalExceptionHandler (the one that set the hardcoded "Token
empty or Invalid or does not exists.") somewhere else in your codebase and it’s still
annotated with @ControllerAdvice.
Spring can load multiple @ControllerAdvice beans. If both match, Spring may choose the older
one.
2. Wrong Exception Type
Your new handler is catching InvalidTokenException.

But maybe you are throwing a different exception (TokenEmptyException in your log).
If you don’t update the @ExceptionHandler annotation to cover that, Spring will keep using the
other handler.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 84/110
👉 In your log:
bash

typeOfException":"TokenEmptyException"

This is not InvalidTokenException, so your new handler never runs.


3. Spring Boot DevTools / Caching
If you are running with DevTools, sometimes it keeps old class versions in memory. A full clean
+ rebuild + restart usually fixes it.

✅ How to fix
Step 1: Search your project for any other @ControllerAdvice.
Delete or comment out the old handler.
Step 2: Unify your exception classes.
If you are throwing TokenEmptyException, update the handler:

java

@ExceptionHandler({[Link], [Link]})
public ResponseEntity<ErrorHandler> handleInvalidTokenException(RuntimeException ex) {
ErrorHandler error = new ErrorHandler();
[Link]([Link]() != null ? [Link]() : "Token is null or
Invalid");
[Link]([Link]().getSimpleName());
[Link]([Link]());

return new ResponseEntity<>(error, [Link]);


}

Step 3: Do a clean build:

nginx

mvn clean install

then restart the application (not hot reload).

👉 So the real issue here is:


Your new handler only handles InvalidTokenException, but your code is throwing TokenEmptyException.
That’s why Spring is still responding with the old message.
Do you want me to show you a generic global exception handler that will automatically catch all your
custom token-related exceptions so you don’t have to add them one by one?

hey i tried your all approaches but still spring container is using older bean which i created

at
[Link]([Link]
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 85/110
:102)
at
[Link](DefaultResponseErr
[Link])
at
[Link](DefaultResponseErr
[Link])
at
[Link]([Link]
:63)
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at
[Link](AuthenticationCommo
[Link])
at
[Link]([Link])
at [Link]/[Link].invoke0(Native Method)
at
[Link]/[Link]([Link]
a:77)
at
[Link]/[Link](DelegatingMethodAccesso
[Link])
at [Link]/[Link]([Link])
at
[Link](InvocableHandl
[Link])
at
[Link](Invoca
[Link])
at
[Link]
keAndHandle([Link])
at
[Link]
okeHandlerMethod([Link])
at
[Link]
ndleInternal([Link])
at
[Link](Abstract
[Link])
at
[Link]([Link])
at
[Link]([Link])
at
[Link]([Link]
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 86/110
14)
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at
[Link]([Link])
at [Link]([Link])
at [Link]([Link])
at
[Link]([Link])
at [Link]([Link])
at
[Link]$[Link]([Link]:
108)
at
[Link]$doFilterInternal$3(FilterChainProxy
.java:231)
at
[Link]$FilterObservation$SimpleF
[Link]$wrap$1([Link])
at
[Link]$AroundFilterObservation$
[Link]$wrap$1([Link])
at
[Link]$wrapSecured$0(O
[Link])
at
[Link]$[Link](
[Link])
at
[Link](AuthorizationFilt
[Link])
at
[Link]$[Link]
er([Link])
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
[Link])
at
[Link](ExceptionTranslati
[Link])
at
[Link](ExceptionTranslati
[Link])
at
[Link]$[Link]
er([Link])
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 87/110
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
[Link])
at
[Link](Anon
[Link])
at
[Link]$[Link]
er([Link])
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
[Link])
at
[Link]
([Link])
at
[Link]$[Link]
er([Link])
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
[Link])
at
[Link](RequestCac
[Link])
at
[Link]$[Link]
er([Link])
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
[Link])
at
[Link]([Link]:
107)
at
[Link]([Link]:
93)
at
[Link]$[Link]
er([Link])
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 88/110
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
[Link])
at
[Link](HeaderWriterFilte
[Link])
at
[Link](HeaderWriterFilte
[Link])
at
[Link]([Link])
at
[Link]$[Link]
er([Link])
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
[Link])
at
[Link](SecurityContext
[Link])
at
[Link](SecurityContext
[Link])
at
[Link]$[Link]
er([Link])
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
[Link])
at
[Link]
FilterInternal([Link])
at
[Link]([Link])
at
[Link]$[Link]
er([Link])
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 89/110
[Link])
at
[Link](DisableEncod
[Link])
at
[Link]([Link])
at
[Link]$[Link]
er([Link])
at
[Link]$AroundFilterObservation$
[Link]$wrap$0([Link])
at
[Link]$[Link](
[Link])
at
[Link]$[Link](
[Link])
at
[Link]([Link])
at [Link]([Link])
at
[Link]$[Link]([Link]:
113)
at
[Link]$createCacheFil
ter$3([Link])
at
[Link]$[Link]([Link]:
113)
at [Link]([Link])
at
[Link]
on$[Link]([Link])
at
[Link]([Link]
a:352)
at
[Link]([Link])
at
[Link]([Link])
at [Link]([Link])
at
[Link]([Link]:
100)
at
[Link]([Link])
at
[Link]([Link])
at [Link]([Link])
at
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 90/110
[Link]([Link])
at
[Link]([Link])
at
[Link]([Link])
at [Link]([Link])
at
[Link](ServerHttpObserva
[Link])
at
[Link]([Link])
at
[Link]([Link])
at [Link]([Link])
at
[Link](CharacterEncodingFilte
[Link])
at
[Link]([Link])
at
[Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at [Link]([Link])
at
[Link]$[Link]([Link])
at [Link]$[Link]([Link])
at [Link]([Link])
at
[Link]([Link])
at
[Link]$[Link]([Link])
at [Link]$[Link]([Link])
at [Link]/[Link]([Link])
, message=500 : "{"message":"Token empty or Invalid or does not
exists.","errorCode":401,"typeOfException":"TokenEmptyException"}", path=/products/7}]

Aha, this stack trace gives away the culprit 🚨


Notice this part 👇
less

at
[Link]([Link]

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 91/110
)
...
at
[Link]([Link])

That means:

The error response is not coming from your local GlobalExceptionHandler at all.
It’s coming from a remote API that RestTemplate calls inside your
[Link]() method.

That remote service is still returning:

json

{"message":"Token empty or Invalid or does not


exists.","errorCode":401,"typeOfException":"TokenEmptyException"}

👉 So your Spring container is not “reusing an old bean.”


It’s simply passing through the response it got from the remote authentication service. That’s why
no matter how much you change your GlobalExceptionHandler, you keep seeing the same old message.

✅ What to do
You have two choices:

1. Let your GlobalExceptionHandler wrap remote exceptions

Catch the HttpServerErrorException that RestTemplate throws when the remote service returns 500, then
translate it into your custom error response:

java

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handleHttpServerError(HttpServerErrorException ex) {
ErrorHandler error = new ErrorHandler();
[Link]("Token is invalid (remote service response overridden).");
[Link]("InvalidTokenException");
[Link]([Link]());

return new ResponseEntity<>(error, [Link]);


}
}

This way your client never sees the raw "Token empty or Invalid or does not exists.".

2. Handle it inside [Link]()

Instead of letting the raw exception bubble up:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 92/110
java

public UserDto validateToken(String token) {


try {
// [Link](... call auth service ...)
} catch (HttpServerErrorException ex) {
throw new InvalidTokenException("Token invalid or expired");
}
}

Then your GlobalExceptionHandler for InvalidTokenException will kick in correctly.

👉 To summarize:
The old message isn’t stuck in Spring’s bean container.
It’s coming from the remote service you call with RestTemplate.
To fix it, you need to catch and rewrap that remote error into your own exception or override it in
your @ControllerAdvice.

Do you want me to show you the cleanest setup where all remote service errors (401, 403, 500) from
RestTemplate are mapped into your own custom exceptions, so you never leak their raw JSON to your
clients?

* It’s coming from a **remote API** that `RestTemplate` calls inside your
`[Link]()` method.
package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].*;

import [Link];

@RestController
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 93/110
@RequestMapping("/products")
public class ProductController {
private final AuthenticationCommons authenticationCommons;
private final ProductService productService;
private final GlobalExceptionHandler globalExceptionHandler;

@Value("${[Link]}")
private String serverPort;

@Qualifier("eurekaRegistration")
private Registration registration;

private final EurekaClient eurekaClient;

@Autowired
public ProductController(@Qualifier("HeyProductService") ProductService productService,
AuthenticationCommons authenticationCommons,
GlobalExceptionHandler globalExceptionHandler,
@Qualifier("eurekaRegistration") Registration registration,
EurekaClient eurekaClient) {
[Link] = productService;
[Link] = authenticationCommons;
[Link] = globalExceptionHandler;
[Link] = registration;
[Link] = eurekaClient;
}

//[Link]
@GetMapping("/allProducts")
public List<Product> getAllProducts() {
InstanceInfo instanceInfo = [Link]().getInfo();
String instanceId = (instanceInfo != null) ? [Link]() : "Unknown
Instance";

[Link]("Port Name/Instance Name registered in Eureka Server is: " +


instanceId);
[Link]("Request arrived in product service in port no. " + serverPort);
return [Link]();
}

//[Link]
@GetMapping("/{id}")
public Product getProductById(@PathVariable("id") Long id, @RequestHeader("Authorization")
String token) {
UserDto userDto = [Link](token);

if (userDto == null) {
throw new InvalidTokenException("Token is null or invalid");
}

Product product = [Link](id);


Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 94/110
[Link]("Check do Api requests are load balanced in product service");
return product;
}

//[Link]
@PostMapping("/all")
public Product postAllProducts(@RequestBody CreateProductRequestDto
createProductRequestDto) {
return [Link](
[Link](),
[Link](),
[Link](),
[Link](),
[Link]()
);
}

@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody
CreateProductRequestDto createProductRequestDto) {
return [Link](id, createProductRequestDto);
}

/* @GetMapping("/products1")
public List<ProductIdAndTitleProjection> getProductsByCategoryTitle(@RequestParam("title")
String title) {
return [Link](title);
}*/

//[Link]
@GetMapping("/categories/{title}")
public List<ProductIdAndTitleProjection>
getProductTitlesByCategoryTitle(@PathVariable("title") String categoryTitle) {
return [Link](categoryTitle);
}

//[Link]
@GetMapping("/categories/{title}/{id}")
public Product getFindNameOfProductByCategoryTitleAndProdId(@PathVariable("title")
String title, @PathVariable("id") Long id) {
return [Link](title, id);
}

@GetMapping("/allPrice")
public List<ProductPriceProjection> getPriceFromProduct() {
return [Link]();
}

/*
public ResponseEntity<Product> updateProduct(@PathVariable Long id, @RequestBody
Product updatedProduct) {
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 95/110
Product updatedProductResult = [Link](id, updatedProduct);
return new ResponseEntity<>(updatedProductResult, [Link]);
}

*/

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

@Component
public class AuthenticationCommons {
private final RestTemplate restTemplate;

public AuthenticationCommons(RestTemplate restTemplate) {


[Link] = restTemplate;
}

public UserDto validateToken(String token) {


if (token == null) {
return null;
}

HttpHeaders headers = new HttpHeaders();


[Link]("Authorization", token);

// Create HttpEntity with headers


HttpEntity<String> entity = new HttpEntity<>(headers);

// Use exchange method to make the request with headers


ResponseEntity<UserDto> response = [Link](
//"[Link] //calling user service to validate token from a
Product service project
// "[Link] SERVICE TOKEN AND JWT/users/validate", //won't work if you have
space in the url
// "[Link] //if you have
space in the url then it won't work instead change "[Link]=" i.e. project name
without any spaces
"[Link]
[Link],
entity,
[Link]
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 96/110
);
// [Link]("Check do Api requests are load balanced in product service");
return [Link]();
}
}this is my updated code from last last error msgs are you dumb kya?

Got it 👍
I see what’s happening in your code.
The reason you are still seeing the old error message ( "Token empty or Invalid or does not exists." )
even after updating your GlobalExceptionHandler is because:
➡️ That message is not coming from your Product Service’s GlobalExceptionHandler.
It’s actually coming from the User Service you’re calling here:

java

ResponseEntity<UserDto> response = [Link](


"[Link]
[Link],
entity,
[Link]
);

If the users/validate API in the User Service throws InvalidTokenException, then its own
GlobalExceptionHandler there returns the JSON with message "Token empty or Invalid or does not
exists.".

So your Product Service never gets a chance to apply its own GlobalExceptionHandler — instead, it just
receives that JSON from the remote call and passes it along.

✅ How to fix this:


You have two options:

Option 1: Let the User Service decide messages

Keep User Service responsible for token validation and error messages.
Then in Product Service, don’t throw InvalidTokenException, just propagate whatever User Service
returns.

Option 2: Centralize error handling in Product Service

Catch the exception (or bad response) from RestTemplate and rethrow your own
InvalidTokenException.

Example:

java

public UserDto validateToken(String token) {


if (token == null) {
throw new InvalidTokenException("Token is null or invalid");
}

try {
HttpHeaders headers = new HttpHeaders();

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 97/110
[Link]("Authorization", token);

HttpEntity<String> entity = new HttpEntity<>(headers);

ResponseEntity<UserDto> response = [Link](


"[Link]
[Link],
entity,
[Link]
);

return [Link]();

} catch (Exception ex) {


// Convert remote service error into *your own exception*
throw new InvalidTokenException("Token is invalid or expired");
}
}

Now your GlobalExceptionHandler in Product Service will kick in and return your new custom message,
not the one from User Service.

👉 So basically, nothing is “stuck in Spring’s container.”


The old message you see is still being returned by the remote User Service.

Do you want me to show you how to intercept the RestTemplate error (like HttpClientErrorException)
and map it to your own InvalidTokenException, so that you always control the error response in Product
Service?

Hey based upon developer choice or industry expert experiences which is the best way to
handle exception at Runtime Or Exception meaning unchecked exception or checked exception
is best to use think deeper and tell me

Short answer: in modern Spring apps (esp. microservices), prefer unchecked (runtime) exceptions
almost everywhere. Use checked exceptions only at low-level boundaries where the caller can
immediately recover (I/O, parsing, reflection), then convert them to your own unchecked exceptions
before crossing service/module boundaries.
Here’s the deeper “why” and a clean pattern to follow.

When to use which


Use unchecked (extends RuntimeException) for:

Business/HTTP errors: validation failures (400), not found (404), unauthorized/invalid token
(401/403), domain rule violations (409), etc.
Infrastructure/technical faults you won’t handle locally: downstream 5xx, timeouts, DB errors,
circuit breaker open, etc.
Transactional code: Spring rolls back on RuntimeException by default; checked exceptions need
rollbackFor, which is easy to forget.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 98/110
Use checked (extends Exception) only when:

The method’s immediate caller can and should handle/recover (e.g., retry a local file read, select a
different parser, prompt for different path).
You’re writing a public library API (not a Spring service) and want to force handling of a specific,
recoverable condition.

Avoid exceptions for routine control flow. For expected, frequent “misses” (e.g., cache lookup), return
Option/nullable or a Result type—reserve exceptions for exceptional paths.

How this maps to your case


Invalid/empty token → client error → unchecked InvalidTokenException and map to 401.
User Service unreachable/timeout → technical fault → unchecked DownstreamServiceException
and map to 502/503.
Do not bubble the User Service’s raw error JSON; catch its client/server exceptions and rethrow
your own unchecked exceptions so your API surface and error shape stay consistent.

A practical pattern
1) Exception hierarchy (unchecked):

java

public abstract class AppException extends RuntimeException {


private final int httpStatus;
private final String code;
public AppException(String message, int httpStatus, String code, Throwable cause) {
super(message, cause);
[Link] = httpStatus;
[Link] = code;
}
public int getHttpStatus() { return httpStatus; }
public String getCode() { return code; }
}

public class InvalidTokenException extends AppException {


public InvalidTokenException(String msg) {
super(msg, 401, "AUTH_INVALID_TOKEN", null);
}
}

public class DownstreamServiceException extends AppException {


public DownstreamServiceException(String msg, Throwable cause) {
super(msg, 503, "DOWNSTREAM_UNAVAILABLE", cause);
}
}

2) Translate at integration boundaries:

java

public UserDto validateToken(String token) {


if (token == null || [Link]()) {
throw new InvalidTokenException("Missing Authorization header");
}
try {
// ... call user-service ...

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 99/110
return [Link]();
} catch ([Link] e) {
throw new InvalidTokenException("Token is invalid or expired");
} catch (ResourceAccessException | HttpServerErrorException e) {
throw new DownstreamServiceException("User service unavailable", e);
}
}

3) Centralize HTTP mapping (@ControllerAdvice):

java

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handleAppException(AppException ex) {
ErrorHandler dto = new ErrorHandler();
[Link]([Link]());
[Link]([Link]().getSimpleName());
[Link]([Link]());
return [Link]([Link]()).body(dto);
}

@ExceptionHandler([Link]) // safety net


public ResponseEntity<ErrorHandler> handleOther(Exception ex) {
ErrorHandler dto = new ErrorHandler();
[Link]("Unexpected error");
[Link]("InternalError");
[Link](500);
return [Link](500).body(dto);
}
}

Tip: In Spring 6+, consider returning ProblemDetail to align with RFC-7807.

Industry consensus (why unchecked wins in Spring)


Ergonomics & readability: no throws clutter across layers.
Framework alignment: Spring’s transaction and exception resolvers expect runtime exceptions.
Consistency at boundaries: you translate diverse lower-level failures into a small, consistent set of
API errors.
Checked exceptions are overused in legacy Java; most teams now reserve them for immediate,
recoverable situations in non-Spring libraries.

Bottom line
Default: unchecked exceptions + centralized mapping.
Boundary rule: catch low-level (often checked) exceptions, decide if recoverable; if not, convert to
your unchecked domain/infrastructure exceptions.
HTTP mapping: 4xx for client issues, 5xx for server/infra; don’t leak downstream payloads.

If you want, I can help refactor your project to this pattern end-to-end (exception classes, mappers, and
the RestTemplate/WebClient translation spots).

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 100/110
so you mean uncheck exceptions are best to throw error right? now my question is in service
layer of backend code we need to throw exception at method level right

public List<ScheduledLecture> scheduleLectures(List<Long> lectureIds, Long instructorId,


Long batchId) throws InvalidLectureException, InvalidInstructorException,
InvalidBatchException {
}
and in exception package we need to write this way correct?.

package [Link];

public class InvalidInstructorException extends Exception{


public InvalidInstructorException(String message) {
super(message);
}
}

Great question 👍 — let’s slow this down because you’re mixing two things:
Checked exceptions (extends Exception) → must declare with throws in the method signature.
Unchecked exceptions (extends RuntimeException) → no need to declare throws, they can be
thrown anywhere.

✅ What you wrote:


java

public List<ScheduledLecture> scheduleLectures(List<Long> lectureIds, Long instructorId, Long


batchId)
throws InvalidLectureException, InvalidInstructorException, InvalidBatchException {
}

and

java

public class InvalidInstructorException extends Exception {


public InvalidInstructorException(String message) {
super(message);
}
}

This is checked exception style.


Meaning: every caller of scheduleLectures(...) will now be forced to write:

java

try {
[Link](lectures, instructorId, batchId);
} catch (InvalidLectureException | InvalidInstructorException | InvalidBatchException e) {

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 101/110
// handle
}

This is useful only if the caller can immediately do something meaningful with the exception (retry,
substitute, prompt user, etc.).
But in a typical Spring backend service layer → controller → REST API flow, the caller (controller) usually
just bubbles up to the global exception handler. That means checked exceptions here only add
boilerplate and noise.

✅ Recommended in service layer


Use unchecked exceptions:

java

public class InvalidInstructorException extends RuntimeException {


public InvalidInstructorException(String message) {
super(message);
}
}

And then your service method doesn’t need throws:

java

public List<ScheduledLecture> scheduleLectures(List<Long> lectureIds, Long instructorId, Long


batchId) {
if (!instructorExists(instructorId)) {
throw new InvalidInstructorException("Instructor not found: " + instructorId);
}
// more logic...
}

The exception flows up, your @ControllerAdvice catches it, and you map it to a proper HTTP response
(400/404 etc.).

🔑 Rule of Thumb:
Spring applications (REST, microservices, backend apps):
→ Use unchecked exceptions in your exceptions package (extends RuntimeException).
→ Handle them centrally with @ControllerAdvice.
Libraries, utilities, or API code where caller must handle:
→ Use checked exceptions (extends Exception).
Example: a CSV parsing library throwing InvalidCsvFormatException (caller can switch to another
parser or skip the file).

👉 So in your case ( InvalidInstructorException, InvalidLectureException,


etc.) — these are domain
errors in a backend service. Make them unchecked exceptions, and don’t clutter your method
signatures with throws.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 102/110
Do you want me to rewrite your scheduleLectures method + exception classes in the clean, Spring-
style unchecked + @ControllerAdvice approach so you have a working template?

* **Checked exceptions** (`extends Exception`) → must declare with `throws` in the method
signature. * **Unchecked exceptions** (`extends RuntimeException`) → no need to declare `throws`,
they can be thrown anywhere.
hey please add points like try catch block. for which exception we must use and so on

Perfect 👍 let’s put everything together in a developer-friendly guide so you’ll know when to use
checked vs unchecked exceptions, and when to wrap code in try–catch.

⚖️ Checked vs Unchecked Exceptions in Java (and Spring)


🔹 Checked Exceptions ( extends Exception)

Must be declared in the method signature using throws.


Caller is forced to either try–catch or rethrow.
Best when:
The caller can recover immediately (e.g., ask user for a new file, retry a network call).
You’re writing a library or API where clients must handle certain error conditions.

👉 Example:
java

try {
FileInputStream fis = new FileInputStream("[Link]");
} catch (FileNotFoundException e) {
// Handle: maybe prompt user to select another file
}

🔹 Unchecked Exceptions ( extends RuntimeException)

No need to declare throws in method signature.


Caller can choose to handle, or let it bubble up.
Best when:
It’s a programming error (null pointer, illegal argument, bad state).
It’s a domain/business error in a Spring backend (e.g., invalid ID, user not found).
You have a global exception handler (@ControllerAdvice) to map it to an HTTP response.

👉 Example in Spring:
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 103/110
java

public Product getProductById(Long id) {


return [Link](id)
.orElseThrow(() -> new ProductNotFoundException("Product " + id + " not found"));
}

No throws needed → ProductNotFoundException is RuntimeException.

🧑‍💻 When to Use try–catch

Use try–catch for checked exceptions when you can do something useful right there:
Retry logic
Cleanup resources
Fallback to defaults

Don’t wrap unchecked exceptions in try–catch unless you really have a recovery/fallback plan.
Example: catching NullPointerException is almost always a code smell.

✅ Industry Practice (Spring/Backend Services)


1. Service & Controller layers:
Throw unchecked exceptions (RuntimeException) for domain/business errors.
Let them bubble to @ControllerAdvice.
2. DAO/External API calls (checked exceptions from Java APIs):
Catch them in service layer and rethrow as custom unchecked exceptions.
Example:

java

try {
[Link]("SOME QUERY");
} catch (SQLException e) {
throw new DatabaseAccessException("DB error occurred", e);
}

3. Global Handling:
Use @ControllerAdvice to centralize the mapping of exceptions → HTTP status codes + JSON
responses.

📝 Rule of Thumb
Checked (Exception): caller must handle → IO, JDBC, external API.
Unchecked (RuntimeException): programmer/business errors → invalid state, bad input, missing
entity.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 104/110
try–catch only where you can recover. Otherwise, let it bubble.

👉 Would you like me to create a ready-made template for your project with:
1 checked exception use case (like file upload)
1 unchecked exception use case (like invalid product ID)
and the global @ControllerAdvice handler for both?

But in a typical Spring backend service layer → controller → REST API flow, the caller (controller)
usually just **bubbles up** to the global exception handler. That means checked exceptions here
only add boilerplate and noise.
so you mean in controller we shouldn't be using try catch block right? which is bad to use

Exactly 👍 — you got it.


In a Spring REST controller, using try–catch blocks all over the place is considered bad practice
because:

❌ Why try–catch in Controller is not good

1. Boilerplate & Repetition – every controller method would need the same repetitive error handling
code.
2. Hard to Maintain – if you change error format, you must update all controllers.
3. Breaks Separation of Concerns – controller should just handle input → service → output, not deal
with exception formatting.

✅ Best Practice
Don’t use try–catch in controller for business/domain errors.
Throw unchecked exceptions (RuntimeException) from service layer.
Handle them centrally with @ControllerAdvice (global exception handler).

👉 Example:
Service layer

java

public Product getProductById(Long id) {


return [Link](id)
.orElseThrow(() -> new ProductNotFoundException("Product " + id + " not found"));
}

Controller

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 105/110
java

@GetMapping("/{id}")
public Product getProduct(@PathVariable Long id) {
return [Link](id);
// no try–catch here
}

Global Exception Handler

java

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler([Link])
public ResponseEntity<ErrorHandler> handleProductNotFound(ProductNotFoundException ex) {
ErrorHandler error = new ErrorHandler();
[Link]([Link]());
[Link]("ProductNotFoundException");
[Link](HttpStatus.NOT_FOUND.value());

return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);


}
}

📌 The only time you’d put try–catch inside a controller is when:

You need very specific handling for that one endpoint only (rare case).
Example: calling a third-party API where you want to fallback with a default response instead of
failing globally.

👉 Do you want me to show you one real case where a try–catch in controller is acceptable, so you’ll
see the contrast clearly?

unchecked exceptions
meaning at the time of runtime we are throwing exception

Yes ✅ — exactly.
When we say unchecked exceptions (like RuntimeException and its subclasses), it means:

They are thrown at runtime.


The compiler does not force you to declare them in the method signature with throws.
Example:

java

public Product getProductById(Long id) {


return [Link](id)
.orElseThrow(() -> new ProductNotFoundException("Product not found"));

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 106/110
// ProductNotFoundException extends RuntimeException (unchecked)
}

Here, ProductNotFoundException is thrown during runtime if product not found.


You don’t need:

java

public Product getProductById(Long id) throws ProductNotFoundException { ... }

That “throws” part is only required for checked exceptions (extends Exception).

🔑 Difference
Checked Exception → must declare in method signature (throws ...), compiler forces handling.
Unchecked Exception (Runtime) → no need to declare, thrown freely at runtime, best for
business/domain logic in modern Spring apps.

So yes 👍in controllers/services, we generally throw runtime (unchecked) exceptions → and then
Spring’s @ControllerAdvice catches them at runtime and formats a proper response.
👉 Do you want me to show you a comparison of your InvalidInstructorException in both ways — once
as checked and once as unchecked, with pros/cons?

Do you want me to **rewrite your scheduleLectures method + exception classes** in the clean,
Spring-style unchecked + `@ControllerAdvice` approach so you have a working template? Ask
ChatGPT
please write that will helpful for me

Perfect 👍 let’s take your scheduleLectures example and write it in both ways:

✅ 1. Using Checked Exceptions (extends Exception)

Exception Classes

java

package [Link];

public class InvalidInstructorException extends Exception {


public InvalidInstructorException(String message) {
super(message);
}
}

public class InvalidLectureException extends Exception {


public InvalidLectureException(String message) {
super(message);

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 107/110
}
}

public class InvalidBatchException extends Exception {


public InvalidBatchException(String message) {
super(message);
}
}

Service Layer

java

public List<ScheduledLecture> scheduleLectures(


List<Long> lectureIds,
Long instructorId,
Long batchId)
throws InvalidLectureException, InvalidInstructorException, InvalidBatchException {

if (lectureIds == null || [Link]()) {


throw new InvalidLectureException("No lectures provided.");
}

if (instructorId == null) {
throw new InvalidInstructorException("Instructor not valid.");
}

if (batchId == null) {
throw new InvalidBatchException("Batch not valid.");
}

// business logic ...


return [Link]();
}

Controller

Since these are checked exceptions, you must either:

Declare throws ... again in the controller, OR


Wrap in try/catch.

That creates extra boilerplate 👎.


✅ 2. Using Unchecked Exceptions (extends RuntimeException)

Exception Classes

java

package [Link];

public class InvalidInstructorException extends RuntimeException {


public InvalidInstructorException(String message) {
super(message);
}
}

public class InvalidLectureException extends RuntimeException {


public InvalidLectureException(String message) {
super(message);

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 108/110
}
}

public class InvalidBatchException extends RuntimeException {


public InvalidBatchException(String message) {
super(message);
}
}

Service Layer

java

public List<ScheduledLecture> scheduleLectures(


List<Long> lectureIds,
Long instructorId,
Long batchId) {

if (lectureIds == null || [Link]()) {


throw new InvalidLectureException("No lectures provided.");
}

if (instructorId == null) {
throw new InvalidInstructorException("Instructor not valid.");
}

if (batchId == null) {
throw new InvalidBatchException("Batch not valid.");
}

// business logic ...


return [Link]();
}

Notice 👉 no throws ... in method signature. Cleaner, less boilerplate.

✅ Global Exception Handler (for both styles)


java

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler({
[Link],
[Link],
[Link]
})
public ResponseEntity<ErrorHandler> handleCustomExceptions(RuntimeException ex) {
ErrorHandler error = new ErrorHandler();
[Link]([Link]());
[Link]([Link]().getSimpleName());
[Link](HttpStatus.BAD_REQUEST.value());

return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);


}
}

🔎 Which is better?
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 109/110
Checked Exceptions → Good when you want to force the caller to handle. But in big apps (like
Spring Boot) this creates too much noise.
Unchecked Exceptions → Cleaner, modern best practice in Spring Boot. Let the global exception
handler deal with them, no need to litter code with throws and try/catch.

👉 That’s why industry experts prefer unchecked exceptions + @ControllerAdvice in microservices.


Do you want me to rewrite your scheduleLectures method + exception classes in the clean, Spring-
style unchecked + @ControllerAdvice approach so you have a working template?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 110/110

You might also like