Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
4dd8f5c
Add MapStruct dependency
axlewin Sep 3, 2025
3625a2c
Add MapStruct annotation processor
axlewin Sep 3, 2025
678c4c8
Use MapStruct mapping for EventsFacade
axlewin Sep 10, 2025
5176ffc
Use MapStruct mapping for PagesFacade
axlewin Sep 10, 2025
8d5ba6a
Remove email addresses from UserSummaryDTOs in EventBookingDTOs
axlewin Sep 15, 2025
c9359d5
Use MapStruct mapping for UserAccountManager
axlewin Sep 15, 2025
2b9c5c8
Map `teacherAccountPending` from auth provider to local user
axlewin Sep 17, 2025
c5cc659
Add unimplemented mapping exception
axlewin Sep 17, 2025
efb7492
Use MapStruct mapping for GameManager
axlewin Sep 18, 2025
407e9af
Use MapStruct mapping for GameboardPersistenceManager
axlewin Sep 18, 2025
95d3557
Resolve merge conflicts
axlewin Sep 18, 2025
d0ddaf1
Fix gameManager initialisation
axlewin Sep 18, 2025
308e419
Use MapStruct mapping for GroupManager
axlewin Sep 19, 2025
3e46318
Use MapStruct mapping for PgQuizAttemptPersistenceManager
axlewin Sep 19, 2025
798fc1e
Use MapStruct mapping for PgAssignmentPersistenceManager
axlewin Sep 19, 2025
d0c7e93
Use MapStruct mapping for PgQuizAssignmentPersistenceManager
axlewin Sep 19, 2025
296a4d6
Remove unused orika imports
axlewin Sep 19, 2025
28e3ef9
Use MapStruct mapping for ContentSummarizerService
axlewin Sep 24, 2025
5247293
Use MapStruct mappings for QuestionManager
axlewin Sep 24, 2025
269af91
Use MapStruct mapping for QuizQuestionManager
axlewin Sep 24, 2025
fa93f20
Use MapStruct mapping for GitContentManager
axlewin Sep 24, 2025
0e05415
Replace remaining Orika usage in ContentMapper
axlewin Sep 25, 2025
e957613
Remove remaining Orika usage
axlewin Sep 25, 2025
7cf0f72
Remove Orika dependency
axlewin Sep 25, 2025
8073c1a
Rename content mappers
axlewin Sep 25, 2025
dbe1594
Add default Content to ContentDTO/Wildcard mapper
axlewin Sep 26, 2025
61c63b5
Set subclass exhaustive strategy to simplify ContentBase mappings
axlewin Sep 26, 2025
6738c4d
Rename GameboardMapper -> AssignmentMapper
axlewin Sep 26, 2025
39c9b28
Rename fields for consistency, update javadocs
axlewin Sep 26, 2025
c35b90d
Add remaining content subclass mappings
axlewin Sep 29, 2025
e81bbe2
Revert "Add remaining content subclass mappings"
axlewin Sep 29, 2025
2aeb4ad
Add missing content subclass mappings
axlewin Sep 30, 2025
067ee1c
Remove ignore annotations for specific fields
axlewin Sep 30, 2025
a475612
Ignore all unmapped target properties
axlewin Sep 30, 2025
f4cb150
Suppress unchecked cast warnings
axlewin Sep 30, 2025
600cdff
Simplify & rename mappings
axlewin Oct 1, 2025
b8c5422
Merge branch 'main' of https://github.com/isaacphysics/isaac-api into…
axlewin Oct 1, 2025
c81b269
Rename ContentSubclassMapper instances
axlewin Oct 1, 2025
06eedbe
Fix Checkstyle warnings in mappers
axlewin Oct 1, 2025
0bb6673
Fix Checkstyle warnings
axlewin Oct 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<ossindex.version>3.2.0</ossindex.version>
<swagger-core.version>2.2.34</swagger-core.version>
<jgit.version>6.10.1.202505221210-r</jgit.version>
<mapstruct.version>1.6.3</mapstruct.version>
<surefire.jacoco.args />
<failsafe.jacoco.args />
</properties>
Expand Down Expand Up @@ -139,12 +140,6 @@
<version>${jgit.version}</version>
</dependency>

<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
Expand Down Expand Up @@ -480,6 +475,12 @@
<version>4.3.1</version>
</dependency>

<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>

