Skip to content

Commit 93a0057

Browse files
feat: Implement mappers for core entities in concept service
- Created `ConceptMapper`, `AgendaItemMapper`, `EventDetailsMapper`, `PricingMapper`, and `SpeakerMapper` classes to handle conversions between DTOs and entities. - Implemented methods for mapping properties, including handling null values and collections. - Updated the implementation plan to reflect the completion of mapper classes.
1 parent 02cd6d4 commit 93a0057

File tree

6 files changed

+388
-8
lines changed

6 files changed

+388
-8
lines changed

concept-svc/IMPLEMENTATION_PLAN.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ Implementation of the Concept Service following patterns established by the User
6767
## Phase 4: Mapper Classes
6868

6969
### 4.1 Core Mappers
70-
- [ ] Create `ConceptMapper.java` with:
71-
- [ ] `toEntity(Concept dto)` method
72-
- [ ] `toDto(ConceptEntity entity)` method
73-
- [ ] Handle null values and collections properly
74-
- [ ] Create `EventDetailsMapper.java` for embedded entity conversion
75-
- [ ] Create `AgendaItemMapper.java` for agenda item conversion
76-
- [ ] Create `SpeakerMapper.java` for speaker conversion
77-
- [ ] Create `PricingMapper.java` for pricing conversion
70+
- [x] Create `ConceptMapper.java` with:
71+
- [x] `toEntity(Concept dto)` method
72+
- [x] `toDto(ConceptEntity entity)` method
73+
- [x] Handle null values and collections properly
74+
- [x] Create `EventDetailsMapper.java` for embedded entity conversion
75+
- [x] Create `AgendaItemMapper.java` for agenda item conversion
76+
- [x] Create `SpeakerMapper.java` for speaker conversion
77+
- [x] Create `PricingMapper.java` for pricing conversion
7878

