MapStruct হল একটি কোড জেনারেশন টুল যা Java Beans এর মধ্যে ডেটা ট্রান্সফরমেশন সহজ এবং দ্রুত করতে ব্যবহৃত হয়। Mapping Methods তৈরি করা MapStruct এর একটি গুরুত্বপূর্ণ অংশ, যা ডেটা এক ধরনের অবজেক্ট থেকে অন্য ধরনের অবজেক্টে স্থানান্তর করতে ব্যবহৃত হয়। Mapping Methods হল সেই পদ্ধতিগুলি যা Mapper Interface এর মধ্যে ডিফাইন করা হয় এবং MapStruct সেই পদ্ধতিগুলির জন্য কোড জেনারেট করে।
এই টিউটোরিয়ালে, আমরা দেখব কিভাবে Mapping Methods তৈরি করা যায় এবং MapStruct এর মাধ্যমে ডেটা ট্রান্সফরমেশন করা যায়।
১. MapStruct Mapping Methods কী?
Mapping Methods হল সেই মেথড যেগুলির মাধ্যমে MapStruct বিভিন্ন Java Beans এর মধ্যে ডেটা ম্যাপিং করে। MapStruct সাধারণত একটি Mapper Interface এর মাধ্যমে এই মেথডগুলি ডিফাইন করে। MapStruct পরে কম্পাইল টাইমে এই মেথডগুলির জন্য কোড জেনারেট করে, যা ডেটা ট্রান্সফরমেশন সম্পাদন করে।
২. Mapping Methods তৈরি করার পদ্ধতি
২.১ Simple Mapping Method
MapStruct দিয়ে সাধারণভাবে একটি মেটাডেটা ম্যাপিং মেথড তৈরি করতে হলে প্রথমে একটি Mapper Interface তৈরি করতে হয়। নিচে একটি সাধারণ উদাহরণ দেওয়া হলো যেখানে Person ক্লাস থেকে PersonDTO ক্লাসে ডেটা ম্যাপ করা হচ্ছে।
Person.java ক্লাস:
public class Person { private String firstName; private String lastName; // getters and setters }PersonDTO.java ক্লাস:
public class PersonDTO { private String firstName; private String lastName; // getters and setters }Mapper Interface:
import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper public interface PersonMapper { PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class); PersonDTO personToPersonDTO(Person person); }
এখানে, PersonMapper একটি Mapper Interface যা Person অবজেক্ট থেকে PersonDTO অবজেক্টে ডেটা ম্যাপ করতে personToPersonDTO মেথড তৈরি করেছে। MapStruct কম্পাইল টাইমে এই মেথডটির জন্য কোড জেনারেট করবে।
২.২ Complex Mapping Method
একটি ডিপার ডেটা ম্যাপিং করতে, যেমন nested objects অথবা collections ম্যাপ করতে, MapStruct আরও উন্নত কনফিগারেশন এবং কাস্টম ম্যাপিং সমর্থন করে।
Employee.java ক্লাস:
public class Employee { private String name; private Address address; // getters and setters }Address.java ক্লাস:
public class Address { private String street; private String city; // getters and setters }EmployeeDTO.java ক্লাস:
public class EmployeeDTO { private String name; private String street; private String city; // getters and setters }Mapper Interface:
import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper public interface EmployeeMapper { EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class); EmployeeDTO employeeToEmployeeDTO(Employee employee); // Mapping nested Address object default String mapStreet(Address address) { return address.getStreet(); } default String mapCity(Address address) { return address.getCity(); } }
এখানে, EmployeeMapper ইন্টারফেসের মাধ্যমে Employee এবং EmployeeDTO এর মধ্যে ডেটা ট্রান্সফরমেশন সম্পন্ন করা হয়েছে। mapStreet এবং mapCity মেথড ব্যবহার করা হয়েছে, যা Address ক্লাসের nested object থেকে EmployeeDTO তে street এবং city ম্যাপ করে।
২.৩ Mapping Method with Collection
MapStruct Collections এর মধ্যে ডেটা ম্যাপিং করার জন্যও সমর্থন দেয়। এটি List, Set, Map ইত্যাদি থেকে DTO তে ডেটা ম্যাপ করতে ব্যবহার করা যেতে পারে।
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);
List<EmployeeDTO> employeesToEmployeeDTOs(List<Employee> employees);
}
এখানে, employeesToEmployeeDTOs মেথডটি একটি List থেকে List তে ডেটা ম্যাপিং করে।
৩. Custom Mapping Logic (কাস্টম ম্যাপিং লজিক)
MapStruct আপনাকে কাস্টম ম্যাপিং যুক্ত করার সুবিধা প্রদান করে, যেখানে আপনি নিজে লজিক ডিফাইন করতে পারেন। উদাহরণস্বরূপ, যদি আপনার Person ক্লাসের age ফিল্ডের ভিত্তিতে একটি নতুন ফিল্ড ম্যাপ করতে চান, তবে MapStruct আপনাকে এটি করার অনুমতি দেয়।
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
@Mapping(source = "birthDate", target = "age", dateFormat = "yyyy-MM-dd")
PersonDTO personToPersonDTO(Person person);
default Integer mapAge(Date birthDate) {
return Period.between(birthDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), LocalDate.now()).getYears();
}
}
এখানে, mapAge মেথডটি birthDate থেকে age তৈরি করছে, যেখানে কাস্টম লজিক প্রয়োগ করা হয়েছে।
৪. MapStruct Mapping Method Parameters
MapStruct এর মেথড প্যারামিটারও কাস্টমাইজ করা যায়। যেমন, আপনি যখন ম্যাপিং করেন, তখন প্যারামিটারগুলির জন্য নির্দিষ্ট ম্যানিপুলেশন করতে পারেন।
@Mapper
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);
@Mapping(target = "name", expression = "java(employee.getFirstName() + \" \" + employee.getLastName())")
EmployeeDTO employeeToEmployeeDTO(Employee employee);
}
এখানে, expression ব্যবহার করে employee অবজেক্টের firstName এবং lastName থেকে name তৈরি করা হচ্ছে।
৫. Mapping Method Error Handling
MapStruct এর মাধ্যমে ম্যাপিংয়ে কোন সমস্যা হলে, এটি null check বা default values যোগ করার মাধ্যমে ভুল হ্যান্ডেল করতে সহায়তা করে। আপনি defaultValue ব্যবহার করতে পারেন বা nullValueMappingStrategy কনফিগার করে এই ধরনের ত্রুটি প্রতিরোধ করতে পারেন।
@Mapper
public interface EmployeeMapper {
@Mapping(target = "name", defaultValue = "Unknown")
EmployeeDTO employeeToEmployeeDTO(Employee employee);
}
এখানে, যদি name ফিল্ডটি null থাকে, তবে "Unknown" ভ্যালু সেট করা হবে।
সারাংশ
MapStruct Mapping Methods হল MapStruct এর একটি শক্তিশালী ফিচার যা Java Beans এর মধ্যে ডেটা ট্রান্সফরমেশন (যেমন DTO, Entity) করতে ব্যবহৃত হয়। Mapping Methods ব্যবহার করে আপনি সহজভাবে ডেটা ম্যাপিং করতে পারেন এবং জটিল ম্যাপিং লজিক, কাস্টম ম্যাপিং, এবং nested objects এর মধ্যে ডেটা ট্রান্সফরমেশন করতে পারবেন। MapStruct compile-time কোড জেনারেশন করে, যা আপনাকে দ্রুত পারফরম্যান্স এবং টাইপ সেফটি প্রদান করে।
MapStruct একটি কোড জেনারেশন টুল যা Java Beans এর মধ্যে ডেটা ম্যাপিং অটোমেটিক্যালি সম্পন্ন করে। MapStruct সাধারণত DTO (Data Transfer Object) এবং Entity ক্লাসের মধ্যে ডেটা ম্যাপিং করার জন্য ব্যবহৃত হয়। এর মাধ্যমে, আপনি সোজাসুজি কোড লিখে একটি অবজেক্ট থেকে অন্য অবজেক্টে ডেটা ট্রান্সফার করতে পারেন, যা সাধারণত ম্যানুয়ালি করা হয়।
Mapping Methods হল MapStruct এর গুরুত্বপূর্ণ অংশ, যেখানে আপনি Java Beans এর মধ্যে ডেটা ম্যাপিং করার জন্য বিশেষ মেথড তৈরি করেন। এই মেথডগুলো MapStruct অটোমেটিক্যালি কোড জেনারেট করার সময় ব্যবহার করে এবং ডেটা ট্রান্সফরমেশন সম্পন্ন করে।
এই টিউটোরিয়ালে আমরা Mapping Methods কী এবং MapStruct এর মাধ্যমে কীভাবে কাজ করে তা বিস্তারিতভাবে আলোচনা করব।
১. Mapping Methods কী?
Mapping Methods হল সেই মেথডগুলো যা MapStruct দ্বারা কোড জেনারেশন করতে ব্যবহৃত হয়, যাতে একটি অবজেক্টের ডেটা অন্য অবজেক্টে স্থানান্তরিত হয়। এগুলি Mapper Interface এর অংশ হিসেবে থাকে এবং MapStruct এর মাধ্যমে এই মেথডগুলোর জন্য কোড অটোমেটিক্যালি জেনারেট হয়।
এই মেথডগুলির মাধ্যমে আপনি DTO থেকে Entity বা একটি অবজেক্ট থেকে অন্য অবজেক্টে ডেটা ম্যানিপুলেশন করতে পারেন।
২. Mapping Methods কিভাবে কাজ করে?
MapStruct Mapper Interface এর মাধ্যমে ডেটা ম্যাপিং পরিচালনা করে। একটি Mapper Interface ডিফাইন করে, যা source object (যেমন Person ক্লাস) এবং target object (যেমন PersonDTO ক্লাস) এর মধ্যে ডেটা ম্যাপিং সম্পর্কিত নির্দেশনা দেয়।
২.১ Mapping Method উদাহরণ
ধরা যাক, আপনার দুটি ক্লাস আছে:
- Person (Entity Class)
- PersonDTO (DTO Class)
আমরা Person অবজেক্ট থেকে PersonDTO অবজেক্টে ডেটা ম্যাপ করতে চাই।
Person.java (Entity Class):
public class Person {
private String firstName;
private String lastName;
// getters and setters
}
PersonDTO.java (DTO Class):
public class PersonDTO {
private String firstName;
private String lastName;
// getters and setters
}
এখন, আপনি একটি Mapper Interface তৈরি করবেন যা এই দুই ক্লাসের মধ্যে ডেটা ম্যাপ করবে:
PersonMapper.java (Mapper Interface):
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
PersonDTO personToPersonDTO(Person person);
}
এখানে:
- PersonMapper একটি Mapper Interface যা personToPersonDTO নামক একটি mapping method ডিফাইন করে, যা Person অবজেক্ট থেকে PersonDTO তে ডেটা ম্যাপ করবে।
- Mappers.getMapper(PersonMapper.class): MapStruct এর মাধ্যমে কোড জেনারেট করা হয়, যার মাধ্যমে এই মেথডটি বাস্তবায়িত হয়।
৩. Mapping Method কিভাবে কাজ করে?
MapStruct কম্পাইল টাইমে একটি কনক্রিট ক্লাস তৈরি করে, যেটি আপনার Mapper Interface এর mapping method গুলি বাস্তবায়ন করে। একে code generation বলা হয়, যেখানে MapStruct কোডটি রানটাইমে তৈরি করে, তাই এটি performance দ্রুত এবং type-safe।
৩.১ Code Generation
আপনি যখন mvn compile কমান্ড রান করবেন, তখন MapStruct একটি ক্লাস তৈরি করবে (যেমন PersonMapperImpl) এবং এতে আপনার personToPersonDTO মেথডের কোড থাকবে। এই কোডটি Person অবজেক্টের প্রোপার্টি PersonDTO তে স্থানান্তর করবে।
৩.২ Using Mapping Method
কোড জেনারেশন হওয়ার পরে, আপনি এটি ব্যবহার করতে পারবেন:
Person person = new Person();
person.setFirstName("John");
person.setLastName("Doe");
PersonDTO personDTO = PersonMapper.INSTANCE.personToPersonDTO(person);
System.out.println(personDTO.getFirstName()); // Output: John
System.out.println(personDTO.getLastName()); // Output: Doe
এখানে, PersonMapper.INSTANCE.personToPersonDTO(person) কল করার মাধ্যমে Person অবজেক্টের ডেটা PersonDTO তে ম্যাপ হবে।
৪. Multiple Mapping Methods
MapStruct এর মাধ্যমে একাধিক Mapping Methods তৈরি করা সম্ভব, যেখানে আপনি একাধিক অবজেক্টের মধ্যে ডেটা ম্যাপিং করতে পারেন। উদাহরণস্বরূপ, Person থেকে Employee তে ডেটা ট্রান্সফরমেশন।
উদাহরণ: Multiple Mapping Methods
ধরা যাক, আপনার আরো একটি EmployeeDTO ক্লাস আছে:
EmployeeDTO.java:
public class EmployeeDTO {
private String name;
private String position;
// getters and setters
}
এখন, আপনি Person থেকে EmployeeDTO তে ম্যাপিং করার জন্য আলাদা একটি mapping method তৈরি করতে পারেন:
PersonMapper.java:
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
PersonDTO personToPersonDTO(Person person);
// New mapping method
EmployeeDTO personToEmployeeDTO(Person person);
}
এখানে, personToEmployeeDTO মেথডটি Person অবজেক্ট থেকে EmployeeDTO তে ডেটা ম্যাপ করবে।
৫. Custom Mapping Methods
আপনি কাস্টম ম্যাপিংও তৈরি করতে পারেন যেখানে কোনো বিশেষ কনভার্সন বা ট্রান্সফরমেশন প্রয়োজন হয়। উদাহরণস্বরূপ, যদি আপনার Person ক্লাসে ফিল্ডের নাম firstName এবং lastName থাকে, কিন্তু EmployeeDTO তে একটি ফিল্ডের নাম fullName থাকে, তাহলে আপনি একটি কাস্টম ম্যাপিং মেথড তৈরি করতে পারেন।
উদাহরণ: Custom Mapping Method
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
// Custom Mapping Method
@Mapping(source = "firstName", target = "fullName")
EmployeeDTO personToEmployeeDTO(Person person);
}
এখানে, @Mapping অ্যনোটেশন ব্যবহার করে firstName কে fullName এ ম্যাপ করা হয়েছে।
৬. Mapping Collections
MapStruct বিভিন্ন ধরনের Collections (যেমন List, Set) এর মধ্যে ডেটা ম্যাপিংও সমর্থন করে। আপনি একটি List থেকে List এ ডেটা ম্যাপ করতে পারেন।
উদাহরণ: Mapping Collections
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
List<PersonDTO> personListToPersonDTOList(List<Person> persons);
}
এখানে, personListToPersonDTOList মেথডটি একটি List থেকে List তে ডেটা ম্যাপ করবে।
৭. MapStruct এবং Null Handling
MapStruct স্বয়ংক্রিয়ভাবে null মান হ্যান্ডেল করে এবং কোনো null অবজেক্ট থাকলে, এটি সাধারণত null হিসাবে ট্রান্সফার করে। আপনি যদি বিশেষভাবে null হ্যান্ডলিং কাস্টমাইজ করতে চান, তবে @Mapping অ্যনোটেশন ব্যবহার করে nullValueCheckStrategy অথবা defaultValue সেট করতে পারেন।
উদাহরণ: Null Handling in MapStruct
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
@Mapping(target = "lastName", defaultValue = "Unknown")
PersonDTO personToPersonDTO(Person person);
}
এখানে, যদি lastName ফিল্ডের মান null হয়, তবে এটি "Unknown" সেট হবে।
সারাংশ
MapStruct একটি শক্তিশালী টুল যা Java Beans এর মধ্যে ডেটা ট্রান্সফরমেশন সহজ এবং দ্রুত করে তোলে। Mapping Methods হল সেই পদ্ধতিগুলি যা Mapper Interface এর মাধ্যমে source এবং target অবজেক্টের মধ্যে ডেটা ম্যাপিং সম্পন্ন করে। MapStruct কোড জেনারেশন করে, যাতে কম্পাইল টাইমে ডেটা ম্যাপিং দ্রুত এবং নিরাপদ হয়।
এছাড়া, MapStruct nested objects, collections, custom mapping এবং null handling সহ বিভিন্ন ধরনের ডেটা ম্যাপিং সমর্থন করে, যা ডেটা ট্রান্সফরমেশন প্রক্রিয়াকে আরও সহজ এবং দ্রুত করে তোলে।
MapStruct হল একটি শক্তিশালী কোড জেনারেশন টুল যা Java Beans এর মধ্যে ডেটা ম্যানুয়াল ট্রান্সফরমেশনকে কম্পাইল টাইমে বাস্তবায়ন করে। @Mapping অ্যানোটেশন MapStruct এর অন্যতম প্রধান অ্যানোটেশন, যা ডেটা ম্যাপিং প্রক্রিয়ায় কীভাবে এবং কোথায় ট্রান্সফরমেশন ঘটবে তা নির্দেশ করে। এটি MapStruct Mapper Interface বা Abtract Method-এর মধ্যে ব্যবহার করা হয় এবং উৎস এবং লক্ষ্য ফিল্ডগুলির মধ্যে ম্যাপিং নির্ধারণ করতে সাহায্য করে।
এই টিউটোরিয়ালে, আমরা @Mapping অ্যানোটেশন ব্যবহারের কিছু উদাহরণ এবং এর কনফিগারেশন দেখব।
১. @Mapping অ্যানোটেশন কী?
@Mapping অ্যানোটেশন MapStruct এ ব্যবহৃত হয় ডেটা ট্রান্সফরমেশনের জন্য। এটি নির্দেশ করে যে একটি ফিল্ডের মান একটি উৎস (source) ক্লাস থেকে একটি লক্ষ্য (target) ক্লাসে কিভাবে কপি হবে। এই অ্যানোটেশনটি ফিল্ড নাম, কাস্টম কনভার্টার, বা মিথড ব্যবহার করে ম্যাপিং কনফিগার করতে সক্ষম।
@Mapping অ্যানোটেশন ব্যবহার করে আপনি নিম্নলিখিত কাজগুলো করতে পারেন:
- Source এবং Target ফিল্ড নাম মেলানো: যদি সোর্স এবং টার্গেট ফিল্ডের নাম ভিন্ন হয় তবে @Mapping ব্যবহার করা হয়।
- Custom Value Mapping: কাস্টম কনভার্টার ব্যবহার করে ফিল্ড মান কাস্টমাইজ করা যায়।
- Ignore Certain Fields: কোনো নির্দিষ্ট ফিল্ড ম্যাপিং থেকে বাদ দেয়া।
২. @Mapping অ্যানোটেশন এর সিঙ্কট্যাক্স
@Mapping অ্যানোটেশনটি সাধারণত তিনটি প্রধান প্যারামিটার সহ ব্যবহার করা হয়:
- source: উৎস ফিল্ডের নাম।
- target: লক্ষ্য ফিল্ডের নাম।
- ignore: যদি আপনি কোনো ফিল্ড ম্যাপ করতে না চান, তবে
trueসেট করুন।
উদাহরণ:
@Mapping(source = "firstName", target = "name")
@Mapping(source = "age", target = "years")
@Mapping(target = "address", ignore = true)
এখানে:
- source এবং target কাস্টম ম্যাপিং নির্দেশ করে।
- ignore = true নির্দেশ করে যে
addressফিল্ডটি ম্যাপ করা হবে না।
৩. @Mapping অ্যানোটেশন এর ব্যবহার উদাহরণ
ধরা যাক আমাদের দুটি ক্লাস রয়েছে, Person এবং PersonDTO, এবং আমরা Person থেকে PersonDTO তে ডেটা ম্যাপ করতে চাই।
- Person.java ক্লাস:
public class Person {
private String firstName;
private String lastName;
private int age;
// getters and setters
}
- PersonDTO.java ক্লাস:
public class PersonDTO {
private String name;
private String surname;
private int years;
// getters and setters
}
এখানে, Person ক্লাসের firstName ফিল্ডকে name ফিল্ডে এবং age ফিল্ডকে years ফিল্ডে ম্যাপ করতে হবে। কিন্তু lastName এবং surname ফিল্ডগুলোর মধ্যে মেলানো হবে না।
Mapper Interface:
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper
public interface PersonMapper {
@Mapping(source = "firstName", target = "name")
@Mapping(source = "lastName", target = "surname")
@Mapping(source = "age", target = "years")
PersonDTO personToPersonDTO(Person person);
}
এখানে:
@Mapping(source = "firstName", target = "name"):PersonএরfirstNameফিল্ডকেPersonDTOএরnameফিল্ডে ম্যাপ করছে।@Mapping(source = "age", target = "years"):ageফিল্ডটিyearsফিল্ডে ম্যাপ করছে।@Mapping(source = "lastName", target = "surname"):lastNameফিল্ডটিsurnameফিল্ডে ম্যাপ করছে।
এখন, MapStruct স্বয়ংক্রিয়ভাবে একটি PersonMapperImpl ক্লাস তৈরি করবে, যা Person থেকে PersonDTO তে ডেটা ম্যাপ করবে।
৪. @Mapping এর Advanced ব্যবহার
৪.১ Custom Value Mapping
কখনো কখনো আপনি ফিল্ডের মান কাস্টম ট্রান্সফরমেশন করতে চাইবেন। এর জন্য @Mapping এর মাধ্যমে কাস্টম কনভার্টার ব্যবহার করা যেতে পারে।
@Mapping(source = "birthDate", target = "age", qualifiedByName = "ageFromBirthDate")
PersonDTO personToPersonDTO(Person person);
@Named("ageFromBirthDate")
default int convertToAge(LocalDate birthDate) {
return Period.between(birthDate, LocalDate.now()).getYears();
}
এখানে, convertToAge মেথডে কাস্টম কনভার্টার ব্যবহার করা হয়েছে যা birthDate থেকে age নির্ধারণ করবে।
৪.২ Ignoring Fields
MapStruct এ আপনি যদি কোনো ফিল্ড ম্যাপ করতে না চান তবে আপনি @Mapping(ignore = true) ব্যবহার করতে পারেন। উদাহরণস্বরূপ:
@Mapping(source = "firstName", target = "name")
@Mapping(source = "age", target = "years")
@Mapping(target = "address", ignore = true)
PersonDTO personToPersonDTO(Person person);
এখানে, address ফিল্ডটি ম্যাপিং থেকে বাদ দেওয়া হয়েছে এবং MapStruct এই ফিল্ডটি ট্রান্সফার করবে না।
৫. Nested Mapping
MapStruct অনেক সময় nested objects (যেখানে এক ক্লাসের মধ্যে অন্য ক্লাস থাকে) এর মধ্যে ডেটা ম্যাপ করতে ব্যবহৃত হয়। আপনি যখন nested mappings করতে চান, তখন @Mapping অ্যানোটেশন দিয়ে অন্তর্নিহিত ক্লাসের মধ্যে ডেটা ট্রান্সফার করতে পারেন।
উদাহরণ:
public class Person {
private String firstName;
private Address address;
// getters and setters
}
public class PersonDTO {
private String name;
private AddressDTO address;
// getters and setters
}
public class Address {
private String city;
private String country;
// getters and setters
}
public class AddressDTO {
private String city;
private String country;
// getters and setters
}
@Mapper
public interface PersonMapper {
@Mapping(source = "firstName", target = "name")
@Mapping(source = "address", target = "address")
PersonDTO personToPersonDTO(Person person);
@Mapping(source = "city", target = "city")
@Mapping(source = "country", target = "country")
AddressDTO addressToAddressDTO(Address address);
}
এখানে, Address এবং AddressDTO এর মধ্যে nested mapping তৈরি করা হয়েছে। PersonMapper ক্লাসে একটি মেথড personToPersonDTO ব্যবহার করে, যেখানে Address অবজেক্টটি AddressDTO তে ট্রান্সফার করা হচ্ছে।
সারাংশ
@Mapping অ্যানোটেশন MapStruct এর মূল অংশ যা ডেটা ট্রান্সফরমেশনে ব্যবহৃত হয়। এটি source এবং target ফিল্ডগুলির মধ্যে ম্যানুয়াল ম্যাপিং কনফিগার করতে সহায়তা করে। আপনি @Mapping এর মাধ্যমে:
- Field Mapping নির্ধারণ করতে পারেন।
- Custom Value Mapping করতে পারেন।
- Nested Mapping পরিচালনা করতে পারেন।
- কোনো ফিল্ডকে Ignore করতে পারেন।
MapStruct অ্যানোটেশন ব্যবহার করে আপনি আপনার প্রোজেক্টের ডেটা মাপিং প্রক্রিয়াকে খুব সহজ, দ্রুত এবং সঠিকভাবে করতে পারেন। এটি টাইপ সেফটি নিশ্চিত করে এবং runtime পারফরম্যান্সে কোনো নেতিবাচক প্রভাব ফেলে না, কারণ এটি compile-time কোড জেনারেশন ব্যবহার করে।
MapStruct হল একটি কোড জেনারেটর লাইব্রেরি যা compile-time এ ডোমেইন অবজেক্ট এবং DTO (Data Transfer Object) এর মধ্যে ম্যাপিং কোড জেনারেট করে। এটি দ্রুত এবং টাইপ-সেফ ম্যাপিং প্রদান করে। MapStruct ব্যবহার করে আপনি Field Mapping এবং Custom Mapping করতে পারেন, যেখানে কিছু ক্ষেত্র ডোমেইন অবজেক্ট থেকে অন্য অবজেক্টে সরাসরি ম্যাপ হয় এবং কিছু ক্ষেত্রে কাস্টম ম্যাপিং ব্যবহার করতে হয়।
এই টিউটোরিয়ালে, আমরা Field Mapping এবং Custom Mapping এর দুটি বাস্তব উদাহরণ দেখব।
১. Field Mapping (ফিল্ড ম্যাপিং)
Field Mapping হল এমন একটি প্রক্রিয়া যেখানে দুটি অবজেক্টের মধ্যে ফিল্ডের মান সরাসরি কপি করা হয়। MapStruct এটি খুব সহজে এবং দ্রুত করে, যেহেতু এটি compile-time এ কোড জেনারেট করে।
উদাহরণ: Simple Field Mapping
ধরা যাক, আমাদের দুটি ক্লাস Employee এবং EmployeeDTO রয়েছে, এবং আমরা তাদের মধ্যে ফিল্ড ম্যাপিং করতে চাই।
Employee.java (Domain Object)
public class Employee {
private String name;
private int age;
private String department;
// Getters and Setters
}
EmployeeDTO.java (DTO)
public class EmployeeDTO {
private String name;
private int age;
private String department;
// Getters and Setters
}
এখন, MapStruct এর মাধ্যমে Employee থেকে EmployeeDTO তে ফিল্ড ম্যাপিং করতে হবে। MapStruct সাধারণত field names এর মধ্যে মিল খুঁজে ম্যাপিং করে দেয়।
EmployeeMapper.java (Mapper Interface)
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);
// Simple field-to-field mapping
EmployeeDTO employeeToEmployeeDTO(Employee employee);
}
এখানে, employeeToEmployeeDTO মেথডটি Employee অবজেক্ট থেকে EmployeeDTO অবজেক্টে ফিল্ড ম্যাপিং করে। MapStruct কোড জেনারেট করে যে name, age, এবং department ফিল্ডগুলির মান সরাসরি ম্যাপ করা হবে।
Main.java (Usage Example)
public class Main {
public static void main(String[] args) {
Employee employee = new Employee();
employee.setName("John");
employee.setAge(30);
employee.setDepartment("Engineering");
// Using MapStruct Mapper to map Employee to EmployeeDTO
EmployeeDTO employeeDTO = EmployeeMapper.INSTANCE.employeeToEmployeeDTO(employee);
System.out.println("Name: " + employeeDTO.getName());
System.out.println("Age: " + employeeDTO.getAge());
System.out.println("Department: " + employeeDTO.getDepartment());
}
}
এখানে, MapStruct মেথড employeeToEmployeeDTO কে কল করে Employee থেকে EmployeeDTO তে ফিল্ড ম্যাপিং সম্পন্ন করবে।
২. Custom Mapping (কাস্টম ম্যাপিং)
Custom Mapping হল এমন একটি প্রক্রিয়া যেখানে আপনি কিছু ফিল্ডের মান কাস্টমভাবে ম্যাপ করতে পারেন, যেমন কোনো বিশেষ রূপান্তর বা ডেটা কনভার্শন। MapStruct আপনাকে custom mapping করার সুযোগ দেয়, যেখানে আপনি নিজের কাস্টম কনভার্টার বা লজিক প্রয়োগ করতে পারেন।
উদাহরণ: Custom Mapping
ধরা যাক, আমাদের Person অবজেক্টে fullName ফিল্ডটি আছে, এবং আমরা চাই যে এটি firstName এবং lastName ফিল্ডে ভেঙে ম্যাপ করা হোক।
Person.java (Domain Object)
public class Person {
private String fullName;
// Getters and Setters
}
PersonDTO.java (DTO)
public class PersonDTO {
private String firstName;
private String lastName;
// Getters and Setters
}
এখন, MapStruct ব্যবহার করে Person এর fullName থেকে PersonDTO এর firstName এবং lastName এ ডেটা ভেঙে ম্যাপ করতে হবে।
PersonMapper.java (Mapper Interface with Custom Mapping)
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper
public interface PersonMapper {
// Custom mapping: Split fullName into firstName and lastName
@Mapping(source = "fullName", target = "firstName",
qualifiedByName = "splitFullNameFirstName")
@Mapping(source = "fullName", target = "lastName",
qualifiedByName = "splitFullNameLastName")
PersonDTO personToPersonDTO(Person person);
// Custom method to extract first name from full name
default String splitFullNameFirstName(String fullName) {
return fullName != null ? fullName.split(" ")[0] : null;
}
// Custom method to extract last name from full name
default String splitFullNameLastName(String fullName) {
return fullName != null ? fullName.split(" ")[1] : null;
}
}
এখানে, splitFullNameFirstName এবং splitFullNameLastName কাস্টম মেথড তৈরি করা হয়েছে যা fullName থেকে firstName এবং lastName একে অপরের মধ্যে আলাদা করবে।
Main.java (Usage Example)
public class Main {
public static void main(String[] args) {
Person person = new Person();
person.setFullName("John Doe");
// Using MapStruct Mapper to map Person to PersonDTO
PersonDTO personDTO = PersonMapper.INSTANCE.personToPersonDTO(person);
System.out.println("First Name: " + personDTO.getFirstName());
System.out.println("Last Name: " + personDTO.getLastName());
}
}
এখানে, fullName এর মান "John Doe" কে firstName ("John") এবং lastName ("Doe") তে কাস্টম ম্যাপ করা হবে।
৩. MapStruct এর অন্যান্য কাস্টম ম্যাপিং পদ্ধতি
MapStruct আরও কিছু কাস্টম ম্যাপিং পদ্ধতি প্রদান করে যা ব্যবহার করে আপনি জটিল লজিক প্রয়োগ করতে পারেন। উদাহরণস্বরূপ:
- Expression: ডেটার মান ম্যাপিং করতে এক্সপ্রেশন ব্যবহার করা।
- Iterable and Array Mapping: তালিকা বা অ্যারে ম্যাপিং করতে কাস্টম লজিক ব্যবহার করা।
- Enum Mapping: এনাম টাইপের মান ম্যাপিং করা।
উদাহরণ: Expression Mapping
@Mapping(source = "age", target = "ageInMonths", expression = "java(person.getAge() * 12)")
PersonDTO personToPersonDTO(Person person);
এখানে, age ফিল্ডের মান ageInMonths ফিল্ডে কাস্টম এক্সপ্রেশনের মাধ্যমে ম্যাপ করা হয়েছে।
সারাংশ
MapStruct ব্যবহার করে আপনি সহজেই Field Mapping এবং Custom Mapping করতে পারেন। Field Mapping সাধারণত সরাসরি ফিল্ডের মান কপি করে, যেখানে Custom Mapping আপনাকে কাস্টম লজিক প্রয়োগ করার সুযোগ দেয়। এটি MapStruct এর একটি শক্তিশালী বৈশিষ্ট্য যা আপনার ডেটা ট্রান্সফার লজিক আরও নমনীয় এবং পারফরম্যান্সে উন্নত করে।
MapStruct একটি Java annotation processor যা ডোমেইন অবজেক্ট এবং DTO (Data Transfer Object) এর মধ্যে অটোমেটিকভাবে ম্যাপিং করতে সহায়তা করে। এতে Mapping Methods তৈরি করতে হয়, যা ডেটা এক অবজেক্ট থেকে অন্য অবজেক্টে কপি করে। MapStruct compile-time এ কোড জেনারেট করে, ফলে পারফরম্যান্সে কোনো সমস্যা হয় না। এটি বিশেষত JavaBeans (POJOs) বা ডোমেইন অবজেক্টের মধ্যে ম্যাপিং করার জন্য উপকারী।
এই টিউটোরিয়ালে, আমরা উদাহরণ সহ দেখব কীভাবে MapStruct এর মাধ্যমে Mapping Methods তৈরি করা যায়।
১. MapStruct Mapping Methods তৈরি করা
MapStruct এর মূল কাজ হল ডোমেইন অবজেক্ট এবং DTO (Data Transfer Object) এর মধ্যে ম্যাপিং করা। এজন্য MapStruct এ একটি Mapper Interface তৈরি করতে হয়, এবং এই ইন্টারফেসে ম্যাপিং মেথডগুলির সিগনেচার থাকে। MapStruct সেই মেথডগুলোর জন্য কোড জেনারেট করে।
উদাহরণ: Mapping Methods তৈরি
ধরা যাক, আমাদের দুটি ক্লাস Employee এবং EmployeeDTO রয়েছে, এবং আমরা এই দুই ক্লাসের মধ্যে ম্যাপিং করতে চাই।
১.১ Employee (Domain Object)
public class Employee {
private String name;
private String department;
private int age;
// Constructors, Getters, and Setters
public Employee(String name, String department, int age) {
this.name = name;
this.department = department;
this.age = age;
}
// Getters and Setters
}
1.2 EmployeeDTO (Data Transfer Object)
public class EmployeeDTO {
private String fullName;
private String department;
private int age;
// Constructors, Getters, and Setters
public EmployeeDTO(String fullName, String department, int age) {
this.fullName = fullName;
this.department = department;
this.age = age;
}
// Getters and Setters
}
এখন, আমাদের Employee ক্লাসের ডেটা EmployeeDTO ক্লাসে ম্যাপ করতে হবে।
1.3 EmployeeMapper (Mapper Interface)
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);
// Mapping method
EmployeeDTO employeeToEmployeeDTO(Employee employee);
}
এখানে, EmployeeMapper একটি Mapper Interface যা employeeToEmployeeDTO মেথডের মাধ্যমে Employee অবজেক্টকে EmployeeDTO অবজেক্টে ম্যাপ করবে।
1.4 Main Class (Usage)
public class Main {
public static void main(String[] args) {
Employee employee = new Employee("John Doe", "Engineering", 30);
// Mapping
EmployeeDTO employeeDTO = EmployeeMapper.INSTANCE.employeeToEmployeeDTO(employee);
System.out.println("Full Name: " + employeeDTO.getFullName());
System.out.println("Department: " + employeeDTO.getDepartment());
System.out.println("Age: " + employeeDTO.getAge());
}
}
এখানে, EmployeeMapper.INSTANCE.employeeToEmployeeDTO(employee) এর মাধ্যমে Employee অবজেক্টটি EmployeeDTO তে ম্যাপ হয়ে যায়।
এটি কম্পাইল টাইমে ম্যাপিং কোড জেনারেট করবে এবং আপনাকে রানটাইমে কোনো কাস্টম কোড লেখার প্রয়োজন হবে না।
২. MapStruct Mapping Methods এর বিভিন্ন ধরণ
MapStruct এর মাধ্যমে Mapping Methods তৈরি করতে আপনি বিভিন্ন কাস্টম ম্যাপিং লজিক বা কনভার্সন যুক্ত করতে পারেন। এটি সুনির্দিষ্ট ম্যাপিং প্রক্রিয়া তৈরি করতে সহায়তা করে।
২.১ Custom Mapping for Specific Fields
ধরা যাক, আমাদের Employee এবং EmployeeDTO ক্লাসের মধ্যে name এবং fullName ফিল্ডের নাম ভিন্ন, তাহলে আমরা কাস্টম ম্যাপিং করতে পারি।
@Mapper
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);
@Mapping(source = "name", target = "fullName")
EmployeeDTO employeeToEmployeeDTO(Employee employee);
}
এখানে, @Mapping অ্যানোটেশন ব্যবহার করে Employee এর name ফিল্ডকে EmployeeDTO এর fullName ফিল্ডে ম্যাপ করা হয়েছে।
২.২ Mapping Collections
MapStruct এর মাধ্যমে আপনি একটি লিস্ট বা অ্যারে থেকেও ম্যাপিং করতে পারবেন। এখানে একটি উদাহরণ:
@Mapper
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);
List<EmployeeDTO> employeesToEmployeeDTOs(List<Employee> employees);
}
এখানে, employeesToEmployeeDTOs মেথডটি একটি List কে List তে রূপান্তরিত করবে।
৩. MapStruct এর মাধ্যমে Complex Mapping
আপনি যদি আরও জটিল ম্যাপিং করতে চান, যেখানে বিভিন্ন ক্লাসের মধ্যে ম্যাপিং করা হয়, তাহলে MapStruct সহজেই তা সমাধান করতে পারে।
৩.১ Mapping Nested Objects
ধরা যাক, আমাদের Employee এবং Department নামে দুটি ক্লাস রয়েছে, এবং Employee ক্লাসে Department অবজেক্ট রয়েছে। আমাদের EmployeeDTO তে এই Department ক্লাসটিও ম্যাপ করতে হবে।
Example: Nested Object Mapping
public class Department {
private String departmentName;
// Getters and Setters
}
public class Employee {
private String name;
private Department department;
// Getters and Setters
}
এখন, Department কে EmployeeDTO তে ম্যাপ করতে আমরা কাস্টম ম্যাপিং ব্যবহার করতে পারি।
@Mapper
public interface EmployeeMapper {
EmployeeDTO employeeToEmployeeDTO(Employee employee);
// Mapping Department to DepartmentDTO
DepartmentDTO departmentToDepartmentDTO(Department department);
}
এখানে, আমরা Department ক্লাসের ম্যাপিংয়ের জন্য departmentToDepartmentDTO মেথড তৈরি করেছি, যা DepartmentDTO তে ডেটা কপি করবে।
৪. Default and Custom Mapping Methods
MapStruct ডিফল্ট ম্যাপিং পদ্ধতি যেমন ফিল্ড নামের ভিত্তিতে অটোমেটিক ম্যাপিং করার জন্য পরিচিত। কিন্তু আপনি যখন কাস্টম ম্যাপিং চাহিদা প্রয়োগ করবেন, তখন custom mapping methods তৈরি করতে হবে। এই কাস্টম মেথডের মাধ্যমে আপনি ডেটা কনভার্সন বা লজিক প্রয়োগ করতে পারবেন।
Example: Custom Mapping Method
@Mapper
public interface EmployeeMapper {
@Mapping(target = "fullName", expression = "java(employee.getName() + \" - \" + employee.getDepartment())")
EmployeeDTO employeeToEmployeeDTO(Employee employee);
}
এখানে, expression এর মাধ্যমে কাস্টম ম্যাপিং করা হয়েছে, যেখানে fullName ফিল্ডে name এবং department ফিল্ডের মান একসাথে যোগ করা হয়েছে।
সারাংশ
MapStruct একটি শক্তিশালী টুল যা ডোমেইন অবজেক্ট এবং DTO (Data Transfer Object) এর মধ্যে ডেটা ম্যাপিং করতে সাহায্য করে। এটি compile-time এ কোড জেনারেট করে, ফলে রানটাইম পারফরম্যান্সের কোন প্রভাব পড়ে না। Mapping Methods তৈরি করার সময়, আপনি বিভিন্ন কাস্টম এবং ডিফল্ট ম্যাপিং পদ্ধতি ব্যবহার করতে পারেন, যেমন nested object mapping, custom mapping এবং collections mapping। MapStruct ব্যবহারে কোড লেখার প্রক্রিয়া অনেক সহজ হয়ে ওঠে এবং এটি আপনার ডেভেলপমেন্ট সাইকেলকে দ্রুততর করে।
Read more