0% found this document useful (0 votes)
17 views

CorejavaInterviewBooster13

Uploaded by

tellapuri.naresh
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views

CorejavaInterviewBooster13

Uploaded by

tellapuri.naresh
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 39

In Java, the `synchronized` keyword is used to ensure thread safety by allowing

only one thread to access a block of code or method at a time for a given object or
class. Here’s a detailed explanation of the three variations you mentioned:

---

### **1. `synchronized(this)`**


This synchronizes on the current object instance (`this`). It ensures that only one
thread can execute the synchronized block/method for a particular instance at a
time.

#### **Example:**
```java
class Display {
public void displayNumbers() {
synchronized (this) {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

public class SynchronizedExample {


public static void main(String[] args) {
Display display = new Display();

Thread t1 = new Thread(() -> display.displayNumbers(), "Thread-1");


Thread t2 = new Thread(() -> display.displayNumbers(), "Thread-2");

t1.start();
t2.start();
}
}
```

#### **Output Explanation:**


- Both threads share the same `Display` instance.
- The `synchronized(this)` ensures only one thread enters the `displayNumbers()`
block at a time.

**Expected Output:**
```
Thread-1 - 1
Thread-1 - 2
Thread-1 - 3
Thread-1 - 4
Thread-1 - 5
Thread-2 - 1
Thread-2 - 2
Thread-2 - 3
Thread-2 - 4
Thread-2 - 5
```
---

### **2. `synchronized(objectReference)`**


This synchronizes on a specific object reference (not necessarily `this`). Threads
synchronize on that specific object, and only one thread can acquire the lock on
that object at a time.

#### **Example:**
```java
class Display {
private final Object lock = new Object();

public void displayNumbers() {


synchronized (lock) {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

public class SynchronizedExample {


public static void main(String[] args) {
Display display = new Display();

Thread t1 = new Thread(() -> display.displayNumbers(), "Thread-1");


Thread t2 = new Thread(() -> display.displayNumbers(), "Thread-2");

t1.start();
t2.start();
}
}
```

#### **Output Explanation:**


- The `lock` object ensures that only one thread at a time executes the
synchronized block.
- Behavior is similar to `synchronized(this)`, but it's more explicit and provides
flexibility if you want to use multiple locks in the same class.

---

### **3. `synchronized(ClassName.class)`**


This synchronizes on the `Class` object. It is used for static methods or blocks
where all instances of the class need to share the same lock.

#### **Example:**
```java
class Display {
public static void displayStaticNumbers() {
synchronized (Display.class) {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

public class SynchronizedExample {


public static void main(String[] args) {
Thread t1 = new Thread(() -> Display.displayStaticNumbers(), "Thread-1");
Thread t2 = new Thread(() -> Display.displayStaticNumbers(), "Thread-2");

t1.start();
t2.start();
}
}
```

#### **Output Explanation:**


- Synchronizing on `Display.class` ensures that only one thread executes the
synchronized block/method for the `Display` class, no matter how many instances of
`Display` exist.

**Expected Output:**
```
Thread-1 - 1
Thread-1 - 2
Thread-1 - 3
Thread-1 - 4
Thread-1 - 5
Thread-2 - 1
Thread-2 - 2
Thread-2 - 3
Thread-2 - 4
Thread-2 - 5
```

---

### **Key Differences**

| Synchronization Type | Lock Acquired On | Use Case


|
|---------------------------|-------------------------------|----------------------
---------------------|
| `synchronized(this)` | The current object instance | Instance-level
synchronization. |
| `synchronized(objectRef)` | A specific object reference | Fine-grained control
for multiple locks. |
| `synchronized(ClassName.class)` | The `Class` object of the class | Class-level
(static) synchronization. |

---

### **Best Practices**


1. Use `synchronized(objectReference)` when you need finer control and want
multiple locks in the same class.
2. Use `synchronized(ClassName.class)` for static methods or blocks shared across
all instances.
3. Use `synchronized(this)` for instance-level synchronization when there’s no
specific external object to use as a lock.
=================================
The `Callable` interface in Java is used to define tasks that can return a result
and throw a checked exception. It is part of the `java.util.concurrent` package and
is typically used in conjunction with executors and future objects for asynchronous
programming.

---

### **Key Features of `Callable`:**


1. **Returns a Result**: Unlike `Runnable`, which doesn't return a result,
`Callable` provides a `call()` method that returns a value.
2. **Throws Exceptions**: The `call()` method can throw checked exceptions, making
it more versatile than `Runnable`.

---

### **Use Cases of `Callable`:**

#### 1. **Tasks Requiring a Return Value**:


When you need to execute a task that computes and returns a result.

#### **Example**:
```java
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableExample {


public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();

Callable<Integer> task = () -> {


// Simulate some computation
Thread.sleep(2000);
return 42; // Result of the task
};

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

try {
System.out.println("Doing something else while the task is
running...");
Integer result = future.get(); // Waits for the task to complete and
gets the result
System.out.println("Result of the task: " + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
```
**Output**:
```
Doing something else while the task is running...
Result of the task: 42
```

---

#### 2. **Handling Checked Exceptions**:


When a task might throw checked exceptions.

