Jackson এর Error Handling এবং Exception Management

জ্যাকসন (Jackson) - Java Technologies

446

Jackson একটি শক্তিশালী JSON প্রসেসিং লাইব্রেরি যা সাধারণত JSON ডেটা সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করার জন্য ব্যবহৃত হয়। তবে, JSON ডেটার কাঠামো বা মানে ত্রুটি থাকলে Jackson বিভিন্ন ধরনের Exceptions নিক্ষেপ করতে পারে। এই ত্রুটিগুলি সঠিকভাবে পরিচালনা করা অ্যাপ্লিকেশনের স্থায়িত্ব এবং ব্যবহারকারীর অভিজ্ঞতার জন্য গুরুত্বপূর্ণ।


1. Common Jackson Exceptions

Jackson ডেটা প্রসেসিংয়ের সময় যে প্রধান ত্রুটিগুলি নিক্ষেপ করতে পারে তা হল:

Exceptionকারণ
JsonParseExceptionJSON ফরম্যাট সঠিক না হলে।
JsonMappingExceptionJSON ডেটা এবং Java Object এর মধ্যে ম্যাপিং এর সমস্যায়।
InvalidDefinitionExceptionকাস্টম Serializer বা Deserializer সঠিকভাবে সংজ্ঞায়িত না হলে।
MismatchedInputExceptionJSON ইনপুট প্রত্যাশিত টাইপের সাথে মেলেনি।
UnrecognizedPropertyExceptionJSON-এ অপ্রত্যাশিত ফিল্ড পাওয়া গেলে।

2. Exception Handling উদাহরণ

Basic Example:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;

public class JacksonErrorHandlingExample {
    public static void main(String[] args) {
        String invalidJson = "{ \"id\": 1, \"name\": \"John\", \"email\": 12345 }";

        ObjectMapper objectMapper = new ObjectMapper();
        try {
            User user = objectMapper.readValue(invalidJson, User.class);
            System.out.println(user.getName());
        } catch (JsonProcessingException e) {
            System.err.println("Error processing JSON: " + e.getMessage());
        }
    }
}

// User ক্লাস
class User {
    private int id;
    private String name;
    private String email;

    // Getters and Setters
}

আউটপুট:

Error processing JSON: Cannot deserialize value of type `java.lang.String` from Integer value (token `JsonToken.VALUE_NUMBER_INT`)

3. Common Error Scenarios এবং সমাধান

Scenario 1: Unrecognized Properties

Jackson যদি JSON-এ অপ্রত্যাশিত ফিল্ড খুঁজে পায়, তবে এটি UnrecognizedPropertyException নিক্ষেপ করে।

সমাধান:

@JsonIgnoreProperties অ্যানোটেশন ব্যবহার করুন।

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    private int id;
    private String name;

    // Getters and Setters
}

Scenario 2: Missing Required Properties

Jackson যদি প্রয়োজনীয় প্রোপার্টি JSON-এ না পায়, তবে এটি MismatchedInputException নিক্ষেপ করে।

সমাধান:

@JsonProperty এর মাধ্যমে প্রয়োজনীয় প্রোপার্টি নিশ্চিত করুন।

import com.fasterxml.jackson.annotation.JsonProperty;

public class User {
    @JsonProperty(required = true)
    private int id;

    @JsonProperty(required = true)
    private String name;

    // Getters and Setters
}

Scenario 3: Invalid Type Conversion

Jackson যদি JSON ডেটা Java টাইপে কনভার্ট করতে ব্যর্থ হয়, তবে এটি JsonMappingException নিক্ষেপ করে।

সমাধান:

ডেটার টাইপ নিশ্চিত করতে Custom Deserializer ব্যবহার করুন।

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;

public class StringToIntegerDeserializer extends JsonDeserializer<Integer> {
    @Override
    public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String value = p.getText();
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            return null;
        }
    }
}

4. Spring Boot-এর সাথে Jackson Error Handling

Spring Boot-এ Jackson Error Handling আরও সহজ এবং কাঠামোগত। Spring Boot-এ @ControllerAdvice এবং @ExceptionHandler ব্যবহার করে Jackson এর ত্রুটিগুলি পরিচালনা করা যায়।

