מיפוי אוספים עם MapStruct

1. סקירה כללית

במדריך זה נבחן כיצד למפות אוספים של אובייקטים באמצעות MapStruct.

מכיוון שמאמר זה מניח כבר הבנה בסיסית של MapStruct, על המתחילים לבדוק קודם את המדריך המהיר שלנו ל- MapStruct.

2. מיפוי אוספים

בכללי, מיפוי אוספים עם MapStruct פועל באופן זהה לסוגים פשוטים.

בעיקרון, עלינו ליצור ממשק פשוט או מחלקה מופשטת ולהצהיר על שיטות המיפוי. בהתבסס על הצהרותינו, MapStruct תייצר את קוד המיפוי באופן אוטומטי. בדרך כלל, הקוד שנוצר יעבור על אוסף המקור, ימיר כל אלמנט לסוג היעד ויכלול כל אחד מהם באוסף היעד.

בואו נסתכל על דוגמה פשוטה.

2.1. רשימות מיפוי

ראשית, לדוגמא, בואו ניקח בחשבון POJO פשוט כמקור המיפוי של המפות שלנו:

שכבה ציבורית עובד {פרטי מחרוזת firstName; שם משפחה פרטי מחרוזת; // קונסטרוקטור, גטרים וקובעים} 

היעד יהיה DTO פשוט:

מחלקה ציבורית EmployeeDTO {פרטי מחרוזת שם פרטי; שם משפחה פרטי מחרוזת; // גטרים וקובעים}

לאחר מכן, בואו נגדיר את המפה שלנו:

ממשק ציבורי @Mapper EmployeeMapper {מפת מפה (רשימת עובדים); } 

לבסוף, בואו נסתכל על הקוד MapStruct שנוצר מה- שלנו עובד עובד מִמְשָׁק:

מחלקה ציבורית EmployeeMapperImpl מיישמת EmployeeMapper {@Override public list map (רשימת עובדים) {if (עובדים == null) {להחזיר null; } רשימת רשימות = ArrayList חדש (עובדים.גודל ()); עבור (עובד שכיר: עובדים) {list.add (עובדToEmployeeDTO (עובד)); } רשימת החזרה; } עובד עובד מוגן מוגן ToEmployeeDTO (עובד עובד) {if (עובד == null) {להחזיר null; } EmployeeDTO עובדDTO = EmployeeDTO חדש (); employeeDTO.setFirstName (עובד.גטפירסטנאם ()); employeeDTO.setLastName (employee.getLastName ()); החזר עובדDTO; }} 

יש לציין דבר חשוב. במיוחד, MapStruct שנוצר עבורנו באופן אוטומטי את המיפוי מ- עוֹבֵד ל EmployeeDTO.

יש מקרים שזה לא אפשרי. לדוגמה, נניח שאנחנו רוצים למפות את שלנו עוֹבֵד מודל לדגם הבא:

מחלקה ציבורית EmployeeFullNameDTO {Private String fullName; // גטר וקובע}

במקרה זה, אם רק נכריז על שיטת המיפוי מ- רשימה שֶׁל עוֹבֵד אל א רשימה שֶׁל EmployeeFullNameDTO נקבל שגיאת זמן הידור או אזהרה כמו:

אזהרה: (11, 31) java: מאפיין יעד לא ממופה: "fullName". מיפוי מאלמנט האוסף "com.baeldung.mapstruct.mappingCollections.model.Em עובד עובד" ל- "com.baeldung.mapstruct.mappingCollections.dto.EmployeeFullNameDTO עובדFullNameDTO".

בעיקרון, זה אומר את זה MapStruct לא הצליחה ליצור את המיפוי באופן אוטומטי עבורנובמקרה הזה. לכן עלינו להגדיר באופן ידני את המיפוי בין עוֹבֵד ו EmployeeFullNameDTO.

בהתחשב בנקודות אלה, בואו נגדיר זאת ידנית:

ממשק ציבורי @Mapper EmployeeFullNameMapper {מפת מפה (רשימת עובדים); מפת EmployeeFullNameDTO המוגדרת כברירת מחדל (עובד שכיר) {EmployeeFullNameDTO employeeInfoDTO = EmployeeFullNameDTO חדש (); employeeInfoDTO.setFullName (employee.getFirstName () + "" + employee.getLastName ()); החזר עובדInfoDTO; }}

הקוד שנוצר ישתמש בשיטה שהגדרנו למיפוי רכיבי המקור רשימה אל היעד רשימה.

זה חל גם באופן כללי. אם הגדרנו שיטה הממפה את סוג אלמנט המקור לסוג אלמנט היעד, MapStruct ישתמש בה.

2.2. מיפוי סטים ומפות

סטים למיפוי עם MapStruct פועלים באותו אופן כמו ברשימות. לדוגמא, נניח שאנחנו רוצים למפות א מַעֲרֶכֶת שֶׁל עוֹבֵד מקרים לא מַעֲרֶכֶת שֶׁל EmployeeDTO מקרים.

כמו קודם, אנו זקוקים למפות:

ממשק ציבורי @Mapper EmployeeMapper {הגדר מפה (הגדר עובדים); }

ו- MapStruct תיצור את הקוד המתאים:

מחלקה ציבורית EmployeeMapperImpl מיישם EmployeeMapper {@Override public הגדר מפה (הגדר עובדים) {if (עובדים == null) {החזר null; } Set set = HashSet new (Math.max ((int) (workers.size () / .75f) + 1, 16)); עבור (עובד שכיר: עובדים) {set.add (עובדToEmployeeDTO (עובד)); } סט חזרה; } עובד עובד מוגן מוגן ToEmployeeDTO (עובד עובד) {if (עובד == null) {להחזיר null; } EmployeeDTO עובדDTO = EmployeeDTO חדש (); employeeDTO.setFirstName (עובד.גטפירסטנאם ()); employeeDTO.setLastName (employee.getLastName ()); החזר עובדDTO; }}

כנ"ל לגבי מפות. בואו ניקח בחשבון שאנחנו רוצים למפות א מַפָּה אל א מַפָּה.

לאחר מכן נוכל לבצע את אותם השלבים כמו קודם:

ממשק ציבורי @Mapper EmployeeMapper {מפת מפה (Map idEmployeeMap); }

ו- MapStruct עושה את עבודתה:

מחלקה ציבורית EmployeeMapperImpl מיישמת EmployeeMapper {@Override Map Map map (Map idEmployeeMap) {if (idEmployeeMap == null) {return null; } מפת מפה = HashMap חדש (Math.max ((int) (idEmployeeMap.size () / .75f) + 1, 16)); עבור (java.util.Map.Entry entry: idEmployeeMap.entrySet ()) {String key = entry.getKey (); ערך EmployeeDTO = workerToEmployeeDTO (entry.getValue ()); map.put (מפתח, ערך); } מפה חזרה; } עובד עובד מוגן מוגן ToEmployeeDTO (עובד עובד) {if (עובד == null) {להחזיר null; } EmployeeDTO עובדDTO = EmployeeDTO חדש (); employeeDTO.setFirstName (employee.getFirstName ()); employeeDTO.setLastName (employee.getLastName ()); החזר עובדDTO; }}

3. אסטרטגיות מיפוי אוספים

לעיתים קרובות עלינו למפות סוגי נתונים המנהלים יחסי הורים וילדים. בדרך כלל, יש לנו סוג נתונים (הורה) שיש לו כשדה a אוסף מסוג נתונים אחר (ילד).

במקרים כאלה, MapStruct מציעה דרך לבחור כיצד להגדיר או להוסיף את הילדים לסוג ההורה. בפרט, ה @Mapper להערה יש collectionMappingStrategy תכונה שיכולה להיות ACCESSOR_ONLY, SETTER_FREFERRED, ADDER_PREFERRED אוֹ TARGET_IMMUTABLE.

כל הערכים הללו מתייחסים לאופן שבו יש להגדיר או להוסיף את הילדים לסוג ההורה. ערך ברירת המחדל הוא ACCESSOR_ONLY, כלומר, ניתן להשתמש רק באביזרים להגדרת ה- אוסף של ילדים.

אפשרות זו שימושית כאשר ה- מגדיר עבור אוסף השדה אינו זמין אך יש לנו תוסף. מקרה נוסף בו זה שימושי הוא כאשר אוסף אינו ניתן לשינוי בסוג ההורה. בדרך כלל, אנו נתקלים במקרים אלה בסוגי יעד שנוצרו.

3.1. ACCESSOR_ONLY אסטרטגיית מיפוי אוספים

בואו ניקח דוגמה כדי להבין טוב יותר איך זה עובד.

לדוגמא שלנו, בואו ליצור a חֶברָה הכיתה כמקור המיפוי שלנו:

חברה ממעמד ציבורי {עובדי רשימה פרטית; // גטר וקובע}

והיעד למיפוי שלנו יהיה DTO פשוט:

מעמד ציבורי CompanyDTO {עובדי רשימה פרטית; רשימת הציבור getEmployees () {להחזיר עובדים; } בטל ציבורי ריק עובדים (עובדים ברשימה) {זה.עובדים = עובדים; } ריק ריק addEmployee (EmployeeDTO עובדDTO) {if (עובדים == null) {עובדים = ArrayList חדש (); } workers.add (עובדDTO); }}

שימו לב שיש לנו את שני הקובעים, עובדים והקצין, הוסף עובד, זמין. גַם, עבור התוסף, אנו אחראים לאתחול האוסף.

עכשיו, נניח שאנחנו רוצים למפות א חֶברָה אל א CompanyDTO. ואז, כמו קודם, אנו זקוקים למפות:

@Mapper (משתמש = EmployeeMapper.class) ממשק ציבורי CompanyMapper {מפת CompanyDTO (חברת חברה); }

שים לב ששימשנו מחדש את ה- עובד עובד ואת ברירת המחדל collectionMappingStrategy.

עכשיו, בואו נסתכל על הקוד שהופק MapStruct:

מחלקה ציבורית CompanyMapperImpl מיישמת CompanyMapper {פרטית סופית EmployeeMapper employeeMapper = Mappers.getMapper (EmployeeMapper.class); @ ביטול מפת CompanyDTO ציבורית ציבורית (חברת חברה) {if (company == null) {return null; } CompanyDTO companyDTO = CompanyDTO חדש (); companyDTO.setEmployees (employeeMapper.map (company.getEmployees ())); חברת החזרת DTO; }}

כפי שאפשר לראות, MapStruct משתמש במגדיר, עובדים מוגדרים, כדי להגדיר את רשימה שֶׁל EmployeeDTO מקרים. זה קורה מכיוון שכאן אנו משתמשים בברירת המחדל collectionMappingStrategy,ACCESSOR_ONLY.

כמו כן, MapStruct מצאה מיפוי שיטה א רשימה אל א רשימה ב עובד עובד ועשה בו שימוש חוזר.

3.2. ADDER_PREFERRED אסטרטגיית מיפוי אוספים

לעומת זאת, בואו ניקח בחשבון שהשתמשנו ADDER_PREFERRED כפי ש collectionMappingStrategy:

@Mapper (collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, שימושים = EmployeeMapper.class) ממשק ציבורי CompanyMapperAdderPreferred {מפת CompanyDTO (חברת חברה); }

שוב, אנו רוצים לעשות שימוש חוזר ב עובד עובד. למרות זאת, עלינו להוסיף במפורש שיטה שיכולה להמיר יחיד עוֹבֵד ל EmployeeDTO ראשון:

ממשק ציבורי @Mapper EmployeeMapper {מפת EmployeeDTO (עובד שכיר); מפת רשימות (רשימת עובדי); הגדר מפה (קבע עובדים); מפת מפות (Map idEmployeeMap); }

הסיבה לכך היא ש- MapStruct ישתמש בתוספת כדי להוסיף EmployeeDTO מקרים ליעד CompanyDTO מקרה אחד אחד:

מעמד ציבורי CompanyMapperAdderPreferredImpl מיישם CompanyMapperAdderPreferred {private final EmployeeMapper employeeMapper = Mappers.getMapper (EmployeeMapper.class); @ ביטול מפת CompanyDTO ציבורית ציבורית (חברת חברה) {if (company == null) {return null; } CompanyDTO companyDTO = CompanyDTO חדש (); אם (company.getEmployees ()! = null) {עבור (עובד שכיר: company.getEmployees ()) {companyDTO.addEmployee (עובדMapper.map (עובד)); }} להחזיר חברת DTO; }}

אם התוספת לא הייתה זמינה, היה נעשה שימוש במגדיר.

אנו יכולים למצוא תיאור מלא של כל אסטרטגיות מיפוי האוסף בתיעוד ההתייחסות של MapStruct.

4. סוגי יישום לאיסוף יעד

MapStruct תומך בממשקי אוספים כסוגי יעד לשיטות מיפוי.

במקרה זה, נעשה שימוש בחלק מיישומי ברירת המחדל בקוד שנוצר. לדוגמה, יישום ברירת המחדל עבור רשימה הוא רשימת מערך כפי שניתן לציין מהדוגמאות שלנו לעיל.

אנו יכולים למצוא את רשימת הממשקים המלאה שתומכת ב- MapStruct ואת יישומי ברירת המחדל שבהם היא משתמשת עבור כל ממשק, בתיעוד הפניה.

5. מסקנה

במאמר זה, בדקנו כיצד למפות אוספים באמצעות MapStruct.

ראשית, בדקנו כיצד אנו יכולים למפות סוגים שונים של אוספים. לאחר מכן ראינו כיצד אנו יכולים להתאים אישית את מיפוי קשרי הורים וילדים באמצעות אסטרטגיות מיפוי אוספים.

לאורך הדרך הדגשנו את נקודות המפתח והדברים שיש לזכור בעת מיפוי אוספים באמצעות MapStruct.

כרגיל, הקוד השלם זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found