So my problem is updating Subjects in Class, I get an exception. What do you think may be the reason and can you explain how can I solve my problem (for dummies, please). I was thinking changing modelmapper config but I will always have the subjects in my classes and classes in my subjects that way and the problem persists. But on the other hand I prefer to leave the relationship like so (not to create SQL with joins - I prefer using FKs). But in the end the question still exists - how do you propose I solved this problem? Thanks in advance!
@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "classes")
public class Class {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
private String name;
@OneToOne(mappedBy = "myClass")
private Teacher headTeacher;
@OneToMany
private List<Student> students;
@OneToMany(mappedBy = "myClass")
private List<Subject> subjects;
@Builder
private Class(final Long id,
final String name,
final Teacher headTeacher,
final List<Student> students,
final List<Subject> subjects){
checkArgument(!Strings.isNullOrEmpty(name), "name cannot be null or empty");
checkArgument(headTeacher != null, "headTeacher cannot be null");
this.id = id;
this.name = name;
this.headTeacher = headTeacher;
this.students = students;
this.subjects = subjects;
}
}
@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "subjects")
@ToString(exclude = "myClass")
@EqualsAndHashCode(exclude = "myClass")
public class Subject {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne
private Teacher teacher;
@ManyToMany
private Set<Teacher> replacingTeachers;
@ManyToOne
@JoinColumn(name = "class_id")
private Class myClass;
@Builder
private Subject(final Long id,
final String name,
final Teacher teacher,
final Set<Teacher> replacingTeachers,
final Class myClass){
checkArgument(!Strings.isNullOrEmpty(name), "name cannot be null or empty");
checkArgument(teacher != null, "teacher cannot be null");
this.id = id;
this.name = name;
this.teacher = teacher;
this.replacingTeachers = replacingTeachers;
this.myClass = myClass;
}
}
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ClassDto {
private Long id;
@NotBlank
private String name;
private TeacherDto headTeacher;
private List<StudentDto> students;
@JsonManagedReference
private List<SubjectDto> subjects;
@Builder
@JsonCreator
private ClassDto(@JsonProperty("id") final Long id,
@JsonProperty("name") final String name,
@JsonProperty("headTeacher") final TeacherDto headTeacher,
@JsonProperty("students") final List<StudentDto> students,
@JsonProperty("subjects") final List<SubjectDto> subjects){
this.id = id;
this.name = name;
this.headTeacher = headTeacher;
this.students = students;
this.subjects = subjects;
}
}
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@ToString(exclude = "myClass")
@EqualsAndHashCode(exclude = "myClass")
public class SubjectDto {
private Long id;
@NotBlank
private String name;
@NotNull
private TeacherDto teacher;
private Set<TeacherDto> replacingTeachers;
@JsonBackReference
private ClassDto myClass;
@Builder
@JsonCreator
private SubjectDto(@JsonProperty("id") final Long id,
@JsonProperty("name") final String name,
@JsonProperty("teacher") final TeacherDto teacher,
@JsonProperty("replacingTeachers") final Set<TeacherDto> replacingTeachers,
@JsonProperty("myClass") final ClassDto myClass){
this.id = id;
this.name = name;
this.teacher = teacher;
this.replacingTeachers = replacingTeachers;
this.myClass = myClass;
}
}
@Transactional
public ClassDto update(final ClassDto classDto) throws NoSuchElementException {
log.info("Altering class: " + classDto.toString());
Class aClass = repository.findById(classDto.getId())
.orElseThrow(() -> new NoSuchElementException("No class with id " + classDto.getId() + " was found"));
modelMapper.map(classDto, aClass);
return modelMapper.map(repository.save(aClass), ClassDto.class);
}
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.modelmapper.MappingException: ModelMapper mapping errors:
1) Converter org.modelmapper.internal.converter.MergingCollectionConverter@1cf94666 failed to convert java.util.ArrayList to java.util.List.
1 error] with root cause
org.modelmapper.ConfigurationException: ModelMapper configuration errors:
1) The destination property io.soft.ejournal.entity.Subject.setTeacher()/io.soft.ejournal.entity.person.Teacher.setMyClass()/io.soft.ejournal.entity.Class.setName() matches multiple source property hierarchies:
io.soft.ejournal.dto.SubjectDto.getMyClass()/io.soft.ejournal.dto.ClassDto.getHeadTeacher()/io.soft.ejournal.dto.person.PersonDto.getMiddleName()
io.soft.ejournal.dto.SubjectDto.getMyClass()/io.soft.ejournal.dto.ClassDto.getHeadTeacher()/io.soft.ejournal.dto.person.PersonDto.getLastName()
io.soft.ejournal.dto.SubjectDto.getMyClass()/io.soft.ejournal.dto.ClassDto.getHeadTeacher()/io.soft.ejournal.dto.person.PersonDto.getFirstName()
1 error
at org.modelmapper.internal.Errors.throwConfigurationExceptionIfErrorsExist(Errors.java:241) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.ImplicitMappingBuilder.matchDestination(ImplicitMappingBuilder.java:158) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.ImplicitMappingBuilder.matchDestination(ImplicitMappingBuilder.java:151) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.ImplicitMappingBuilder.matchDestination(ImplicitMappingBuilder.java:151) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.ImplicitMappingBuilder.build(ImplicitMappingBuilder.java:89) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.ImplicitMappingBuilder.build(ImplicitMappingBuilder.java:74) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.TypeMapStore.getOrCreate(TypeMapStore.java:128) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.TypeMapStore.getOrCreate(TypeMapStore.java:102) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:113) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:59) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:31) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:303) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:110) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:242) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:188) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:152) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:106) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:72) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.ModelMapper.mapInternal(ModelMapper.java:573) ~[modelmapper-2.3.9.jar:na]
at org.modelmapper.ModelMapper.map(ModelMapper.java:447) ~[modelmapper-2.3.9.jar:na]
at io.soft.ejournal.service.ClassService.update(ClassService.java:65) ~[classes/:na]
at io.soft.ejournal.service.ClassService$$FastClassBySpringCGLIB$$783efd16.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:123) ~[spring-context-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.2.jar:5.3.2]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.2.jar:5.3.2]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) ~[spring-aop-5.3.2.jar:5.3.2]
at io.soft.ejournal.service.ClassService$$EnhancerBySpringCGLIB$$bd8a181c.update(<generated>) ~[classes/:na]
at io.soft.ejournal.controller.ClassController.update(ClassController.java:106) ~[classes/:na]
at io.soft.ejournal.controller.ClassController$$FastClassBySpringCGLIB$$2162dd02.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.security.access.intercept.aopalliance.MethodSe