Global Exception Handler উদাহরণ:

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(JsonParseException.class)
    public ResponseEntity<String> handleJsonParseException(JsonParseException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                             .body("Invalid JSON format: " + e.getMessage());
    }

    @ExceptionHandler(JsonMappingException.class)
    public ResponseEntity<String> handleJsonMappingException(JsonMappingException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                             .body("JSON Mapping error: " + e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGenericException(Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                             .body("An unexpected error occurred: " + e.getMessage());
    }
}

Spring REST Controller:

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

    @PostMapping
    public ResponseEntity<String> createUser(@RequestBody User user) {
        return ResponseEntity.ok("User created successfully: " + user.getName());
    }
}

5. Custom Exception Messages

Jackson-এর ডিফল্ট ত্রুটি বার্তা পরিবর্তন করতে ProblemHandler বা কাস্টম Serializer ব্যবহার করা যেতে পারে।

Custom Deserialization Problem Handler:

import com.fasterxml.jackson.databind.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.ObjectMapper;

public class CustomProblemHandler extends DeserializationProblemHandler {
    @Override
    public Object handleUnknownProperty(DeserializationContext ctxt, JsonParser p, JsonDeserializer<?> deserializer, Object beanOrClass, String propertyName) {
        System.out.println("Unknown property: " + propertyName);
        return null; // Ignore unknown properties
    }
}

// ObjectMapper কনফিগার করা
ObjectMapper mapper = new ObjectMapper();
mapper.addHandler(new CustomProblemHandler());

6. JSON Validation এবং Exception Management

Validation Example:

import com.fasterxml.jackson.annotation.JsonProperty;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public class User {
    @NotNull(message = "ID is required")
    private Integer id;

    @Size(min = 3, message = "Name must be at least 3 characters long")
    private String name;

    // Getters and Setters
}

Spring Boot Controller:

import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

    @PostMapping
    public ResponseEntity<String> createUser(@Valid @RequestBody User user) {
        return ResponseEntity.ok("User created successfully: " + user.getName());
    }
}

Validation Exception Handling:

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class ValidationExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        for (FieldError error : ex.getBindingResult().getFieldErrors()) {
            errors.put(error.getField(), error.getDefaultMessage());
        }
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
    }
}

  1. Jackson-এর Error Handling JSON ডেটার সঠিকতা নিশ্চিত করার জন্য গুরুত্বপূর্ণ।
  2. Spring Boot-এ @ControllerAdvice এবং @ExceptionHandler ব্যবহার করে Error Management আরও সহজ।
  3. Custom Serializer এবং Problem Handlers ব্যবহার করে ত্রুটি বার্তাগুলি কাস্টমাইজ করা যায়।
  4. Validation এবং Exception Management REST API-এর স্থায়িত্ব বাড়াতে কার্যকর ভূমিকা পালন করে।
Content added By

Jackson লাইব্রেরি ব্যবহার করার সময় ডেটা সিরিয়ালাইজেশন বা ডেসিরিয়ালাইজেশনের সময় বিভিন্ন ধরনের ত্রুটি এবং এক্সেপশন দেখা দিতে পারে। এসব ত্রুটির বেশিরভাগই ডেটা ফরম্যাট, টাইপ মিসম্যাচ, বা কনফিগারেশন সমস্যার কারণে ঘটে।