7979
## Phase 5: Security Configuration
8080

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package de.tum.aet.devops25.conceptsvc;
2+
3+
import de.tum.aet.devops25.api.generated.model.AgendaItem;
4+
5+
public class AgendaItemMapper {
6+
7+
// DTO → Entity
8+
public static AgendaItemEntity toEntity(AgendaItem dto) {
9+
if (dto == null) {
10+
return null;
11+
}
12+
13+
AgendaItemEntity entity = new AgendaItemEntity();
14+
entity.setId(dto.getId());
15+
entity.setTime(dto.getTime());
16+
entity.setTitle(dto.getTitle());
17+
entity.setDescription(dto.getDescription());
18+
19+
// Enum conversion: API DTO enum → Entity enum
20+
if (dto.getType() != null) {
21+
entity.setType(AgendaItemType.valueOf(dto.getType().getValue()));
22+
}
23+
24+
entity.setSpeaker(dto.getSpeaker());
25+
entity.setDuration(dto.getDuration());
26+
27+
// Note: concept reference is set by parent ConceptMapper, not here
28+
return entity;
29+
}
30+
31+
// Entity → DTO
32+
public static AgendaItem toDto(AgendaItemEntity entity) {
33+
if (entity == null) {
34+
return null;
35+
}
36+
37+
AgendaItem dto = new AgendaItem();
38+
dto.setId(entity.getId());
39+
dto.setTime(entity.getTime());
40+
dto.setTitle(entity.getTitle());
41+
dto.setDescription(entity.getDescription());
42+
43+
// Enum conversion: Entity enum → API DTO enum
44+
if (entity.getType() != null) {
45+
dto.setType(AgendaItem.TypeEnum.fromValue(entity.getType().name()));
46+
}
47+
48+
dto.setSpeaker(entity.getSpeaker());
49+
dto.setDuration(entity.getDuration());
50+
51+
// Note: concept reference not mapped to avoid circular dependency
52+
return dto;
53+
}
54+
}
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package de.tum.aet.devops25.conceptsvc;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Objects;
6+
import java.util.stream.Collectors;
7+
8+
import de.tum.aet.devops25.api.generated.model.Concept;
9+
import de.tum.aet.devops25.api.generated.model.UpdateConceptRequest;
10+
11+
public class ConceptMapper {
12+
13+
// DTO → Entity (full mapping for creation/retrieval)
14+
public static ConceptEntity toEntity(Concept dto) {
15+
if (dto == null) {
16+
return null;
17+
}
18+
19+
ConceptEntity entity = new ConceptEntity();
20+
entity.setId(dto.getId());
21+
entity.setTitle(dto.getTitle());
22+
entity.setDescription(dto.getDescription());
23+
24+
// Enum conversion: API DTO enum → Entity enum
25+
if (dto.getStatus() != null) {
26+
entity.setStatus(ConceptStatus.valueOf(dto.getStatus().getValue()));
27+
}
28+
29+
entity.setUserId(dto.getUserId());
30+
entity.setNotes(dto.getNotes());
31+
entity.setVersion(dto.getVersion());
32+
entity.setCreatedAt(dto.getCreatedAt());
33+
entity.setUpdatedAt(dto.getUpdatedAt());
34+
entity.setLastModifiedBy(dto.getLastModifiedBy());
35+
36+
// Simple collection - defensive copy
37+
entity.setTags(dto.getTags() != null ? new ArrayList<>(dto.getTags()) : new ArrayList<>());
38+
39+
// Embedded entities
40+
entity.setEventDetails(EventDetailsMapper.toEntity(dto.getEventDetails()));
41+
entity.setPricing(PricingMapper.toEntity(dto.getPricing()));
42+
43+
// Child collections with bidirectional relationship handling
44+
if (dto.getAgenda() != null) {
45+
List<AgendaItemEntity> agendaEntities = dto.getAgenda().stream()
46+
.map(AgendaItemMapper::toEntity)
47+
.filter(Objects::nonNull)
48+
.collect(Collectors.toList());
49+
// Set parent reference for bidirectional relationship
50+
agendaEntities.forEach(item -> item.setConcept(entity));
51+
entity.setAgenda(agendaEntities);
52+
} else {
53+
entity.setAgenda(new ArrayList<>());
54+
}
55+
56+
if (dto.getSpeakers() != null) {
57+
List<SpeakerEntity> speakerEntities = dto.getSpeakers().stream()
58+
.map(SpeakerMapper::toEntity)
59+
.filter(Objects::nonNull)
60+
.collect(Collectors.toList());
61+
// Set parent reference for bidirectional relationship
62+
speakerEntities.forEach(speaker -> speaker.setConcept(entity));
63+
entity.setSpeakers(speakerEntities);
64+
} else {
65+
entity.setSpeakers(new ArrayList<>());
66+
}
67+
68+
return entity;
69+
}
70+
71+
// Entity → DTO (full mapping for responses)
72+
public static Concept toDto(ConceptEntity entity) {
73+
if (entity == null) {
74+
return null;
75+
}
76+
77+
Concept dto = new Concept();
78+
dto.setId(entity.getId());
79+
dto.setTitle(entity.getTitle());
80+
dto.setDescription(entity.getDescription());
81+
82+
// Enum conversion: Entity enum → API DTO enum
83+
if (entity.getStatus() != null) {
84+
dto.setStatus(Concept.StatusEnum.fromValue(entity.getStatus().name()));
85+
}
86+
87+
dto.setUserId(entity.getUserId());
88+
dto.setNotes(entity.getNotes());
89+
dto.setVersion(entity.getVersion());
90+
dto.setCreatedAt(entity.getCreatedAt());
91+
dto.setUpdatedAt(entity.getUpdatedAt());
92+
dto.setLastModifiedBy(entity.getLastModifiedBy());
93+
94+
// Simple collection - defensive copy
95+
dto.setTags(entity.getTags() != null ? new ArrayList<>(entity.getTags()) : new ArrayList<>());
96+
97+
// Embedded entities
98+
dto.setEventDetails(EventDetailsMapper.toDto(entity.getEventDetails()));
99+
dto.setPricing(PricingMapper.toDto(entity.getPricing()));
100+
101+
// Child collections (no concept reference to avoid circular dependency)
102+
if (entity.getAgenda() != null) {
103+
List<de.tum.aet.devops25.api.generated.model.AgendaItem> agendaDtos = entity.getAgenda().stream()
104+
.map(AgendaItemMapper::toDto)
105+
.filter(Objects::nonNull)
106+
.collect(Collectors.toList());
107+
dto.setAgenda(agendaDtos);
108+
} else {
109+
dto.setAgenda(new ArrayList<>());
110+
}
111+
112+
if (entity.getSpeakers() != null) {
113+
List<de.tum.aet.devops25.api.generated.model.Speaker> speakerDtos = entity.getSpeakers().stream()
114+
.map(SpeakerMapper::toDto)
115+
.filter(Objects::nonNull)
116+
.collect(Collectors.toList());
117+
dto.setSpeakers(speakerDtos);
118+
} else {
119+
dto.setSpeakers(new ArrayList<>());
120+
}
121+
122+
return dto;
123+
}
124+
125+
// Partial update for PUT operations - only map non-null fields
126+
public static void updateEntityFromRequest(ConceptEntity entity, UpdateConceptRequest request) {
127+
if (entity == null || request == null) {
128+
return;
129+
}
130+
131+
if (request.getTitle() != null) {
132+
entity.setTitle(request.getTitle());
133+
}
134+
135+
if (request.getDescription() != null) {
136+
entity.setDescription(request.getDescription());
137+
}
138+
139+
if (request.getStatus() != null) {
140+
entity.setStatus(ConceptStatus.valueOf(request.getStatus().getValue()));
141+
}
142+
143+
if (request.getNotes() != null) {
144+
entity.setNotes(request.getNotes());
145+
}
146+
147+
if (request.getTags() != null) {
148+
entity.setTags(new ArrayList<>(request.getTags()));
149+
}
150+
151+
// Update embedded entities if provided
152+
if (request.getEventDetails() != null) {
153+
entity.setEventDetails(EventDetailsMapper.toEntity(request.getEventDetails()));
154+
}
155+
156+
if (request.getPricing() != null) {
157+
entity.setPricing(PricingMapper.toEntity(request.getPricing()));
158+
}
159+
160+
// Update child collections if provided
161+
if (request.getAgenda() != null) {
162+
// Clear existing and add new
163+
entity.getAgenda().clear();
164+
List<AgendaItemEntity> agendaEntities = request.getAgenda().stream()
165+
.map(AgendaItemMapper::toEntity)
166+
.filter(Objects::nonNull)
167+
.collect(Collectors.toList());
168+
agendaEntities.forEach(item -> item.setConcept(entity));
169+
entity.getAgenda().addAll(agendaEntities);
170+
}
171+
172+
if (request.getSpeakers() != null) {
173+
// Clear existing and add new
174+
entity.getSpeakers().clear();
175+
List<SpeakerEntity> speakerEntities = request.getSpeakers().stream()
176+
.map(SpeakerMapper::toEntity)
177+
.filter(Objects::nonNull)
178+
.collect(Collectors.toList());
179+
speakerEntities.forEach(speaker -> speaker.setConcept(entity));
180+
entity.getSpeakers().addAll(speakerEntities);
181+
}
182+
}
183+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package de.tum.aet.devops25.conceptsvc;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import de.tum.aet.devops25.api.generated.model.EventDetails;
7+
8+
public class EventDetailsMapper {
9+
10+
// DTO → Entity
11+
public static EventDetailsEntity toEntity(EventDetails dto) {
12+
if (dto == null) {
13+
return null;
14+
}
15+
16+
EventDetailsEntity entity = new EventDetailsEntity();
17+
entity.setTheme(dto.getTheme());
18+
19+
// Enum conversion: API DTO enum → Entity enum
20+
if (dto.getFormat() != null) {
21+
entity.setFormat(EventFormat.valueOf(dto.getFormat().getValue()));
22+
}
23+
24+
entity.setCapacity(dto.getCapacity());
25+
entity.setDuration(dto.getDuration());
26+
entity.setStartDate(dto.getStartDate());
27+
entity.setEndDate(dto.getEndDate());
28+
entity.setTargetAudience(dto.getTargetAudience());
29+
entity.setLocation(dto.getLocation());
30+
31+
// Collection mapping with null safety
32+
entity.setObjectives(dto.getObjectives() != null ? new ArrayList<>(dto.getObjectives()) : new ArrayList<>());
33+
34+
return entity;
35+
}
36+
37+
// Entity → DTO
38+
public static EventDetails toDto(EventDetailsEntity entity) {
39+
if (entity == null) {
40+
return null;
41+
}
42+
43+
EventDetails dto = new EventDetails();
44+
dto.setTheme(entity.getTheme());
45+
46+
// Enum conversion: Entity enum → API DTO enum
47+
if (entity.getFormat() != null) {
48+
dto.setFormat(EventDetails.FormatEnum.fromValue(entity.getFormat().name()));
49+
}
50+
51+
dto.setCapacity(entity.getCapacity());
52+
dto.setDuration(entity.getDuration());
53+
dto.setStartDate(entity.getStartDate());
54+
dto.setEndDate(entity.getEndDate());
55+
dto.setTargetAudience(entity.getTargetAudience());
56+
dto.setLocation(entity.getLocation());
57+
58+
// Collection mapping with null safety
59+
dto.setObjectives(entity.getObjectives() != null ? new ArrayList<>(entity.getObjectives()) : new ArrayList<>());
60+
61+
return dto;
62+
}
63+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package de.tum.aet.devops25.conceptsvc;
2+
3+
import de.tum.aet.devops25.api.generated.model.Pricing;
4+
5+
public class PricingMapper {
6+
7+
// DTO → Entity
8+
public static PricingEntity toEntity(Pricing dto) {
9+
if (dto == null) {
10+
return null;
11+
}
12+
13+
PricingEntity entity = new PricingEntity();
14+
entity.setCurrency(dto.getCurrency());
15+
entity.setEarlyBird(dto.getEarlyBird());
16+
entity.setRegular(dto.getRegular());
17+
entity.setVip(dto.getVip());
18+
entity.setStudent(dto.getStudent());
19+
entity.setGroup(dto.getGroup());
20+
return entity;
21+
}
22+
23+
// Entity → DTO
24+
public static Pricing toDto(PricingEntity entity) {
25+
if (entity == null) {
26+
return null;
27+
}
28+
29+
Pricing dto = new Pricing();
30+
dto.setCurrency(entity.getCurrency());
31+
dto.setEarlyBird(entity.getEarlyBird());
32+
dto.setRegular(entity.getRegular());
33+
dto.setVip(entity.getVip());
34+
dto.setStudent(entity.getStudent());
35+
dto.setGroup(entity.getGroup());
36+
return dto;
37+
}
38+
}

0 commit comments

Comments
 (0)