#### **Example**:
```java
import java.util.concurrent.Callable;

public class CallableWithExceptionExample {


public static void main(String[] args) {
Callable<String> task = () -> {
if (true) { // Simulate some condition
throw new Exception("Something went wrong!");
}
return "Task completed successfully";
};

try {
System.out.println(task.call());
} catch (Exception e) {
System.out.println("Caught exception: " + e.getMessage());
}
}
}
```

**Output**:
```
Caught exception: Something went wrong!
```

---

#### 3. **Parallel Computing**:


For running multiple tasks in parallel and combining their results.

#### **Example**:
```java
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.ArrayList;
import java.util.List;

public class ParallelTasksExample {


public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);

List<Callable<Integer>> tasks = new ArrayList<>();


for (int i = 1; i <= 5; i++) {
int number = i;
tasks.add(() -> {
Thread.sleep(1000);
return number * number;
});
}

try {
List<Future<Integer>> results = executor.invokeAll(tasks);
for (Future<Integer> result : results) {
System.out.println("Result: " + result.get());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
```

**Output**:
```
Result: 1
Result: 4
Result: 9
Result: 16
Result: 25
```

---

#### 4. **Asynchronous Task Management**:


Using `Callable` with `Future` to manage asynchronous tasks, where you might
want to check if a task is completed or cancel it.

---

### **Differences Between `Callable` and `Runnable`:**

| Feature | `Callable` | `Runnable`


|
|--------------------------|-------------------------------|-----------------------
------|
| **Method** | `call()` | `run()`
|
| **Returns a Result** | Yes | No
|
| **Throws Checked Exceptions** | Yes | No
|
| **Used With** | `Future` or `ExecutorService`| `Thread` or
`ExecutorService`|

---

### **When to Use `Callable`?**


1. When a task needs to **return a result**.
2. When a task might throw a **checked exception**.
3. When you are managing **asynchronous tasks** in a thread pool.
4. When combining results of **parallel computations**.
===============================================
In Java, there are several ways to create objects, each with its use case and
significance. Below are the common methods for creating objects in Java:

### 1. **Using `new` Keyword**


This is the most common way to create an object in Java.

**Example:**
```java
class Car {
String model;
int year;

Car(String model, int year) {


this.model = model;
this.year = year;
}
}

public class Main {


public static void main(String[] args) {
// Create object using 'new' keyword
Car myCar = new Car("Tesla", 2022);
System.out.println("Car Model: " + myCar.model + ", Year: " +
myCar.year);
}
}
```

**Explanation:**
- `Car myCar = new Car("Tesla", 2022);`: The `new` keyword creates a new
instance of the `Car` class and assigns it to the `myCar` reference variable.
- This is the most common and direct way to create objects.

### 2. **Using `Class.newInstance()` (Deprecated in Java 9+)**


This method uses reflection to create an instance of a class. It's deprecated in
Java 9 and onwards because it doesn’t handle exceptions properly.

**Example:**
```java
class Car {
String model;

Car(String model) {
this.model = model;
}
}

public class Main {


public static void main(String[] args) throws Exception {
// Create object using reflection (Deprecated)
Class<?> carClass = Class.forName("Car");
Car myCar = (Car)
carClass.getDeclaredConstructor(String.class).newInstance("Tesla");
System.out.println("Car Model: " + myCar.model);
}
}
```
**Explanation:**
- `Class.forName("Car")` loads the `Car` class.
- `newInstance()` creates an object, but this method has been deprecated because
it doesn't provide the ability to handle exceptions properly.

### 3. **Using `clone()` Method**


If a class implements `Cloneable` interface and overrides the `clone()` method,
you can create an object as a copy of another object.

**Example:**
```java
class Car implements Cloneable {
String model;

Car(String model) {
this.model = model;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

public class Main {


public static void main(String[] args) throws CloneNotSupportedException {
// Create original object
Car originalCar = new Car("Tesla");

// Create a new object by cloning the original object


Car clonedCar = (Car) originalCar.clone();
System.out.println("Cloned Car Model: " + clonedCar.model);
}
}
```

**Explanation:**
- The `clone()` method creates a new object that is a copy of the original `Car`
object.
- This approach is useful for duplicating objects when deep cloning is not
required.

### 4. **Using `Reflection` with Constructor**


You can use reflection to instantiate a class by calling its constructor.

**Example:**
```java
import java.lang.reflect.Constructor;

class Car {
String model;

Car(String model) {
this.model = model;
}
}

public class Main {


public static void main(String[] args) throws Exception {
// Use reflection to create an object
Constructor<Car> constructor = Car.class.getConstructor(String.class);
Car myCar = constructor.newInstance("Tesla");
System.out.println("Car Model: " + myCar.model);
}
}
```

**Explanation:**
- The `getConstructor()` method gets the constructor of the `Car` class that
takes a `String` parameter.
- `newInstance()` is used to create the object using the constructor.

### 5. **Using Factory Method**


A factory method is a method that returns an instance of a class. It's often
used in design patterns, like the Factory Pattern.

**Example:**
```java
class Car {
String model;

Car(String model) {
this.model = model;
}

// Factory Method
public static Car createCar(String model) {
return new Car(model);
}
}

public class Main {


public static void main(String[] args) {
// Create object using factory method
Car myCar = Car.createCar("Tesla");
System.out.println("Car Model: " + myCar.model);
}
}
```

**Explanation:**
- The `createCar()` method is a static factory method that returns a new `Car`
object. This approach encapsulates object creation and can be extended to return
different subclasses or objects based on some logic.