Common Errors এবং তাদের কারণ

  1. JsonMappingException
    • কারণ: JSON ডেটা এবং Java অবজেক্টের মধ্যে মিসম্যাচ।
    • সমাধান: মডেল ক্লাস এবং JSON ডেটার ফিল্ড সঠিকভাবে মিলিয়ে দেখুন।
    • উদাহরণ: JSON-এ একটি অতিরিক্ত ফিল্ড আছে যা মডেল ক্লাসে অনুপস্থিত।

      {
        "name": "John",
        "age": 30,
        "address": "Unknown"
      }
      

      মডেল ক্লাস:

      public class User {
          private String name;
          private int age;
          // Address ফিল্ড অনুপস্থিত
      }
      

      সমাধান: @JsonIgnoreProperties(ignoreUnknown = true) যোগ করুন।

      @JsonIgnoreProperties(ignoreUnknown = true)
      public class User {
          private String name;
          private int age;
      }
      

  1. JsonParseException
    • কারণ: JSON ফরম্যাট সঠিক নয়।
    • সমাধান: JSON ডেটা সঠিকভাবে ফরম্যাট করা হয়েছে কিনা তা যাচাই করুন।
    • উদাহরণ: একটি JSON ফাইল যেখানে কমা অনুপস্থিত বা ব্রেস {} সঠিকভাবে বন্ধ হয়নি।

      { "name": "John", "age": 30 // কমা অনুপস্থিত
      

  1. MismatchedInputException
    • কারণ: JSON ডেটা এবং মডেল টাইপের মধ্যে অমিল।
    • সমাধান: JSON ডেটার টাইপ এবং মডেল ক্লাসের টাইপ যাচাই করুন।
    • উদাহরণ: JSON-এ একটি অ্যারে, কিন্তু মডেল একটি অবজেক্ট প্রত্যাশা করে।

      [ { "name": "John", "age": 30 } ]
      

      মডেল ক্লাস:

      public class User {
          private String name;
          private int age;
      }
      

      সমাধান: মডেল ক্লাসে লিস্ট ব্যবহার করুন।

      List<User> users = objectMapper.readValue(json, new TypeReference<List<User>>() {});
      

  1. UnrecognizedPropertyException
    • কারণ: JSON ডেটায় এমন একটি প্রপার্টি রয়েছে যা মডেল ক্লাসে নেই।
    • সমাধান: @JsonIgnoreProperties(ignoreUnknown = true) ব্যবহার করুন।

      @JsonIgnoreProperties(ignoreUnknown = true)
      public class User {
          private String name;
          private int age;
      }
      

  1. InvalidDefinitionException
    • কারণ: সিরিয়ালাইজেশন বা ডেসিরিয়ালাইজেশনের জন্য যথাযথ কনস্ট্রাক্টর বা মেথড অনুপস্থিত।
    • সমাধান: ডিফল্ট কনস্ট্রাক্টর বা @JsonCreator যোগ করুন।
    • উদাহরণ: প্রাইভেট কনস্ট্রাক্টরের কারণে Jackson ডেসিরিয়ালাইজ করতে পারছে না।

      public class User {
          private String name;
          private int age;
      
          private User() {} // প্রাইভেট কনস্ট্রাক্টর
      }
      

      সমাধান: একটি পাবলিক কনস্ট্রাক্টর যোগ করুন বা @JsonCreator ব্যবহার করুন।

      @JsonCreator
      public User(@JsonProperty("name") String name, @JsonProperty("age") int age) {
          this.name = name;
          this.age = age;
      }
      

  1. JsonProcessingException
    • কারণ: সিরিয়ালাইজেশন বা ডেসিরিয়ালাইজেশনের সময় কোন সাধারণ ত্রুটি।
    • সমাধান: Exception এর স্ট্যাকট্রেস দেখে ত্রুটির নির্দিষ্ট কারণ খুঁজুন।

  1. JsonGenerationException
    • কারণ: JSON তৈরি করার সময় সমস্যা।
    • সমাধান: সঠিক ডেটা টাইপ এবং ফরম্যাট নিশ্চিত করুন।
    • উদাহরণ: একটি সাইক্লিক রেফারেন্স।

      public class User {
          private String name;
          private User friend; // সাইক্লিক রেফারেন্স
      }
      

      সমাধান: @JsonManagedReference এবং @JsonBackReference ব্যবহার করুন।


  1. IOException
    • কারণ: ইনপুট বা আউটপুট ফাইল পড়ার বা লেখার সমস্যা।
    • সমাধান: ফাইলের পাথ এবং অনুমতি যাচাই করুন।

  1. MissingNode বা NullNode সমস্যা
    • কারণ: JSON নোড অনুপস্থিত।
    • সমাধান: JSON ডেটা যাচাই করুন বা ডিফল্ট মান প্রদান করুন।

কিছু সাধারণ সমাধান

১. @JsonIgnoreProperties

JSON ডেটায় অপ্রত্যাশিত প্রপার্টি এড়াতে।

@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    private String name;
    private int age;
}