<!-- These two don't need to be included in the war package so their scope is "provided" which means we
promise to make them available in the deployment environment, but we aren't going to because they are
not needed at runtime anyway. -->
Expand Down Expand Up @@ -536,6 +537,13 @@
<version>3.10.1</version>
<configuration>
<release>11</release>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
Expand Down
25 changes: 14 additions & 11 deletions src/main/java/uk/ac/cam/cl/dtg/isaac/api/EventsFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.opencsv.CSVWriter;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import ma.glasnost.orika.MapperFacade;
import org.jboss.resteasy.annotations.GZIP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -66,6 +65,7 @@
import uk.ac.cam.cl.dtg.segue.search.AbstractFilterInstruction;
import uk.ac.cam.cl.dtg.segue.search.DateRangeFilterInstruction;
import uk.ac.cam.cl.dtg.util.AbstractConfigLoader;
import uk.ac.cam.cl.dtg.util.mappers.MainMapper;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.ws.rs.DELETE;
Expand Down Expand Up @@ -117,7 +117,7 @@ public class EventsFacade extends AbstractIsaacFacade {
private final UserAccountManager userAccountManager;
private final SchoolListReader schoolListReader;

private final MapperFacade mapper;
private final MainMapper mapper;

/**
* EventsFacade.
Expand All @@ -136,7 +136,7 @@ public EventsFacade(final AbstractConfigLoader properties, final ILogManager log
final UserAssociationManager userAssociationManager,
final GroupManager groupManager,
final UserAccountManager userAccountManager, final SchoolListReader schoolListReader,
final MapperFacade mapper) {
final MainMapper mapper) {
super(properties, logManager);
this.bookingManager = bookingManager;
this.userManager = userManager;
Expand Down Expand Up @@ -327,7 +327,7 @@ private ResultsWrapper<ContentDTO> getEventsReservedByUser(final HttpServletRequ
throws SegueDatabaseException, ContentManagerException {
List<ContentDTO> filteredResults = Lists.newArrayList();

List<EventBookingDTO> userReservationList = this.mapper.mapAsList(bookingManager.getAllEventReservationsForUser(currentUser.getId()), EventBookingDTO.class);
List<EventBookingDTO> userReservationList = this.mapper.map(bookingManager.getAllEventReservationsForUser(currentUser.getId()));

for (EventBookingDTO booking : userReservationList) {

Expand Down Expand Up @@ -565,7 +565,7 @@ public final Response getEventBookingForGivenGroup(@Context final HttpServletReq
eventBookings = userAssociationManager.filterUnassociatedRecords(currentUser, eventBookings,
booking -> booking.getUserBooked().getId());

return Response.ok(this.mapper.mapAsList(eventBookings, EventBookingDTO.class)).build();
return Response.ok(this.mapper.copy(eventBookings)).build();
} catch (SegueDatabaseException e) {
String errorMsg = String.format(
"Database error occurred while trying retrieve bookings for group (%s) on event (%s).",
Expand Down Expand Up @@ -598,12 +598,15 @@ public final Response getEventBookingForAllGroups(@Context final HttpServletRequ
return new SegueErrorResponse(Status.FORBIDDEN, "You do not have permission to use this endpoint.").toResponse();
}

List<EventBookingDTO> eventBookings = this.mapper.mapAsList(bookingManager.getBookingsByEventId(eventId), EventBookingDTO.class);
List<EventBookingDTO> eventBookings = this.mapper.map(bookingManager.getBookingsByEventId(eventId));

// Only allowed to see the bookings of connected users
eventBookings = userAssociationManager.filterUnassociatedRecords(
currentUser, eventBookings, booking -> booking.getUserBooked().getId());

eventBookings.forEach(booking -> booking.setUserBooked(mapper.map(booking.getUserBooked(),
UserSummaryDTO.class)));

return Response.ok(eventBookings).build();
} catch (NoUserLoggedInException e) {
return SegueErrorResponse.getNotLoggedInResponse();
Expand Down Expand Up @@ -778,7 +781,7 @@ public final Response createBookingForGivenUser(@Context final HttpServletReques
ADMIN_BOOKING_REASON_FIELDNAME, additionalInformation.get("authorisation") == null ? "NOT_PROVIDED" : additionalInformation.get("authorisation")
));

return Response.ok(this.mapper.map(booking, EventBookingDTO.class)).build();
return Response.ok(this.mapper.copy(booking)).build();
} catch (NoUserLoggedInException e) {
return SegueErrorResponse.getNotLoggedInResponse();
} catch (SegueDatabaseException e) {
Expand Down Expand Up @@ -859,7 +862,7 @@ public final Response createReservationsForGivenUsers(@Context final HttpServlet
USER_ID_LIST_FKEY_FIELDNAME, userIds.toArray(),
BOOKING_STATUS_FIELDNAME, BookingStatus.RESERVED.toString()
));
return Response.ok(this.mapper.mapAsList(bookings, EventBookingDTO.class)).build();
return Response.ok(this.mapper.copy(bookings)).build();

} catch (NoUserLoggedInException e) {
return SegueErrorResponse.getNotLoggedInResponse();
Expand Down Expand Up @@ -1017,7 +1020,7 @@ public final Response createBookingForMe(@Context final HttpServletRequest reque
this.getLogManager().logEvent(userManager.getCurrentUser(request), request,
SegueServerLogType.EVENT_BOOKING, ImmutableMap.of(EVENT_ID_FKEY_FIELDNAME, event.getId()));

return Response.ok(this.mapper.map(eventBookingDTO, EventBookingDTO.class)).build();
return Response.ok(this.mapper.copy(eventBookingDTO)).build();
} catch (NoUserLoggedInException e) {
return SegueErrorResponse.getNotLoggedInResponse();
} catch (SegueDatabaseException e) {
Expand Down Expand Up @@ -1072,7 +1075,7 @@ public final Response addMeToWaitingList(@Context final HttpServletRequest reque
this.getLogManager().logEvent(userManager.getCurrentUser(request), request,
SegueServerLogType.EVENT_WAITING_LIST_BOOKING, ImmutableMap.of(EVENT_ID_FKEY_FIELDNAME, event.getId()));

return Response.ok(this.mapper.map(eventBookingDTO, EventBookingDTO.class)).build();
return Response.ok(this.mapper.copy(eventBookingDTO)).build();
} catch (NoUserLoggedInException e) {
return SegueErrorResponse.getNotLoggedInResponse();
} catch (SegueDatabaseException e) {
Expand Down Expand Up @@ -1608,7 +1611,7 @@ private IsaacEventPageDTO getRawEventDTOById(final String eventId)
// The Events Facade *mutates* the EventDTO returned by this method; we must return a copy of
// the original object else we will poison the contentManager's cache!
// TODO: might it be better to get the DO from the cache and map it to DTO here to reduce overhead?
return mapper.map(possibleEvent, IsaacEventPageDTO.class);
return (IsaacEventPageDTO) mapper.copy(possibleEvent);
}
return null;
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/uk/ac/cam/cl/dtg/isaac/api/PagesFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import com.google.inject.Inject;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import ma.glasnost.orika.MapperFacade;
import org.jboss.resteasy.annotations.GZIP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -60,6 +59,7 @@
import uk.ac.cam.cl.dtg.segue.dao.content.ContentManagerException;
import uk.ac.cam.cl.dtg.segue.dao.content.GitContentManager;
import uk.ac.cam.cl.dtg.util.AbstractConfigLoader;
import uk.ac.cam.cl.dtg.util.mappers.MainMapper;

import jakarta.annotation.Nullable;
import jakarta.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -102,7 +102,7 @@ public class PagesFacade extends AbstractIsaacFacade {
private static final Logger log = LoggerFactory.getLogger(PagesFacade.class);

private final ContentService api;
private final MapperFacade mapper;
private final MainMapper mapper;
private final UserAccountManager userManager;
private final URIManager uriManager;
private final QuestionManager questionManager;
Expand Down Expand Up @@ -134,7 +134,7 @@ public class PagesFacade extends AbstractIsaacFacade {
*/
@Inject
public PagesFacade(final ContentService api, final AbstractConfigLoader propertiesLoader,
final ILogManager logManager, final MapperFacade mapper, final GitContentManager contentManager,
final ILogManager logManager, final MainMapper mapper, final GitContentManager contentManager,
final UserAccountManager userManager, final URIManager uriManager,
final QuestionManager questionManager, final GameManager gameManager,
final UserAttemptManager userAttemptManager) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import com.google.api.client.util.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.collections4.comparators.ComparatorChain;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.ImmutablePair;
Expand Down Expand Up @@ -56,10 +55,11 @@
import uk.ac.cam.cl.dtg.segue.dao.SegueDatabaseException;
import uk.ac.cam.cl.dtg.segue.dao.content.ContentManagerException;
import uk.ac.cam.cl.dtg.segue.dao.content.GitContentManager;
import uk.ac.cam.cl.dtg.util.AbstractConfigLoader;
import uk.ac.cam.cl.dtg.util.mappers.MainMapper;

import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotNull;
import uk.ac.cam.cl.dtg.util.AbstractConfigLoader;

import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -93,7 +93,7 @@ public class GameManager {

private final GameboardPersistenceManager gameboardPersistenceManager;
private final Random randomGenerator;
private final MapperFacade mapper;
private final MainMapper mapper;
private final GitContentManager contentManager;
private final QuestionManager questionManager;

Expand All @@ -111,7 +111,7 @@ public class GameManager {
*/
@Inject
public GameManager(final GitContentManager contentManager,
final GameboardPersistenceManager gameboardPersistenceManager, final MapperFacade mapper,
final GameboardPersistenceManager gameboardPersistenceManager, final MainMapper mapper,
final QuestionManager questionManager,
final AbstractConfigLoader properties) {
this.contentManager = contentManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@
import uk.ac.cam.cl.dtg.segue.api.managers.QuestionManager;
import uk.ac.cam.cl.dtg.segue.dao.SegueDatabaseException;
import uk.ac.cam.cl.dtg.segue.dao.content.ContentManagerException;
import uk.ac.cam.cl.dtg.segue.dao.content.ContentMapper;
import uk.ac.cam.cl.dtg.isaac.dos.QuestionValidationResponse;
import uk.ac.cam.cl.dtg.isaac.dos.content.Choice;
import uk.ac.cam.cl.dtg.isaac.dos.content.DTOMapping;
import uk.ac.cam.cl.dtg.isaac.dos.content.Question;
import uk.ac.cam.cl.dtg.isaac.dto.QuestionValidationResponseDTO;
import uk.ac.cam.cl.dtg.isaac.dto.SegueErrorResponse;
import uk.ac.cam.cl.dtg.isaac.dto.content.ChoiceDTO;
import uk.ac.cam.cl.dtg.isaac.dto.content.QuestionDTO;
import uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO;
import uk.ac.cam.cl.dtg.util.mappers.MainMapper;

import jakarta.annotation.Nullable;
import jakarta.ws.rs.core.Response;
Expand All @@ -58,7 +56,7 @@

public class QuizQuestionManager {
private final QuestionManager questionManager;
private final ContentMapper mapper;
private final MainMapper mapper;
private final IQuizQuestionAttemptPersistenceManager quizQuestionAttemptManager;
private final QuizManager quizManager;
private final QuizAttemptManager quizAttemptManager;
Expand All @@ -83,7 +81,7 @@ public class QuizQuestionManager {
* - for attempts, particularly checking attempts are completed before revealing feedback.
*/
@Inject
public QuizQuestionManager(final QuestionManager questionManager, final ContentMapper mapper,
public QuizQuestionManager(final QuestionManager questionManager, final MainMapper mapper,
final IQuizQuestionAttemptPersistenceManager quizQuestionAttemptManager,
final QuizManager quizManager, final QuizAttemptManager quizAttemptManager) {
this.questionManager = questionManager;
Expand All @@ -109,7 +107,7 @@ public QuestionValidationResponseDTO validateAnswer(Question question, ChoiceDTO
}

public void recordQuestionAttempt(QuizAttemptDTO quizAttempt, QuestionValidationResponseDTO questionResponse) throws SegueDatabaseException {
QuestionValidationResponse questionResponseDO = this.mapper.getAutoMapper().map(questionResponse, QuestionValidationResponse.class);
QuestionValidationResponse questionResponseDO = this.mapper.map(questionResponse);

this.quizQuestionAttemptManager.registerQuestionAttempt(quizAttempt.getId(), questionResponseDO);
}
Expand Down Expand Up @@ -301,11 +299,8 @@ void augmentQuestionObjectWithAttemptInformation(Map<QuestionDTO, QuestionValida
lastAttempt = questionManager.convertQuestionValidationResponseToDTO(lastResponse);
} else {
// Manual extract only the safe details (questionId, answer).
Choice answer = lastResponse.getAnswer();
lastAttempt = new QuestionValidationResponseDTO();
DTOMapping dtoMapping = answer.getClass().getAnnotation(DTOMapping.class);
lastAttempt.setAnswer(mapper.getAutoMapper().map(lastResponse.getAnswer(),
(Class<? extends ChoiceDTO>) dtoMapping.value()));
lastAttempt.setAnswer(mapper.map(lastResponse.getAnswer()));
lastAttempt.setQuestionId(lastResponse.getQuestionId());
}
lastAttempt.setDateAttempted(null); // Strip timestamps, since quiz responses may be seen by other users.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@
package uk.ac.cam.cl.dtg.isaac.api.services;

import com.google.inject.Inject;
import ma.glasnost.orika.MapperFacade;
import uk.ac.cam.cl.dtg.isaac.api.managers.URIManager;
import uk.ac.cam.cl.dtg.isaac.dto.ResultsWrapper;
import uk.ac.cam.cl.dtg.isaac.dto.content.ContentDTO;
import uk.ac.cam.cl.dtg.isaac.dto.content.ContentSummaryDTO;
import uk.ac.cam.cl.dtg.util.mappers.ContentMapper;

import java.util.ArrayList;

public class ContentSummarizerService {
protected final MapperFacade mapper;
protected final ContentMapper mapper;
private final URIManager uriManager;

@Inject
public ContentSummarizerService(final MapperFacade mapper, final URIManager uriManager) {
public ContentSummarizerService(final ContentMapper mapper, final URIManager uriManager) {
this.mapper = mapper;
this.uriManager = uriManager;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import ma.glasnost.orika.MapperFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.cam.cl.dtg.isaac.dos.GameboardContentDescriptor;
Expand All @@ -40,9 +39,10 @@
import uk.ac.cam.cl.dtg.segue.api.Constants;
import uk.ac.cam.cl.dtg.segue.dao.SegueDatabaseException;
import uk.ac.cam.cl.dtg.segue.dao.content.ContentManagerException;
import uk.ac.cam.cl.dtg.segue.dao.content.ContentMapper;
import uk.ac.cam.cl.dtg.segue.dao.content.ContentSubclassMapper;
import uk.ac.cam.cl.dtg.segue.dao.content.GitContentManager;
import uk.ac.cam.cl.dtg.segue.database.PostgresSqlDb;
import uk.ac.cam.cl.dtg.util.mappers.MainMapper;

import jakarta.annotation.Nullable;
import java.io.IOException;
Expand Down Expand Up @@ -81,7 +81,7 @@ public class GameboardPersistenceManager {
private final PostgresSqlDb database;
private final Cache<String, GameboardDO> gameboardNonPersistentStorage;

private final MapperFacade mapper; // used for content object mapping.
private final MainMapper mapper; // used for content object mapping.
private final ObjectMapper objectMapper; // used for json serialisation

private final GitContentManager contentManager;
Expand All @@ -100,7 +100,7 @@ public class GameboardPersistenceManager {
*/
@Inject
public GameboardPersistenceManager(final PostgresSqlDb database, final GitContentManager contentManager,
final MapperFacade mapper, final ContentMapper objectMapper) {
final MainMapper mapper, final ContentSubclassMapper objectMapper) {
this.database = database;
this.mapper = mapper;
this.contentManager = contentManager;
Expand Down Expand Up @@ -189,7 +189,7 @@ public String temporarilyStoreGameboard(final GameboardDTO gameboard) {
*/
public String saveGameboardToPermanentStorage(final GameboardDTO gameboard)
throws SegueDatabaseException {
GameboardDO gameboardToSave = mapper.map(gameboard, GameboardDO.class);
GameboardDO gameboardToSave = mapper.map(gameboard);
// the mapping operation won't work for the list so we should just
// create a new one.
gameboardToSave.setContents(Lists.newArrayList());
Expand Down Expand Up @@ -601,7 +601,7 @@ private List<GameboardDTO> convertToGameboardDTOs(final List<GameboardDO> gamebo
List<GameboardDTO> gameboardDTOs = Lists.newArrayList();

for (GameboardDO gameboardDO : gameboardDOs) {
GameboardDTO gameboardDTO = mapper.map(gameboardDO, GameboardDTO.class);
GameboardDTO gameboardDTO = mapper.map(gameboardDO);
List<GameboardItem> sparseGameboardItems = gameboardDO.getContents().stream()
.map(GameboardItem::buildLightweightItemFromContentDescriptor)
.collect(Collectors.toList());
Expand Down Expand Up @@ -640,7 +640,7 @@ private GameboardDTO convertToGameboardDTO(final GameboardDO gameboardDO, final
* @return GameboardDO.
*/
private GameboardDO convertToGameboardDO(final GameboardDTO gameboardDTO) {
GameboardDO gameboardDO = mapper.map(gameboardDTO, GameboardDO.class);
GameboardDO gameboardDO = mapper.map(gameboardDTO);
// the mapping operation won't work for the list so we should just
// create a new one.
gameboardDO.setContents(Lists.newArrayList());
Expand Down
Loading
Loading