### 6. **Using `deserialization` (via `ObjectInputStream`)**


You can create an object by deserializing it from a stream of data (typically
from a file).

**Example:**
```java
import java.io.*;

class Car implements Serializable {


String model;

Car(String model) {
this.model = model;
}
}

public class Main {


public static void main(String[] args) throws IOException,
ClassNotFoundException {
// Serialize object to file
Car car = new Car("Tesla");
try (ObjectOutputStream out = new ObjectOutputStream(new
FileOutputStream("car.ser"))) {
out.writeObject(car);
}

// Deserialize object from file


try (ObjectInputStream in = new ObjectInputStream(new
FileInputStream("car.ser"))) {
Car deserializedCar = (Car) in.readObject();
System.out.println("Deserialized Car Model: " +
deserializedCar.model);
}
}
}
```

**Explanation:**
- The object is serialized to a file using `ObjectOutputStream`.
- The object is deserialized using `ObjectInputStream`, creating a new instance
of the object.
- This is useful for object persistence.

### 7. **Using `enum` Values**


If you're using an `enum` type, the instances are implicitly created for you,
and you don’t have to use the `new` keyword.

**Example:**
```java
enum Car {
TESLA, BMW, AUDI;
}

public class Main {


public static void main(String[] args) {
// Accessing enum instance
Car car = Car.TESLA;
System.out.println("Car Model: " + car);
}
}
```

**Explanation:**
- Enum constants like `Car.TESLA` are instances of the `Car` enum. These
instances are created automatically.

### 8. **Using `Supplier` in Java 8**


In Java 8, you can use the `Supplier` functional interface to create objects.

**Example:**
```java
import java.util.function.Supplier;

class Car {
String model;

Car(String model) {
this.model = model;
}
}

public class Main {


public static void main(String[] args) {
// Create object using Supplier
Supplier<Car> carSupplier = () -> new Car("Tesla");
Car myCar = carSupplier.get();
System.out.println("Car Model: " + myCar.model);
}
}
```

**Explanation:**
- A `Supplier<Car>` is created using a lambda expression, and the `get()` method
is called to create a new `Car` object.

---

### Summary of Ways to Create Objects in Java:


1. **Using `new` keyword**: The most common and straightforward approach.
2. **Using `Class.newInstance()`**: Reflection-based, but deprecated.
3. **Using `clone()` method**: Creates an object as a copy of another.
4. **Using reflection with constructor**: Creates an object using reflection and a
constructor.
5. **Using a Factory Method**: A method that returns an instance of the class.
6. **Using deserialization**: Creating an object by reading from a stream (file or
network).
7. **Using `enum` values**: Enums are implicitly instantiated for you.
8. **Using `Supplier` in Java 8**: A functional approach to object creation.

Each method has its use cases and is suitable for different scenarios. The most
common way is using the `new` keyword, but others, like reflection or factory
methods, can be used depending on the design needs.
==================================
In Spring Data JPA, the `@Transactional` annotation provides declarative
transaction management. One of its key attributes is `rollbackFor` (commonly
misspelled as "roolbackon"), which specifies the exceptions that should cause the
transaction to roll back.

By default, Spring rolls back a transaction only for **unchecked exceptions**


(subclasses of `RuntimeException`) and **errors**. Checked exceptions (subclasses
of `Exception`) do not trigger a rollback unless explicitly specified. The
`rollbackFor` attribute allows you to override this behavior and define which
exceptions should trigger a rollback.

---

### Syntax

```java
@Transactional(rollbackFor = {ExceptionType1.class, ExceptionType2.class})
```

---

### Example

#### Use Case: Order Service

Suppose you have a service that processes orders and needs to ensure that any
exception, including checked exceptions, triggers a rollback.

1. **Entity Class**: `Order`

```java
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String productName;
private int quantity;

// Getters and setters


}
```

2. **Repository Interface**: `OrderRepository`

```java
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRepository extends JpaRepository<Order, Long> {


}
```

3. **Service Class**: `OrderService`

```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderService {

@Autowired
private OrderRepository orderRepository;

@Transactional(rollbackFor = {Exception.class}) // Ensures rollback for both


checked and unchecked exceptions
public void placeOrder(Order order) throws Exception {
try {
orderRepository.save(order); // Save order in DB
if (order.getQuantity() > 100) {
throw new Exception("Quantity too large"); // Checked exception
}
} catch (Exception e) {
// Log exception and rethrow
System.out.println("Exception occurred: " + e.getMessage());
throw e;
}
}
}
```

4. **Controller**: `OrderController`

```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/orders")
public class OrderController {

@Autowired
private OrderService orderService;

@PostMapping
public String createOrder(@RequestBody Order order) {
try {
orderService.placeOrder(order);
return "Order placed successfully";
} catch (Exception e) {
return "Failed to place order: " + e.getMessage();
}
}
}
```

---

### Explanation

1. **Default Behavior**:
- Without `rollbackFor`, the transaction would not roll back for the `Exception`
(a checked exception), and the invalid order would remain in the database.

2. **Custom Behavior**:
- By specifying `rollbackFor = {Exception.class}`, the transaction rolls back
even for checked exceptions.

---

### Testing

**Input**:
```json
{
"productName": "Laptop",
"quantity": 150
}
```
**Output**:
```
Failed to place order: Quantity too large
```

- The database remains unchanged since the transaction was rolled back due to the
checked exception.

---