২. ডেটা টাইপ যাচাই

JSON এবং মডেল টাইপের মিল নিশ্চিত করুন।

ObjectMapper mapper = new ObjectMapper();
List<User> users = mapper.readValue(json, new TypeReference<List<User>>() {});

৩. ডিফল্ট কনস্ট্রাক্টর

মডেল ক্লাসে ডিফল্ট কনস্ট্রাক্টর যোগ করা।

public User() {
    // ডিফল্ট কনস্ট্রাক্টর
}

৪. @JsonInclude

শর্তসাপেক্ষে ফিল্ড অন্তর্ভুক্ত করতে।

@JsonInclude(JsonInclude.Include.NON_NULL)
private String address;

৫. @JsonProperty

ফিল্ডের JSON নাম কাস্টমাইজ করতে।

@JsonProperty("user_name")
private String name;

Jackson ব্যবহার করার সময় সাধারণ সমস্যাগুলো এড়াতে:

  1. JSON ডেটার ফরম্যাট এবং টাইপ যাচাই করুন।
  2. মডেল ক্লাসে যথাযথ অ্যানোটেশন যোগ করুন।
  3. সঠিক কনফিগারেশন এবং ObjectMapper ব্যবহার নিশ্চিত করুন।
  4. ত্রুটি হলে স্ট্যাকট্রেস বিশ্লেষণ করে সঠিক সমাধান খুঁজুন।

এই পদ্ধতিগুলি ব্যবহার করে Jackson সম্পর্কিত বেশিরভাগ ত্রুটি সহজেই সমাধান করা যায়।

Content added By

Spring Framework এবং Jackson একসঙ্গে JSON ডেটা হ্যান্ডল করতে এবং API তে একক ফরম্যাটে এক্সসেপশন ম্যানেজ করতে ব্যবহার করা হয়। Spring Framework এ @RestControllerAdvice এবং @ExceptionHandler ব্যবহার করে কাস্টম এক্সসেপশন তৈরি এবং হ্যান্ডল করা যায়।


Custom Exception তৈরি

১. একটি Custom Exception ক্লাস তৈরি করুন

public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String message) {
        super(message);
    }
}

Custom Exception Handling

২. @RestControllerAdvice ব্যবহার করে Exception Handling

