Skip to content
Snippets Groups Projects
Commit c09b32bd authored by Jan Pokorný's avatar Jan Pokorný :lifter_tone2:
Browse files

Merge branch 'main' into 'M3-data-initialization'

# Conflicts:
#   application/module-language-school/src/main/java/org/fuseri/modulelanguageschool/course/Course.java
parents 45b43706 8cb05668
No related branches found
No related tags found
1 merge request!34M3 data initialization
Pipeline #
Showing
with 343 additions and 99 deletions
package org.fuseri.modulecertificate.service;
package org.fuseri.modulecertificate.certificate;
import org.fuseri.modulecertificate.Certificate;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
......
package org.fuseri.modulecertificate.service;
package org.fuseri.modulecertificate.certificate;
import org.fuseri.modulecertificate.Certificate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
......
package org.fuseri.modulecertificate.exceptions;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.ToString;
import org.springframework.http.HttpStatus;
import java.time.Clock;
import java.time.LocalDateTime;
import java.util.List;
@Getter
@ToString
class ApiError {
private HttpStatus status;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
private LocalDateTime timestamp;
private String message;
private List<ApiSubError> subErrors;
private String path;
private ApiError() {
timestamp = LocalDateTime.now(Clock.systemUTC());
}
ApiError(HttpStatus status, Throwable ex, String path) {
this();
this.status = status;
this.path = path;
this.message = ex.getLocalizedMessage();
}
ApiError(HttpStatus status, List<ApiSubError> subErrors, Throwable ex, String path) {
this();
this.status = status;
this.subErrors = subErrors;
this.path = path;
this.message = ex.getLocalizedMessage();
}
}
package org.fuseri.modulecertificate.exceptions;
public interface ApiSubError {
}
package org.fuseri.modulecertificate.exceptions;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@Getter
@ToString
class ApiValidationError implements ApiSubError {
private String object;
private String field;
private Object rejectedValue;
private String message;
}
package org.fuseri.modulecertificate.exceptions;
import jakarta.persistence.EntityNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.util.UrlPathHelper;
import java.util.List;
@ControllerAdvice
public class RestResponseEntityExceptionHandler {
private static final UrlPathHelper URL_PATH_HELPER = new UrlPathHelper();
/**
* Handle ResourceNotFoundException exceptions
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {EntityNotFoundException.class})
public ResponseEntity<ApiError> handleNotFoundError(EntityNotFoundException ex, HttpServletRequest request) {
ApiError error = new ApiError(
HttpStatus.NOT_FOUND,
ex,
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
/**
* Handle Validation exceptions
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {MethodArgumentNotValidException.class, HttpMessageNotReadableException.class})
public ResponseEntity<ApiError> handleValidationErrors(MethodArgumentNotValidException ex, HttpServletRequest request) {
List<ApiSubError> subErrors = ex.getBindingResult().getFieldErrors()
.stream()
.map(e -> (ApiSubError) new ApiValidationError(e.getObjectName(), e.getField(), e.getRejectedValue(), e.getDefaultMessage()))
.toList();
ApiError error = new ApiError(
HttpStatus.BAD_REQUEST,
subErrors,
ex,
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
/**
* Handle exceptions not matched by above handler methods
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler({Exception.class})
public ResponseEntity<ApiError> handleAll(final Exception ex, HttpServletRequest request) {
final ApiError error = new ApiError(
HttpStatus.INTERNAL_SERVER_ERROR,
ExceptionUtils.getRootCause(ex),
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
return new ResponseEntity<>(apiError, apiError.getStatus());
}
}
package org.fuseri.modulecertificate.service;
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException() {
}
public ResourceNotFoundException(String message) {
super(message);
}
public ResourceNotFoundException(String message, Throwable cause) {
super(message, cause);
}
public ResourceNotFoundException(Throwable cause) {
super(cause);
}
public ResourceNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
......@@ -3,13 +3,13 @@ package org.fuseri.modulecertificate;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.fuseri.model.dto.certificate.CertificateCreateDto;
import org.fuseri.model.dto.certificate.CertificateSimpleDto;
import org.fuseri.model.dto.course.CourseDto;
import org.fuseri.model.dto.course.CourseCertificateDto;
import org.fuseri.model.dto.course.LanguageTypeDto;
import org.fuseri.model.dto.course.ProficiencyLevelDto;
import org.fuseri.model.dto.user.AddressDto;
import org.fuseri.model.dto.user.UserDto;
import org.fuseri.model.dto.user.UserType;
import org.fuseri.modulecertificate.service.CertificateFacade;
import org.fuseri.modulecertificate.certificate.CertificateFacade;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
......@@ -24,6 +24,7 @@ import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
......@@ -35,8 +36,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
class CertificateControllerTests {
private final UserDto USER = new UserDto("novakovat",
"novakova@gamil.com", "Tereza", "Nováková", new AddressDto(), UserType.STUDENT);
private final CourseDto COURSE = new CourseDto("AJ1", 10,
"novakova@gamil.com", "Tereza", "Nováková",
new AddressDto("USA", "New York", "Main Street", "123", "10001"),
UserType.STUDENT, new HashMap<>());
private final CourseCertificateDto COURSE = new CourseCertificateDto("AJ1", 10,
LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1);
private final CertificateCreateDto certificateCreateDto = new CertificateCreateDto(USER, COURSE);
private final CertificateSimpleDto certificateDto = new CertificateSimpleDto(0L, USER.getId(),
......@@ -56,9 +59,26 @@ class CertificateControllerTests {
}
}
@Test
void generateCertificate() throws Exception {
Mockito.when(certificateFacade.generate(ArgumentMatchers.any(CertificateCreateDto.class)))
.thenReturn(certificateDto);
mockMvc.perform(post("/certificates")
.content(asJsonString(certificateCreateDto))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is2xxSuccessful())
.andExpect(jsonPath("$.id").value(certificateDto.getId()))
.andExpect(jsonPath("$.userId").value(certificateDto.getUserId()))
.andExpect(jsonPath("$.generatedAt").value(certificateDto.getGeneratedAt().toString()))
.andExpect(jsonPath("$.courseId").value(certificateDto.getCourseId()))
.andExpect(jsonPath("$.certificateFile").value(certificateDto.getCertificateFile()))
.andExpect(jsonPath("$.certificateFileName").value(certificateDto.getCertificateFileName()));
}
@Test
void generateCertificateWithNullUser() throws Exception {
mockMvc.perform(post("/certificates/generate")
mockMvc.perform(post("/certificates")
.content(asJsonString(new CertificateCreateDto(null, COURSE)))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is4xxClientError());
......@@ -66,7 +86,7 @@ class CertificateControllerTests {
@Test
void generateCertificateWithNullCourse() throws Exception {
mockMvc.perform(post("/certificates/generate")
mockMvc.perform(post("/certificates")
.content(asJsonString(new CertificateCreateDto(USER, null)))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is4xxClientError());
......@@ -74,7 +94,7 @@ class CertificateControllerTests {
@Test
void generateCertificateWithoutParams() throws Exception {
mockMvc.perform(post("/certificates/generate")
mockMvc.perform(post("/certificates")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is4xxClientError());
}
......@@ -107,7 +127,7 @@ class CertificateControllerTests {
@Test
void findCertificatesWithoutUserId() throws Exception {
mockMvc.perform(get("/certificates/findForUser"))
.andExpect(status().is4xxClientError());
.andExpect(status().is5xxServerError());
}
@Test
......@@ -128,20 +148,20 @@ class CertificateControllerTests {
void findCertificateIdWithoutUserId() throws Exception {
mockMvc.perform(get("/certificates/findForUserAndCourse")
.param("courseId", "0"))
.andExpect(status().is4xxClientError());
.andExpect(status().is5xxServerError());
}
@Test
void findCertificateIdWithoutCourseId() throws Exception {
mockMvc.perform(get("/certificates/findForUserAndCourse")
.param("userId", "0"))
.andExpect(status().is4xxClientError());
.andExpect(status().is5xxServerError());
}
@Test
void findCertificateIdWithoutParams() throws Exception {
mockMvc.perform(get("/certificates/findForUserAndCourse"))
.andExpect(status().is4xxClientError());
.andExpect(status().is5xxServerError());
}
@Test
......
......@@ -2,15 +2,16 @@ package org.fuseri.modulecertificate;
import org.fuseri.model.dto.certificate.CertificateCreateDto;
import org.fuseri.model.dto.certificate.CertificateSimpleDto;
import org.fuseri.model.dto.course.CourseDto;
import org.fuseri.model.dto.course.CourseCertificateDto;
import org.fuseri.model.dto.course.LanguageTypeDto;
import org.fuseri.model.dto.course.ProficiencyLevelDto;
import org.fuseri.model.dto.user.AddressDto;
import org.fuseri.model.dto.user.UserDto;
import org.fuseri.model.dto.user.UserType;
import org.fuseri.modulecertificate.service.CertificateFacade;
import org.fuseri.modulecertificate.service.CertificateMapper;
import org.fuseri.modulecertificate.service.CertificateService;
import org.fuseri.modulecertificate.certificate.Certificate;
import org.fuseri.modulecertificate.certificate.CertificateFacade;
import org.fuseri.modulecertificate.certificate.CertificateMapper;
import org.fuseri.modulecertificate.certificate.CertificateService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
......@@ -34,7 +35,7 @@ import static org.mockito.Mockito.when;
final class CertificateFacadeTests {
private final UserDto USER = new UserDto("novakovat",
"novakova@gamil.com", "Tereza", "Nováková", new AddressDto(), UserType.STUDENT);
private final CourseDto COURSE = new CourseDto("AJ1", 10,
private final CourseCertificateDto COURSE = new CourseCertificateDto("AJ1", 10,
LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1);
private final CertificateCreateDto certificateCreateDto = new CertificateCreateDto(USER, COURSE);
private final CertificateSimpleDto certificateDto = new CertificateSimpleDto(0L, USER.getId(),
......
......@@ -2,13 +2,14 @@ package org.fuseri.modulecertificate;
import org.fuseri.model.dto.certificate.CertificateCreateDto;
import org.fuseri.model.dto.certificate.CertificateSimpleDto;
import org.fuseri.model.dto.course.CourseDto;
import org.fuseri.model.dto.course.CourseCertificateDto;
import org.fuseri.model.dto.course.LanguageTypeDto;
import org.fuseri.model.dto.course.ProficiencyLevelDto;
import org.fuseri.model.dto.user.AddressDto;
import org.fuseri.model.dto.user.UserDto;
import org.fuseri.model.dto.user.UserType;
import org.fuseri.modulecertificate.service.CertificateMapper;
import org.fuseri.modulecertificate.certificate.Certificate;
import org.fuseri.modulecertificate.certificate.CertificateMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -26,7 +27,7 @@ final class CertificateMapperTests {
private final UserDto USER = new UserDto("novakovat",
"novakova@gamil.com", "Tereza", "Nováková", new AddressDto(), UserType.STUDENT);
private final CourseDto COURSE = new CourseDto("AJ1", 10,
private final CourseCertificateDto COURSE = new CourseCertificateDto("AJ1", 10,
LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1);
private final Instant instant = Instant.now();
private final String fileName = "fileName";
......
package org.fuseri.modulecertificate;
import org.fuseri.modulecertificate.service.CertificateRepository;
import org.fuseri.modulecertificate.certificate.Certificate;
import org.fuseri.modulecertificate.certificate.CertificateRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
......
......@@ -6,8 +6,9 @@ import org.fuseri.model.dto.course.ProficiencyLevelDto;
import org.fuseri.model.dto.user.AddressDto;
import org.fuseri.model.dto.user.UserDto;
import org.fuseri.model.dto.user.UserType;
import org.fuseri.modulecertificate.service.CertificateRepository;
import org.fuseri.modulecertificate.service.CertificateService;
import org.fuseri.modulecertificate.certificate.Certificate;
import org.fuseri.modulecertificate.certificate.CertificateRepository;
import org.fuseri.modulecertificate.certificate.CertificateService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
......
......@@ -3,7 +3,6 @@ package org.fuseri.moduleexercise.answer;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.persistence.EntityNotFoundException;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.fuseri.model.dto.exercise.AnswerCreateDto;
......@@ -49,11 +48,7 @@ public class AnswerController {
})
@PostMapping
public ResponseEntity<AnswerDto> create(@Valid @RequestBody AnswerCreateDto dto) {
try {
return ResponseEntity.status(HttpStatus.CREATED).body(facade.create(dto));
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.status(HttpStatus.CREATED).body(facade.create(dto));
}
/**
......@@ -72,11 +67,7 @@ public class AnswerController {
})
@PutMapping("/{id}")
public ResponseEntity<AnswerDto> update(@NotNull @PathVariable long id, @Valid @RequestBody AnswerCreateDto dto) {
try {
return ResponseEntity.ok(facade.update(id, dto));
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(facade.update(id, dto));
}
/**
......@@ -92,11 +83,7 @@ public class AnswerController {
})
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@NotNull @PathVariable long id) {
try {
facade.delete(id);
return ResponseEntity.noContent().build();
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
facade.delete(id);
return ResponseEntity.noContent().build();
}
}
......@@ -7,7 +7,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* Represent a service for managing Answer entities
......@@ -31,21 +30,6 @@ public class AnswerService extends DomainService<Answer> {
this.repository = repository;
}
/**
* Retrieve a list of Answer entities with the specified question ID
*
* @param questionId the ID of the question to retrieve answers for
* @return a list of Answer entities with the specified question ID
* @throws EntityNotFoundException if question with questionId does not exist
*/
@Transactional(readOnly = true)
public List<Answer> findAllByQuestionId(long questionId) {
if (!getRepository().existsById(questionId)) {
throw new EntityNotFoundException("Question with id " + questionId + " not found.");
}
return repository.findByQuestionId(questionId);
}
/**
* Retrieve the Answer entity with the specified id
*
......
package org.fuseri.moduleexercise.exceptions;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.ToString;
import org.springframework.http.HttpStatus;
import java.time.Clock;
import java.time.LocalDateTime;
import java.util.List;
@Getter
@ToString
class ApiError {
private HttpStatus status;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
private LocalDateTime timestamp;
private String message;
private List<ApiSubError> subErrors;
private String path;
private ApiError() {
timestamp = LocalDateTime.now(Clock.systemUTC());
}
ApiError(HttpStatus status, Throwable ex, String path) {
this();
this.status = status;
this.path = path;
this.message = ex.getLocalizedMessage();
}
ApiError(HttpStatus status, List<ApiSubError> subErrors, Throwable ex, String path) {
this();
this.status = status;
this.subErrors = subErrors;
this.path = path;
this.message = ex.getLocalizedMessage();
}
}
\ No newline at end of file
package org.fuseri.moduleexercise.exceptions;
interface ApiSubError {
}
package org.fuseri.moduleexercise.exceptions;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@Getter
@ToString
class ApiValidationError implements ApiSubError {
private String object;
private String field;
private Object rejectedValue;
private String message;
}
\ No newline at end of file
package org.fuseri.moduleexercise.exceptions;
import jakarta.persistence.EntityNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.util.UrlPathHelper;
import java.util.List;
@ControllerAdvice
public class RestResponseEntityExceptionHandler {
private static final UrlPathHelper URL_PATH_HELPER = new UrlPathHelper();
/**
* Handle ResourceNotFoundException exceptions
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {EntityNotFoundException.class})
public ResponseEntity<ApiError> handleNotFoundError(EntityNotFoundException ex, HttpServletRequest request) {
ApiError error = new ApiError(
HttpStatus.NOT_FOUND,
ex,
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
/**
* Handle Validation exceptions
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler(value = {MethodArgumentNotValidException.class, HttpMessageNotReadableException.class})
public ResponseEntity<ApiError> handleValidationErrors(MethodArgumentNotValidException ex, HttpServletRequest request) {
List<ApiSubError> subErrors = ex.getBindingResult().getFieldErrors()
.stream()
.map(e -> (ApiSubError) new ApiValidationError(e.getObjectName(), e.getField(), e.getRejectedValue(), e.getDefaultMessage()))
.toList();
ApiError error = new ApiError(
HttpStatus.BAD_REQUEST,
subErrors,
ex,
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
/**
* Handle exceptions not matched by above handler methods
*
* @param ex exception
* @param request request
* @return response entity
*/
@ExceptionHandler({Exception.class})
public ResponseEntity<ApiError> handleAll(final Exception ex, HttpServletRequest request) {
final ApiError error = new ApiError(
HttpStatus.INTERNAL_SERVER_ERROR,
ExceptionUtils.getRootCause(ex),
URL_PATH_HELPER.getRequestUri(request));
return buildResponseEntity(error);
}
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
return new ResponseEntity<>(apiError, apiError.getStatus());
}
}
\ No newline at end of file
......@@ -3,7 +3,6 @@ package org.fuseri.moduleexercise.exercise;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.persistence.EntityNotFoundException;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
......@@ -75,11 +74,7 @@ public class ExerciseController {
})
@GetMapping("/{id}")
public ResponseEntity<ExerciseDto> find(@NotNull @PathVariable long id) {
try {
return ResponseEntity.ok(facade.find(id));
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(facade.find(id));
}
/**
......@@ -135,12 +130,8 @@ public class ExerciseController {
@GetMapping("/{exercise-id}/questions")
public ResponseEntity<Page<QuestionDto>> findQuestions(@NotNull @PathVariable("exercise-id") long exerciseId,
@PositiveOrZero @RequestParam int page) {
try {
Page<QuestionDto> questions = facade.getQuestions(exerciseId, page);
return ResponseEntity.ok(questions);
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
Page<QuestionDto> questions = facade.getQuestions(exerciseId, page);
return ResponseEntity.ok(questions);
}
/**
......@@ -159,11 +150,7 @@ public class ExerciseController {
})
@PutMapping("/{id}")
public ResponseEntity<ExerciseDto> update(@NotNull @PathVariable long id, @Valid @RequestBody ExerciseCreateDto dto) {
try {
return ResponseEntity.ok(facade.update(id, dto));
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(facade.update(id, dto));
}
/**
......
......@@ -2,6 +2,7 @@ package org.fuseri.moduleexercise.question;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
......@@ -35,7 +36,7 @@ public class Question extends DomainObject {
@OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Answer> answers = new HashSet<>();
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "exercise_id", nullable = false)
private Exercise exercise;
......@@ -46,5 +47,8 @@ public class Question extends DomainObject {
*/
public void addAnswers(Set<Answer> answersToAdd) {
answers.addAll(answersToAdd);
for (var answer : answersToAdd) {
answer.setQuestion(this);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment