Jackson ব্যবহার করে Complex Object-এর serialization, deserialization, validation এবং Unit Testing অত্যন্ত গুরুত্বপূর্ণ, বিশেষ করে RESTful API ডেভেলপমেন্টে। সঠিক টেস্টিং এবং ভ্যালিডেশন নিশ্চিত করলে ডেটার সঠিকতা এবং অ্যাপ্লিকেশনের নির্ভরযোগ্যতা বজায় থাকে।
Unit Testing এবং Validation এর ধাপসমূহ
- Setup for Unit Testing:
- JUnit বা TestNG টেস্ট ফ্রেমওয়ার্ক ব্যবহার করুন।
- Jackson-এর ObjectMapper ব্যবহার করে serialization/deserialization টেস্ট করুন।
- Data Validation:
- Java Bean Validation (JSR 380) এর মাধ্যমে ডেটা যাচাই করুন।
- কাস্টম validation এবং exception handling অন্তর্ভুক্ত করুন।
- Testing Complex Objects:
- Nested objects এবং collections এর জন্য টেস্ট কেস তৈরি করুন।
- JSON schema validation অন্তর্ভুক্ত করুন।
1. Maven Dependencies
JUnit এবং Jackson-এর জন্য নিম্নলিখিত ডিপেনডেন্সি যুক্ত করুন:
<dependencies>
<!-- JUnit -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.0.Final</version>
</dependency>
</dependencies>
2. Complex Object Model তৈরি করুন
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.util.List;
public class Order {
@NotNull(message = "Order ID cannot be null")
private String orderId;
@Valid
@NotNull(message = "Customer cannot be null")
private Customer customer;
@Valid
@NotNull(message = "Products cannot be null")
private List<Product> products;
// Getters and Setters
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public Customer getCustomer() { return customer; }
public void setCustomer(Customer customer) { this.customer = customer; }
public List<Product> getProducts() { return products; }
public void setProducts(List<Product> products) { this.products = products; }
}
class Customer {
@NotNull(message = "Customer Name cannot be null")
@Size(min = 2, max = 50, message = "Customer Name must be between 2 and 50 characters")
private String name;
@NotNull(message = "Email cannot be null")
private String email;
// Getters and Setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
class Product {
@NotNull(message = "Product Name cannot be null")
private String name;
@NotNull(message = "Price cannot be null")
private Double price;
// Getters and Setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
}
3. Unit Test Cases for Serialization and Deserialization
Serialization Test:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertEquals;
class SerializationTest {
@Test
void testSerialization() throws Exception {
ObjectMapper mapper = new ObjectMapper();
Product product1 = new Product();
product1.setName("Laptop");
product1.setPrice(1200.50);
Product product2 = new Product();
product2.setName("Mouse");
product2.setPrice(25.75);
Customer customer = new Customer();
customer.setName("Alice");
customer.setEmail("alice@example.com");
Order order = new Order();
order.setOrderId("ORD123");
order.setCustomer(customer);
order.setProducts(Arrays.asList(product1, product2));
String json = mapper.writeValueAsString(order);
System.out.println("Serialized JSON: " + json);
// Assert JSON contains key fields
assertEquals(true, json.contains("ORD123"));
assertEquals(true, json.contains("Laptop"));
assertEquals(true, json.contains("Alice"));
}
}
Deserialization Test:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
class DeserializationTest {
@Test
void testDeserialization() throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = """
{
"orderId": "ORD123",
"customer": {
"name": "Alice",
"email": "alice@example.com"
},
"products": [
{
"name": "Laptop",
"price": 1200.50
},
{
"name": "Mouse",
"price": 25.75
}
]
}
""";
Order order = mapper.readValue(json, Order.class);
// Assertions
assertNotNull(order);
assertNotNull(order.getCustomer());
assertEquals(2, order.getProducts().size());
}
}
4. Validation Test Cases
Validation Logic:
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertFalse;
class ValidationTest {
private final Validator validator;
public ValidationTest() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
this.validator = factory.getValidator();
}
@Test
void testValidationErrors() {
Product product = new Product();
product.setName("Laptop"); // Missing price
Customer customer = new Customer();
customer.setName("Alice");
customer.setEmail(null); // Invalid email
Order order = new Order();
order.setOrderId("ORD123");
order.setCustomer(customer);
order.setProducts(Arrays.asList(product));
Set<jakarta.validation.ConstraintViolation<Order>> violations = validator.validate(order);
// Assert that validation errors exist
assertFalse(violations.isEmpty());
violations.forEach(violation -> System.out.println(violation.getMessage()));
}
}
আউটপুট:
Price cannot be null
Email cannot be null
5. Exception Handling During Testing
Example of Handling Missing Fields:
@Test
void testMissingFields() {
ObjectMapper mapper = new ObjectMapper();
String invalidJson = """
{
"orderId": "ORD123",
"products": []
}
""";
Exception exception = null;
try {
mapper.readValue(invalidJson, Order.class);
} catch (Exception e) {
exception = e;
}
assertNotNull(exception);
System.out.println("Exception: " + exception.getMessage());
}
6. Schema Validation for Complex Objects
JSON Schema Validation:
@Test
void testJsonSchemaValidation() throws Exception {
String schema = """
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"orderId": {"type": "string"},
"customer": {
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string"}
},
"required": ["name", "email"]
},
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "number"}
},
"required": ["name", "price"]
}
}
},
"required": ["orderId", "customer", "products"]
}
""";
String jsonData = """
{
"orderId": "ORD123",
"customer": {
"name": "Alice",
"email": "alice@example.com"
},
"products": [
{"name": "Laptop", "price": 1200.50}
]
}
""";
ObjectMapper mapper = new ObjectMapper();
JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
JsonSchema jsonSchema = factory.getJsonSchema(mapper.readTree(schema));
JsonNode data = mapper.readTree(jsonData);
ProcessingReport report = jsonSchema.validate(data);
assertTrue(report.isSuccess(), "Validation failed: " + report);
}
- Serialization/Deserialization Testing: Complex objects-এর জন্য নিশ্চিত
করুন JSON সঠিকভাবে প্রক্রিয়াজাত হচ্ছে।
2. Validation Testing: Nested objects এবং collections এর জন্য Bean Validation ব্যবহার করুন।
3. Error Handling: Exception Logging এবং Detailed Messages দিয়ে debugging সহজ করুন।
4. Schema Validation: JSON Schema দিয়ে JSON গঠন যাচাই করুন।
এই ধাপগুলো অনুসরণ করে আপনার Complex Object-এর জন্য নির্ভরযোগ্য এবং কার্যকর Unit Testing এবং Validation নিশ্চিত করা সম্ভব।
Read more