Spring Framework এ @RestControllerAdvice গ্লোবালভাবে এক্সসেপশন হ্যান্ডল করার জন্য ব্যবহৃত হয়।

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<Map<String, String>> handleUserNotFoundException(UserNotFoundException ex) {
        Map<String, String> errorResponse = new HashMap<>();
        errorResponse.put("error", "User Not Found");
        errorResponse.put("message", ex.getMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Map<String, String>> handleGenericException(Exception ex) {
        Map<String, String> errorResponse = new HashMap<>();
        errorResponse.put("error", "Internal Server Error");
        errorResponse.put("message", ex.getMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

Controller-এ Exception Trigger করা

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/users/{id}")
    public String getUser(@PathVariable String id) {
        if ("123".equals(id)) {
            return "User found!";
        } else {
            throw new UserNotFoundException("User with ID " + id + " not found.");
        }
    }
}

API Behavior

Valid Request:

GET Request:

GET /users/123

Response:

User found!

Invalid Request:

GET Request:

GET /users/456

Response:

{
  "error": "User Not Found",
  "message": "User with ID 456 not found."
}

Custom Exception Serialization

Jackson ব্যবহার করে কাস্টম এক্সসেপশনকে JSON ফরম্যাটে কাস্টমাইজ করতে @JsonSerialize ব্যবহার করা যায়।

Custom Exception Serialization

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@JsonSerialize(using = CustomExceptionSerializer.class)
public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String message) {
        super(message);
    }
}

Custom Serializer তৈরি

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;

public class CustomExceptionSerializer extends StdSerializer<UserNotFoundException> {

    public CustomExceptionSerializer() {
        super(UserNotFoundException.class);
    }

    @Override
    public void serialize(UserNotFoundException exception, JsonGenerator gen, SerializerProvider provider)
            throws IOException {
        gen.writeStartObject();
        gen.writeStringField("type", "UserNotFoundException");
        gen.writeStringField("message", exception.getMessage());
        gen.writeEndObject();
    }
}

Response with Custom Serialization

GET Request (Invalid):

GET /users/456

Response:

{
  "type": "UserNotFoundException",
  "message": "User with ID 456 not found."
}

Custom Exception with More Details

Exception Class:

public class ApiError {
    private String error;
    private String message;
    private int statusCode;

    // Constructor, Getters and Setters
    public ApiError(String error, String message, int statusCode) {
        this.error = error;
        this.message = message;
        this.statusCode = statusCode;
    }
}

Enhanced Exception Handler:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ApiError> handleUserNotFoundException(UserNotFoundException ex) {
        ApiError error = new ApiError("User Not Found", ex.getMessage(), HttpStatus.NOT_FOUND.value());
        return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiError> handleGenericException(Exception ex) {
        ApiError error = new ApiError("Internal Server Error", ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value());
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

API Response Example

GET Request (Invalid):

GET /users/456

Response:

{
  "error": "User Not Found",
  "message": "User with ID 456 not found.",
  "statusCode": 404
}

  1. Spring Framework এবং Jackson একসঙ্গে ব্যবহার করে Exception Management সহজে কাস্টমাইজ করা যায়।
  2. @RestControllerAdvice এবং @ExceptionHandler Exception হ্যান্ডলিংয়ের জন্য একটি গ্লোবাল মেকানিজম প্রদান করে।
  3. Custom Serializer ব্যবহার করে Exception এর JSON ফরম্যাট সম্পূর্ণ নিয়ন্ত্রণ করা যায়।
  4. REST API ডেভেলপমেন্টে ব্যবহারকারীর জন্য একটি হিউম্যান-রিডেবল এবং কনসিস্টেন্ট এক্সসেপশন ফরম্যাট নিশ্চিত করা যায়।
Content added By

Jackson-এ Invalid JSON Data এবং Missing Fields হ্যান্ডল করার জন্য কাস্টম কনফিগারেশন এবং Exception Management ব্যবহার করা যায়। JSON ডেসিরিয়ালাইজেশনের সময় ডেটা অনুপস্থিত বা ভুল হলে ত্রুটি নির্ধারণ এবং তা হ্যান্ডল করা একটি গুরুত্বপূর্ণ দিক।


Invalid JSON Data হ্যান্ডল করা

Common Errors:

  1. JSON সিনট্যাক্স ভুল।
  2. ডেটার টাইপ ভুল (যেমন, String এর স্থানে Integer)।
  3. অপ্রত্যাশিত বা অজানা ফিল্ড।

Default Behavior:

  • Jackson ডিফল্টভাবে Invalid JSON-এর জন্য JsonParseException এবং JsonMappingException থ্রো করে।

1. Invalid JSON Data হ্যান্ডল করার কনফিগারেশন

কোড উদাহরণ:
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) {
        String invalidJson = """
        {
            "id": 101,
            "name": "John Doe",
            "age": "not_a_number"
        }
        """;

        ObjectMapper objectMapper = new ObjectMapper();

        try {
            User user = objectMapper.readValue(invalidJson, User.class);
        } catch (JsonParseException e) {
            System.out.println("JSON Parsing Error: " + e.getMessage());
        } catch (JsonMappingException e) {
            System.out.println("JSON Mapping Error: " + e.getMessage());
        } catch (Exception e) {
            System.out.println("General Error: " + e.getMessage());
        }
    }
}

class User {
    public int id;
    public String name;
    public int age; // Will cause a mapping error for "not_a_number"
}
আউটপুট:
JSON Mapping Error: Cannot deserialize value of type `int` from String "not_a_number": not a valid Integer value

2. Unknown Fields হ্যান্ডল করা

ডিফল্টভাবে, অজানা (unknown) ফিল্ড থাকলে UnrecognizedPropertyException থ্রো হয়। এটি নিষ্ক্রিয় করার জন্য DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ব্যবহার করা হয়।

কোড উদাহরণ:
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws Exception {
        String jsonWithExtraField = """
        {
            "id": 101,
            "name": "John Doe",
            "email": "john.doe@example.com" // Unknown field
        }
        """;

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        User user = objectMapper.readValue(jsonWithExtraField, User.class);
        System.out.println("User Name: " + user.name);
    }
}