### Key Points

- **rollbackFor**: Specifies which exceptions should trigger a rollback.


- **noRollbackFor**: Specifies exceptions that should not trigger a rollback.
- Use these attributes to fine-tune transactional behavior based on your
application's requirements.
============================****Example for Custom Id
generator****===============================
@Entity
public class Client {

@Id
@GenericGenerator(name = "client_id", strategy =
"com.eframe.model.generator.ClientIdGenerator")
@GeneratedValue(generator = "client_id")
@Column(name="client_id")
private String clientId;
}

public class ClientIdGenerator implements IdentifierGenerator {

@Override
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException {

String prefix = "cli";


Connection connection = session.connection();

try (Statement statement=connection.createStatement();


ResultSet rs=statement.executeQuery("select count(client_id) as Id from
Client")) {
if(rs.next())
{
int id=rs.getInt(1)+101;
String generatedId = prefix + new Integer(id).toString();
return generatedId;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return null;
}
}

@Override
public Object generate(SharedSessionContractImplementor session, Object object){

String prefix = "cli";


JdbcConnectionAccess jdbcConnectionAccess = session.getJdbcConnectionAccess();
String query = "select count(client_id) as Id from Client";
try(Connection connection = jdbcConnectionAccess.obtainConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {
if (resultSet.next()) {
int id=resultSet.getInt(1)+101;
String generatedId = prefix + new Integer(id).toString();
return generatedId;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}}

============================================================
The `Arrays.asList()` method in Java is part of the `java.util.Arrays` utility
class and is used to create a **fixed-size** list backed by the specified array. It
essentially provides a bridge between an array and the `List` interface, allowing
you to treat an array as a `List`.

---

### Syntax

```java
public static <T> List<T> asList(T... a)
```

- **Parameters**:
- `T... a`: The array elements to be converted into a list.
- **Returns**:
- A `List` containing the array elements.

---

### Characteristics of `Arrays.asList()`

1. **Fixed Size**:
- The returned list is **fixed-size**, meaning you cannot add or remove
elements, but you can modify existing elements.

2. **Backed by Array**:
- Changes to the list reflect in the original array and vice versa.

3. **When to Use**:
- When you need to quickly convert an array into a `List` for easier iteration
or use with methods that accept a `List`.

4. **Not a Fully Mutable List**:


- If you need a fully mutable list, wrap it using `new
ArrayList<>(Arrays.asList(array))`.

---
### Example 1: Basic Usage

```java
import java.util.Arrays;
import java.util.List;

public class Main {


public static void main(String[] args) {
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);

// Access elements
System.out.println("List: " + list);

// Modify an element
list.set(1, "D");
System.out.println("Modified List: " + list);
System.out.println("Modified Array: " + Arrays.toString(array)); //
Reflects in the original array
}
}
```

**Output**:
```
List: [A, B, C]
Modified List: [A, D, C]
Modified Array: [A, D, C]
```

---

### Example 2: Adding or Removing Elements (Throws Exception)

```java
import java.util.Arrays;
import java.util.List;

public class Main {


public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3);

// Try to add or remove elements


try {
list.add(4); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("Cannot add elements: " + e.getMessage());
}

try {
list.remove(0); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("Cannot remove elements: " + e.getMessage());
}
}
}
```
**Output**:
```
Cannot add elements: null
Cannot remove elements: null
```

---

### Example 3: Converting to a Fully Mutable List

If you need a `List` where you can add or remove elements, wrap the result in a new
`ArrayList`:

```java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {


public static void main(String[] args) {
List<String> mutableList = new ArrayList<>(Arrays.asList("A", "B", "C"));
mutableList.add("D");
System.out.println("Mutable List: " + mutableList);
}
}
```

**Output**:
```
Mutable List: [A, B, C, D]
```

---

### When to Use `Arrays.asList()`

1. **Quick Conversion**:
- When you need to quickly convert an array into a `List` for easier
manipulation or compatibility with APIs that accept lists.

2. **Iteration**:
- For iterating over array elements using a `List` interface.

3. **Fixed Size Requirements**:


- When you do not need to change the size of the list.

---

### Limitations

1. **Fixed Size**:
- You cannot add or remove elements from the list.

2. **Mutability**:
- Changes to the list affect the backing array and vice versa.

3. **Generic Types**:
- Only works with arrays of objects; primitive arrays need to be converted using
boxed types (e.g., `Integer[]` for `int[]`).
---

### Summary

- `Arrays.asList()` is a quick way to create a `List` backed by an array.


- Use it when you need fixed-size behavior and can handle its limitations.
- If full mutability is needed, wrap it in an `ArrayList`.
==============================================================
In Spring MVC, `ModelAndView` is a class used as the return type of controller
methods to encapsulate both the **model data** and the **view name** in a single
object. It allows developers to pass data from the controller to the view and
specify which view should render that data.

---

### Key Features of `ModelAndView`

1. **Encapsulates Model and View**:


- The model contains data in the form of key-value pairs.
- The view specifies the name of the view (e.g., a JSP, Thymeleaf template,
etc.) to render the response.

2. **Convenience**:
- Instead of setting the model and view separately, `ModelAndView` combines them
into a single object.

3. **Flexible Return Type**:


- It is particularly useful for returning a combination of dynamic data and a
view name.

---

### Syntax

```java
public ModelAndView(String viewName)
public ModelAndView(String viewName, Map<String, ?> model)
public ModelAndView(String viewName, String modelName, Object modelObject)
```

---

### Example Use Cases

#### 1. **Basic Example**

```java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class GreetingController {

@RequestMapping("/greet")
public ModelAndView greet() {
ModelAndView mv = new ModelAndView("greeting"); // View name
mv.addObject("message", "Welcome to Spring MVC!"); // Adding model data
return mv;
}
}
```

- **Explanation**:
- `"greeting"`: The name of the view (e.g., `greeting.jsp` or `greeting.html`).
- `"message"`: A key-value pair added to the model.

---

#### 2. **Passing Multiple Model Attributes**

```java
@RequestMapping("/userDetails")
public ModelAndView userDetails() {
ModelAndView mv = new ModelAndView("user");
mv.addObject("username", "JohnDoe");
mv.addObject("email", "[email protected]");
return mv;
}
```

- In this example, `user.jsp` or `user.html` would receive `username` and `email`


as model attributes.

---

#### 3. **Using a Map for the Model**

```java
@RequestMapping("/product")
public ModelAndView productDetails() {
Map<String, Object> model = new HashMap<>();
model.put("id", 101);
model.put("name", "Laptop");
model.put("price", 75000);

return new ModelAndView("product", model);


}
```

- This approach is useful when you already have a `Map` of data to send to the
view.

---

#### 4. **Using ModelAndView with Logical View Names**

If you use a `ViewResolver` (e.g., Thymeleaf or JSP), you can define logical view
names. For example:

```java
// In application.properties (for Thymeleaf):
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
```

```java
@RequestMapping("/dashboard")
public ModelAndView dashboard() {
ModelAndView mv = new ModelAndView("dashboard"); // Resolves to
/templates/dashboard.html
mv.addObject("title", "User Dashboard");
return mv;
}
```

---

### When to Use `ModelAndView`?

1. **Combining Model and View**:


- Use it when you need to specify both the data (model) and the view to render.

2. **Legacy Code**:
- It is often used in legacy Spring MVC applications.

3. **Flexibility**:
- It gives you control to pass model attributes and specify view names
dynamically.

---

### Alternative: `@ModelAttribute` or `Map/Model`

Modern Spring MVC applications often use the `Model` or `Map` interface instead of
`ModelAndView`. For example:

```java
@RequestMapping("/modernGreet")
public String modernGreet(Model model) {
model.addAttribute("message", "Welcome to Spring MVC with Model!");
return "greeting"; // View name
}
```

- **When to Use Alternatives**:


- If you don't need the flexibility of `ModelAndView` and prefer simplicity.

---

### Summary

- **`ModelAndView`**: Combines model data and view in one return type.


- **Best Use Case**: When you need to return both model data and the view name in
one object.
- **Alternatives**: `Model` or `Map` with a view name string return type for
simplicity in modern Spring applications.
===========================================
If you have multiple JSP pages in the `/views/` folder and you configure the
following properties:

```properties
spring.mvc.view.prefix=/views/
spring.mvc.view.suffix=.jsp
```
This setup will resolve view names dynamically based on the name returned by your
controller. Spring MVC will automatically append the prefix (`/views/`) and suffix
(`.jsp`) to the view name.

---

### Example Scenario

Assume your `/views/` folder contains the following JSP pages:

```
/views/home.jsp
/views/about.jsp
/views/contact.jsp
```

1. **Controller Method Example**:

```java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class PageController {

@GetMapping("/home")
public String homePage() {
return "home"; // Resolves to /views/home.jsp
}

@GetMapping("/about")
public String aboutPage() {
return "about"; // Resolves to /views/about.jsp
}

@GetMapping("/contact")
public String contactPage() {
return "contact"; // Resolves to /views/contact.jsp
}
}
```

2. **How It Works**:
- When the `/home` endpoint is accessed, the `homePage()` method returns
`"home"`.
- Spring MVC adds the prefix (`/views/`) and suffix (`.jsp`) to form the full
path: `/views/home.jsp`.

---

### What Happens with Multiple JSP Pages?

If you have many JSP pages in the `/views/` folder, you can simply return the name
of the desired JSP page from your controller methods. The framework automatically
resolves the correct file path based on the `spring.mvc.view.prefix` and
`spring.mvc.view.suffix` properties.

---
### Dynamic Page Names

If you want to dynamically choose which JSP page to render based on some condition,
you can return the view name conditionally.

```java
@GetMapping("/page")
public String dynamicPage(@RequestParam String name) {
// Dynamically resolve the view based on the "name" parameter
return name; // Resolves to /views/{name}.jsp
}
```

For example:
- Access `/page?name=home` → Resolves to `/views/home.jsp`.
- Access `/page?name=about` → Resolves to `/views/about.jsp`.

---

### Folder Organization (Optional)

If you want to organize your JSP files into subfolders within `/views/`, you can
include the subfolder name in the returned view string.

#### Folder Structure:


```
/views/pages/home.jsp
/views/pages/about.jsp
/views/templates/contact.jsp
```

#### Controller Example:


```java
@GetMapping("/pages/home")
public String homePage() {
return "pages/home"; // Resolves to /views/pages/home.jsp
}

@GetMapping("/templates/contact")
public String contactPage() {
return "templates/contact"; // Resolves to /views/templates/contact.jsp
}
```

---

### Key Points:


1. **Automatic Resolution**:
- Spring appends the prefix and suffix to the view name returned by the
controller.

2. **Organizing Files**:
- You can group JSP files in subfolders and reference them with a path-like view
name (e.g., `subfolder/file`).

3. **Dynamic Selection**:
- Use parameters to dynamically determine which JSP page to render.

This setup makes it easy to manage and render multiple JSP pages without additional
configuration.
==========================================================

public class ReverseAnumber {


public static void main(String[] args) {
int num = Integer.parseInt(args[0]);
int rev = 0;

// while (num != 0) {
// rev = rev * 10 + num % 10;
// num = num / 10;
// }

StringBuffer sb = new StringBuffer(String.valueOf(num));

System.out.println("Reverse number is " + sb.reverse());


}
}

=================================================

import java.util.Scanner;

public class PalindromeCheck {


public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter a Number here");
int num = sc.nextInt();
int original_num = num;
int rev = 0;
while (num != 0) {
rev = rev * 10 + num % 10;
num = num / 10;

}
if (original_num == rev) {
System.out.println("Entered number is a palindrome");
} else {
System.out.println("Entered number is Not a palindrome");
}
}
}

=================================================
The `@RequestBody` annotation in Spring MVC is used to bind the HTTP request body
to a Java object. It is typically used in RESTful APIs when handling HTTP POST,
PUT, or PATCH requests, where the data is sent in the body of the request (usually
in JSON or XML format).

---

### **Key Features of `@RequestBody`:**


1. **Automatic Deserialization**:
- Converts the JSON/XML payload in the HTTP request body into a Java object
using a message converter (e.g., Jackson for JSON).
2. **Validation Support**:
- Can work with validation annotations (like `@Valid`) to ensure the correctness
of the request data.

3. **Simplifies Data Binding**:


- Eliminates the need to manually parse the request body and map the fields.

---

### **Example Usage**

#### **1. Basic Example**

**Controller:**

```java
import org.springframework.web.bind.annotation.*;

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

@PostMapping("/users")
public String createUser(@RequestBody User user) {
// Access the deserialized User object
return "User created: " + user.getName();
}
}
```

**Model Class (`User`):**

```java
public class User {
private String name;
private int age;

// Getters and setters


public String getName() {
return name;
}

public void setName(String name) {


this.name = name;
}

public int getAge() {


return age;
}

public void setAge(int age) {


this.age = age;
}
}
```

**JSON Request Payload:**

```json
{
"name": "John Doe",
"age": 25
}
```

**Output:**

```
User created: John Doe
```

---

#### **2. Using `@Valid` for Validation**

Add validation annotations to the model class and use `@Valid` in the controller to
enforce constraints.

**Updated Model Class:**

```java
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;

public class User {


@NotBlank(message = "Name is mandatory")
private String name;

@Min(value = 18, message = "Age must be at least 18")


private int age;

// Getters and setters


}
```

**Controller with Validation:**

```java
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;

@RestController
@RequestMapping("/api")
@Validated
public class UserController {

@PostMapping("/users")
public String createUser(@Valid @RequestBody User user) {
return "Validated user: " + user.getName();
}
}
```

If the request payload violates any constraints, a validation error will be


returned automatically.
**Invalid JSON Payload:**

```json
{
"name": "",
"age": 15
}
```

**Validation Error Response:**

```json
{
"timestamp": "2024-11-27T12:00:00",
"status": 400,
"errors": [
"Name is mandatory",
"Age must be at least 18"
]
}
```

---

#### **3. Handling Complex Nested Objects**

You can handle nested objects in the request body by defining them in your model
class.

**Model Class with Nested Object:**

```java
public class User {
private String name;
private Address address;

// Getters and setters

public static class Address {


private String street;
private String city;

// Getters and setters


}
}
```

**JSON Payload:**

```json
{
"name": "Jane Doe",
"address": {
"street": "123 Main St",
"city": "Springfield"
}
}
```
Spring will automatically deserialize nested objects as well.

---

### **Use Cases**

1. **Creating or Updating Resources**:


- When submitting data to create or update a resource in the system, e.g.,
adding a new user, product, or order.

2. **Complex Input**:
- When handling complex input data structures with nested objects or arrays.

3. **Validation and Error Handling**:


- Ensure the incoming data conforms to the required format and constraints.

4. **Integration with Front-End**:


- Typically used in APIs consumed by front-end applications that send JSON data
(e.g., Angular, React).

---

=============================================
In Spring MVC, **controller methods** can use different return types to handle
requests and responses. Two commonly used return types are:

1. **`ModelAndView`**
2. **`String`**

Both have distinct purposes and usage patterns. Let's break them down:

---

### **1. `ModelAndView` as Return Type**

#### **What is `ModelAndView`?**


`ModelAndView` is a Spring MVC object that encapsulates both:
- **Model**: Data to be passed to the view.
- **View**: The name of the view (e.g., JSP, Thymeleaf).

This allows you to set both the data and the view in a single object.

---

#### **When to Use `ModelAndView`?**


- When you need to:
1. Pass multiple pieces of data to the view.
2. Dynamically set the view name in the controller.

---

#### **Example**
```java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class DemoController {
@GetMapping("/greeting")
public ModelAndView greeting() {
ModelAndView mav = new ModelAndView("greeting"); // View name (e.g.,
greeting.jsp)
mav.addObject("message", "Hello, welcome to Spring MVC!"); // Data to the
view
mav.addObject("name", "John Doe"); // Additional data

return mav; // Returns the ModelAndView object


}
}
```

#### **Explanation**:
- The `greeting` view will render, and it can use the `message` and `name` values.
- The view file could be `greeting.jsp` in this case.

#### **Advantages**:
- Combines data (`Model`) and view (`View`) in one return type.
- Explicitly specifies both the view and the data.

---

### **2. `String` as Return Type**

#### **What is `String`?**


Returning a `String` from a controller method typically represents the **name of
the view** to be rendered.

---

#### **When to Use `String`?**


- When:
1. The view name is fixed.
2. You don’t need to pass complex or multiple data objects to the view.

---

#### **Example**
```java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class DemoController {

@GetMapping("/welcome")
public String welcome(Model model) {
model.addAttribute("message", "Welcome to Spring MVC!"); // Add data to the
model
return "welcome"; // View name (e.g., welcome.jsp)
}
}
```

#### **Explanation**:
- The `welcome` view will render, and it can access the `message` attribute via the
`Model`.

#### **Advantages**:
- Simpler and more concise when only the view name and a small amount of data are
needed.

---

### **Key Differences**

| **Aspect** | **`ModelAndView`** |
**`String`** |
|-----------------------|---------------------------------------------|------------
---------------------------------|
| **Purpose** | Combines view name and data. | Represents
the view name only. |
| **Flexibility** | More flexible for complex scenarios. | Simpler for
straightforward cases. |
| **Data Passing** | Data is added via `addObject()`. | Data is
passed using the `Model` object. |
| **Dynamic View Name** | Easier to set dynamically. | Requires
additional logic for dynamic names.|
| **Code Style** | Slightly verbose. | Cleaner and
concise. |

---

### **When to Choose Which?**

- Use **`ModelAndView`**:
- If you need to set the view name dynamically.
- When working with complex data models.
- If combining data and view into one return type makes sense for your use case.

- Use **`String`**:
- If the view name is static.
- When the model data is simple.
- To keep the code concise and readable.

---

### **Alternative: `void` and `ResponseEntity`**


In modern Spring applications, `ModelAndView` is less frequently used. Alternatives
include:
1. **`void`**:
- The method itself doesn’t return anything; the framework resolves the view
automatically based on the request mapping.

2. **`ResponseEntity`**:
- Used in RESTful APIs to return a response body with HTTP status codes.

---
============================================================
Securing REST APIs is essential to protect data, prevent unauthorized access, and
ensure the integrity of the system. Below are best practices and techniques to
secure REST APIs in Java-based projects, especially with frameworks like Spring
Boot:

---
## **1. Use HTTPS**

- **Why**: Encrypts data in transit, ensuring confidentiality and integrity.


- **How**:
- Obtain an SSL/TLS certificate.
- Configure HTTPS in your server (e.g., Tomcat, Netty).
- In Spring Boot, set up in `application.properties`:
```properties
server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=your-password
```

---

## **2. Implement Authentication**

Authentication ensures only valid users can access the API. Common methods:

### **a. Basic Authentication**


- Requires a username and password in the `Authorization` header.
- Use HTTPS to secure credentials.

Example with Spring Security:


```java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
```

### **b. Token-Based Authentication (e.g., JWT)**


- Clients include a **JWT token** in the `Authorization` header.
- Use a library like `jjwt` or Spring Security's JWT module.

Example:
```java
Authorization: Bearer <your-token>
```

Generate and validate JWTs:


- Add claims (user roles, permissions).
- Validate signature and expiry.

---

## **3. Use Authorization**

Authorization ensures users access only permitted resources.

- Define roles and permissions.


- Use role-based access control (RBAC).

Example in Spring Security:


```java
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/public/**").permitAll()
.and()
.httpBasic();
}
```

---

## **4. Input Validation and Sanitization**

- Prevent **SQL Injection**, **XSS**, and other attacks.


- Validate user input (e.g., lengths, formats, types).

Example:
```java
@Valid
public ResponseEntity<?> createUser(@RequestBody @Valid UserDTO user) {
// Automatically validates fields
}
```

Use libraries like Hibernate Validator for field constraints.

---

## **5. Use API Rate Limiting**

- Protect APIs from **Denial of Service (DoS)** or **brute force attacks**.


- Use tools like:
- **Bucket4j** (Java-based library for rate limiting).
- API gateways (e.g., Kong, AWS API Gateway).

Example:
```yaml
spring:
cloud:
gateway:
routes:
- id: rate_limit_route
uri: http://your-api
predicates:
- Path=/api/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter:
replenishRate: 10
burstCapacity: 20
```
---

## **6. Secure API Keys**

- If using **API keys**, ensure they are:


- **Encrypted** during storage.
- Sent via secure headers, not query strings.

Example Header:
```http
X-API-KEY: your-api-key
```

---

## **7. Protect Sensitive Endpoints**

- Limit access to sensitive endpoints like `/actuator` in Spring Boot.


- Disable or restrict actuators in `application.properties`:
```properties
management.endpoints.web.exposure.include=health,info
```

---

## **8. Enable Cross-Origin Resource Sharing (CORS) Carefully**

- Restrict allowed origins to trusted domains.


- Example configuration:
```java
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://trusted-domain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
};
}
```

---

## **9. Prevent CSRF (Cross-Site Request Forgery)**

- Use Spring Security's CSRF protection:


```java
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
```

---
## **10. Secure Data**

- **Encrypt sensitive data** before storing it in the database.


- Use tools like:
- Jasypt for encryption in Spring Boot.
- Hash passwords using bcrypt or Argon2.

---

## **11. Logging and Monitoring**

- Log all authentication attempts (both successful and failed).


- Use tools like **ELK stack**, **Splunk**, or **Spring Boot Actuator** to monitor
API activity.
- Ensure logs do not include sensitive data like passwords or tokens.

---

## **12. Use Content Security Policies**

- Set **Content Security Policies (CSP)** headers to mitigate XSS and data
injection attacks:
```java
http.headers().contentSecurityPolicy("script-src 'self'; object-src 'none';");
```

---

## **13. Regular Security Audits and Penetration Testing**

- Periodically review and test your APIs for vulnerabilities using tools like:
- OWASP ZAP
- Burp Suite

---

## **14. Use an API Gateway**

- API gateways like **Kong**, **Zuul**, or **AWS API Gateway** provide centralized
security features like:
- Authentication.
- Rate limiting.
- Logging.

---

## **Example: Secure REST API with Spring Boot**

```java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/public/**").permitAll() // Public APIs
.antMatchers("/api/private/**").authenticated() // Secure APIs
.and()
.httpBasic(); // Or JWT Authentication
}
}
```

---

By combining these practices, you can build robust, secure REST APIs. Let me know
if you'd like examples for a specific method!
==============================================
To configure JWT (JSON Web Token) security in a Spring Boot application, you need
to implement the following components:

---

## **Basic Configuration for JWT Security**

### **1. Add Required Dependencies**

In your **Maven** `pom.xml`:


```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
```

For **Gradle**:
```gradle
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
```

---

### **2. Generate and Validate JWT Tokens**

#### **a. JWT Utility Class**


This class will generate, parse, and validate JWT tokens.
```java
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;

import java.security.Key;
import java.util.Date;

import org.springframework.stereotype.Component;

@Component
public class JwtUtil {

private final String SECRET_KEY = "your-very-secure-secret-key-for-signing-


tokens";
private final long EXPIRATION_TIME = 1000 * 60 * 60; // 1 hour

private Key getSigningKey() {


return Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
}

// Generate JWT Token


public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() +
EXPIRATION_TIME))
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}

// Validate JWT Token


public boolean validateToken(String token) {
try {

Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token);
return true;
} catch (JwtException e) {
return false; // Invalid token
}
}

// Extract Username from Token


public String extractUsername(String token) {
return Jwts.parserBuilder()
.setSigningKey(getSigningKey())
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
```

---

### **3. Configure Spring Security**

#### **a. Create a Filter for JWT Validation**


This filter intercepts incoming requests, extracts and validates the JWT, and sets
the security context.
```java
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import
org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

@Autowired
private JwtUtil jwtUtil;

@Autowired
private UserDetailsService userDetailsService;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
response, FilterChain filterChain)
throws ServletException, IOException {

String authorizationHeader = request.getHeader("Authorization");

String username = null;


String jwt = null;

// Check for Bearer Token


if (authorizationHeader != null && authorizationHeader.startsWith("Bearer
")) {
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}

// Validate Token and Set Security Context


if (username != null &&
SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails =
userDetailsService.loadUserByUsername(username);

if (jwtUtil.validateToken(jwt)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(userDetails, null,
userDetails.getAuthorities());
authToken.setDetails(new
WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}

filterChain.doFilter(request, response);
}
}
```

---

#### **b. Configure Security Settings**


Enable the JWT filter and disable default form-based authentication.
```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import
org.springframework.security.config.annotation.authentication.configuration.Authent
icationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilte
r;

@Configuration
public class SecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http,
JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests()
.requestMatchers("/auth/**").permitAll() // Open endpoints (e.g.,
login)
.anyRequest().authenticated() // Secure all other endpoints
.and()
.addFilterBefore(jwtAuthenticationFilter,
UsernamePasswordAuthenticationFilter.class);

return http.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration
configuration) throws Exception {
return configuration.getAuthenticationManager();
}
}
```
---

### **4. Create Authentication Controller**

This controller handles login and generates JWT tokens for valid users.
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/auth")
public class AuthController {

@Autowired
private AuthenticationManager authenticationManager;

@Autowired
private JwtUtil jwtUtil;

@PostMapping("/login")
public String login(@RequestBody AuthRequest authRequest) {
try {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authRequest.getUsername(),
authRequest.getPassword())
);
return jwtUtil.generateToken(authentication.getName());
} catch (AuthenticationException e) {
throw new RuntimeException("Invalid username or password");
}
}
}

// Request DTO
class AuthRequest {
private String username;
private String password;

// Getters and setters


}
```

---

### **5. Protect Your Endpoints**

All endpoints, except `/auth/**`, are secured. Include the JWT token in the
`Authorization` header for authenticated requests.

#### Example Request:


```http
POST /auth/login
Content-Type: application/json
{
"username": "user",
"password": "password"
}
```

#### Example Response:


```json
{
"token": "eyJhbGciOiJIUzI1NiJ9..."
}
```

For secured endpoints:


```http
GET /api/secure-data
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
```

---

This setup ensures your API is protected with JWT-based authentication. Let me know
if you need further clarification!
=============================================

You might also like