class User {
    public int id;
    public String name;
}
আউটপুট:
User Name: John Doe

Missing Fields হ্যান্ডল করা

Default Behavior:

Jackson ডিফল্টভাবে Missing Fields এর জন্য কোনো ত্রুটি দেয় না। ডেসিরিয়ালাইজেশনের সময় অনুপস্থিত ফিল্ডগুলো null বা প্রাথমিক মান (default value) সেট করে।


1. Required Fields চিহ্নিত করা

Custom Validation with Annotations:

Java Bean Validation (Hibernate Validator) ব্যবহার করে Required Fields চিহ্নিত করা যায়।

import javax.validation.constraints.NotNull;

class User {
    @NotNull(message = "ID cannot be null")
    public Integer id;

    @NotNull(message = "Name cannot be null")
    public String name;
}
Spring Boot Integration:
@RestController
@RequestMapping("/api")
public class UserController {

    @PostMapping("/user")
    public ResponseEntity<String> createUser(@Valid @RequestBody User user) {
        return ResponseEntity.ok("User created successfully");
    }
}
Global Exception Handler:
@ControllerAdvice
public class ValidationExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        String errors = ex.getBindingResult().getFieldErrors().stream()
                          .map(error -> error.getField() + ": " + error.getDefaultMessage())
                          .collect(Collectors.joining(", "));
        return ResponseEntity.badRequest().body("Validation Errors: " + errors);
    }
}

2. Default Values সেট করা

Jackson @JsonProperty এনোটেশন দিয়ে Default Value সেট করতে পারে।

import com.fasterxml.jackson.annotation.JsonProperty;

class User {
    @JsonProperty(defaultValue = "0")
    public int id;

    @JsonProperty(defaultValue = "Unknown")
    public String name;

    public int age;
}

Custom Error Handling for Missing and Invalid Fields

Jackson মডিউলে @JsonSetter এবং @JsonIgnoreProperties ব্যবহার করে কাস্টম হ্যান্ডলিং করা যায়।

1. @JsonSetter এর ব্যবহার

import com.fasterxml.jackson.annotation.JsonSetter;

class User {
    public int id;

    private String name;

    @JsonSetter
    public void setName(String name) {
        if (name == null || name.isEmpty()) {
            this.name = "Default Name";
        } else {
            this.name = name;
        }
    }

    public String getName() {
        return name;
    }
}

2. @JsonIgnoreProperties এর ব্যবহার

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
class User {
    public int id;
    public String name;
}

Exception Handling for Invalid JSON

Custom Exception Handler Class:

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(JsonMappingException.class)
    public ResponseEntity<String> handleJsonMappingException(JsonMappingException ex) {
        return new ResponseEntity<>("Invalid JSON Mapping: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(JsonParseException.class)
    public ResponseEntity<String> handleJsonParseException(JsonParseException ex) {
        return new ResponseEntity<>("Invalid JSON Syntax: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGeneralException(Exception ex) {
        return new ResponseEntity<>("An error occurred: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

Key Takeaways

  1. Invalid JSON Data:
    • JsonParseException: JSON সিনট্যাক্স ভুল হলে।
    • JsonMappingException: টাইপ বা কাঠামো না মিললে।
  2. Missing Fields:
    • Default value সেট করার জন্য @JsonProperty(defaultValue) ব্যবহার।
    • Validation দিয়ে প্রয়োজনীয় ফিল্ড নিশ্চিত।
  3. Custom Handling:
    • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ব্যবহার করে অজানা ফিল্ড ইগনোর করা।
    • Spring Boot-এ Global Exception Handling সহজ।
  4. Global ObjectMapper Config:
    • Missing বা Invalid Fields হ্যান্ডল করার জন্য একটি Global ObjectMapper তৈরি করুন এবং সেটিকে কনফিগার করুন।

এই পদ্ধতিগুলো ব্যবহার করে আপনি Invalid JSON এবং Missing Fields সহজেই হ্যান্ডল করতে পারবেন।

Content added By

Jackson একটি শক্তিশালী JSON প্রসেসিং লাইব্রেরি হলেও, JSON serialization এবং deserialization-এর সময় বিভিন্ন ধরণের Exceptions ঘটতে পারে। সঠিক Exception Logging এবং Debugging Techniques ব্যবহার করে এসব সমস্যা দ্রুত সমাধান করা সম্ভব।


Common Jackson Exceptions এবং তাদের কারণ

  1. JsonParseException:
    • অবৈধ বা ভুল ফরম্যাটের JSON প্রসেস করার সময় ঘটে।
    • যেমন: {key: "value"} (মিসিং কোটেশনের কারণে)।
  2. JsonMappingException:
    • JSON থেকে Java Object বা Java Object থেকে JSON এ ম্যাপ করার সময় ত্রুটি।
    • যেমন: ফিল্ড মিসিং, টাইপ মিসম্যাচ।
  3. UnrecognizedPropertyException:
    • JSON-এ এমন ফিল্ড পাওয়া গেলে যা Java Object-এ নেই।
  4. InvalidDefinitionException:
    • কাস্টম Serializer/Deserializer সংজ্ঞায়িত করতে ভুল হলে।

Exception Logging এবং Debugging টেকনিক

1. Log Messages ব্যবহার করে Exception Tracking

Jackson Exception হ্যান্ডল করার সময় সঠিক লগ বার্তা সংরক্ষণ গুরুত্বপূর্ণ। Spring Boot বা Java এর Logger ব্যবহার করুন।

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JacksonLoggingExample {
    private static final Logger logger = LoggerFactory.getLogger(JacksonLoggingExample.class);

    public static void main(String[] args) {
        String invalidJson = "{ \"name\": \"John\", \"age\": \"invalid_number\" }";

        try {
            ObjectMapper mapper = new ObjectMapper();
            User user = mapper.readValue(invalidJson, User.class);
        } catch (JsonMappingException e) {
            logger.error("JSON Mapping Exception: ", e);
        } catch (JsonParseException e) {
            logger.error("JSON Parse Exception: ", e);
        } catch (Exception e) {
            logger.error("Unexpected Exception: ", e);
        }
    }
}

2. Custom Exception Messages

Custom Exception তৈরি করে আরো পরিষ্কার এবং context-specific বার্তা প্রদর্শন করা যায়।

public class CustomJsonException extends RuntimeException {
    public CustomJsonException(String message, Throwable cause) {
        super(message, cause);
    }
}
public class JacksonCustomExceptionExample {
    public static void main(String[] args) {
        String invalidJson = "{ \"name\": \"John\", \"age\": \"invalid_number\" }";

        try {
            ObjectMapper mapper = new ObjectMapper();
            User user = mapper.readValue(invalidJson, User.class);
        } catch (JsonMappingException e) {
            throw new CustomJsonException("Error mapping JSON to User object", e);
        } catch (JsonParseException e) {
            throw new CustomJsonException("Error parsing JSON input", e);
        }
    }
}

3. Enable Jackson Debugging Logs

Jackson এর ডিবাগ লগ সক্ষম করে এর অভ্যন্তরীণ কার্যপ্রণালী দেখতে পারেন।

Logback Configuration (Spring Boot Example):

<configuration>
    <logger name="com.fasterxml.jackson" level="DEBUG" />
</configuration>

আউটপুট:

DEBUG com.fasterxml.jackson.databind.deser.BeanDeserializerFactory - Deserializing property: "name"
DEBUG com.fasterxml.jackson.databind.deser.BeanDeserializerFactory - Deserialization failed for field: "age"

4. Unrecognized Properties হ্যান্ডল করা

JSON-এ অতিরিক্ত ফিল্ড পাওয়া গেলে UnrecognizedPropertyException ঘটে। এটি প্রতিরোধ করতে @JsonIgnoreProperties ব্যবহার করুন।

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    private String name;
    private int age;

    // Getters and Setters
}

বা Globally Configure করুন:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

5. Validate JSON Input

Jackson ব্যবহার করার আগে JSON-এর গঠন বৈধ কিনা তা যাচাই করা। এটি JsonNode এবং Tree Model ব্যবহার করে করা যায়।

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonValidationExample {
    public static void main(String[] args) {
        String invalidJson = "{ \"name\": \"John\", \"age\": \"invalid_number\" }";

        try {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode node = mapper.readTree(invalidJson);

            if (!node.has("name") || !node.has("age")) {
                throw new IllegalArgumentException("Required fields are missing");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

6. Use Custom Deserializer for Better Debugging

কাস্টম Deserializer তৈরি করে আরো স্পষ্ট ডিবাগ বার্তা পাওয়া যায়।

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import java.io.IOException;

public class User {
    private String name;

    @JsonDeserialize(using = AgeDeserializer.class)
    private int age;

    // Getters and Setters
}

class AgeDeserializer extends JsonDeserializer<Integer> {
    @Override
    public Integer deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
        try {
            return Integer.parseInt(parser.getText());
        } catch (NumberFormatException e) {
            throw new IOException("Age must be a valid integer, but found: " + parser.getText());
        }
    }
}

7. Test with Invalid JSON Cases

API ডেভেলপমেন্টের সময় কিছু সাধারণ ত্রুটি পরীক্ষা করুন:

  1. Missing Fields: প্রয়োজনীয় ফিল্ড বাদ।
  2. Invalid Types: যেমন স্ট্রিং-এর পরিবর্তে সংখ্যা।
  3. Extra Fields: JSON-এ অতিরিক্ত ফিল্ড।
@Test
public void testInvalidJson() {
    String invalidJson = "{ \"name\": \"John\", \"age\": \"invalid_number\" }";

    Assertions.assertThrows(CustomJsonException.class, () -> {
        ObjectMapper mapper = new ObjectMapper();
        mapper.readValue(invalidJson, User.class);
    });
}

8. Use Global Exception Handler in Spring Boot

Spring Boot-এ @ControllerAdvice ব্যবহার করে Jackson Exception গ্লোবালি হ্যান্ডল করুন।

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(JsonMappingException.class)
    public ResponseEntity<String> handleJsonMappingException(JsonMappingException e) {
        return new ResponseEntity<>("JSON Mapping Error: " + e.getMessage(), HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(JsonParseException.class)
    public ResponseEntity<String> handleJsonParseException(JsonParseException e) {
        return new ResponseEntity<>("JSON Parse Error: " + e.getMessage(), HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGenericException(Exception e) {
        return new ResponseEntity<>("Unexpected Error: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

আউটপুট:

{
  "error": "JSON Mapping Error: Cannot deserialize value of type `int` from String \"invalid_number\""
}

Jackson Exception Logging এবং Debugging-এর জন্য:

  1. Logger ব্যবহার করুন: Exception Stack Trace এবং Contextual Message।
  2. Custom Exception তৈরি করুন: বিস্তারিত বার্তা এবং কারণ প্রদর্শনের জন্য।
  3. Debugging Logs সক্ষম করুন: Jackson এর অভ্যন্তরীণ কার্যপ্রণালী বুঝতে।
  4. Validation নিশ্চিত করুন: JSON ডেটা প্রসেস করার আগে validate করুন।
  5. Global Exception Handler: Spring Boot-এ Exception সঠিকভাবে হ্যান্ডল করুন।

এই পদ্ধতিগুলো ব্যবহার করে আপনি API-এর কার্যকারিতা এবং ত্রুটি সমাধান প্রক্রিয়া আরো দক্ষতার সাথে পরিচালনা করতে পারবেন।

Content added By
Promotion

Are you sure to start over?

Loading...