映射处理器出现内部错误:java.lang.StackOverflowError。

4

在试图映射我的域对象时,我遇到了以下的StackOverflowError异常。我曾试图忽略导致循环依赖的属性,但没有成功。

在我的领域模型中心是WorkoutSet,其中包括一个User和一个Exercise。

如果我从WorkoutSetMapper中移除映射注释,则会按预期生成UserMapperImpl和ExerciseMapperImpl。

错误:(15,1) java: 映射处理器内部错误: java.lang.StackOverflowError 在 com.sun.tools.javac.code.Type$ClassType.accept(Type.java:786) 中 com.sun.tools.javac.code.Types$UnaryVisitor.visit(Types.java:4652) 中 com.sun.tools.javac.code.Types.supertype(Types.java:2315) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1966) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1955) 中 com.sun.tools.javac.code.Type$ClassType.accept(Type.java:786) 中 com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:4571) 中 com.sun.tools.javac.code.Types.asSuper(Types.java:1952) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1968) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1955) 中 com.sun.tools.javac.code.Type$ClassType.accept(Type.java:786) 中 com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:4571) 中 com.sun.tools.javac.code.Types.asSuper(Types.java:1952) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1975) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1955) 中 com.sun.tools.javac.code.Type$ClassType.accept(Type.java:786) 中 com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:4571) 中 com.sun.tools.javac.code.Types.asSuper(Types.java:1952) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1975) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1955) 中 com.sun.tools.javac.code.Type$ClassType.accept(Type.java:786) 中 com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:4571) 中 com.sun.tools.javac.code.Types.asSuper(Types.java:1952) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1975) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1955) 中 com.sun.tools.javac.code.Type$ClassType.accept(Type.java:786) 中 com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:4571) 中 com.sun.tools.javac.code.Types.asSuper(Types.java:1952) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1975) 中 com.sun.tools.javac.code.Types$13.visitClassType(Types.java:1955) 中 com.sun.tools.javac.code.Type$ClassType.accept(Type.java:786) 中 com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:4571) 中 com.sun.tools.javac.code.Types.asSuper(Types.java:1952) 中 com.sun.tools.javac.code.Types$4.visitClassType(Types.java:921) 中 com.sun.tools.javac.code.Types$4.visitClassType(Types.java:844) 中 com.sun.tools.javac.code.Type$ClassType.accept(Type.java:786) 中 com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:4571) 中 com.sun.tools.javac.code.Types.isSubtype(Types.java:840) 中 com.sun.tools.javac.code.Types.isSubtype(Types.java:804) 中 com.sun.tools.javac.model.JavacTypes.isSubtype(JavacTypes.java:98) 中 org.mapstruct.ap.internal.util.workarounds.SpecificCompilerWorkarounds.isSubtype(SpecificCompilerWorkarounds.java:76) 中 org.mapstruct.ap.internal.util.workarounds.TypesDecorator.isSubtype(TypesDecorator.java:68) 中 org.mapstruct.ap.internal.model.common.Type.isSubType(Type.java:638) 中 org.mapstruct.ap.internal.model.common.Type.isCollection(Type.java:628) 中 org.mapstruct.ap.internal.model.common.Type.isCollectionOrMap(Type.java:624) 中

我的域类如下:

            @Entity
            public class User implements FirstClassDomainObject {
                @Id
                @GeneratedValue(strategy = GenerationType.IDENTITY)
                private long id;
                private String name;
                private String email;
            ...

            @Entity
            public class Exercise implements FirstClassDomainObject {
                @Id
                @GeneratedValue(strategy = GenerationType.IDENTITY)
                private long id;
                private String name;
                private String description;
            ...

            @Entity
            public class WorkoutSet implements FirstClassDomainObject {
                @Id
                @GeneratedValue(strategy = GenerationType.IDENTITY)
                private long id;
                private int repetition;
                private double wight;
                private LocalDateTime timestamp;
                @ManyToOne
                private Exercise exercise;
                @ManyToOne
                private User user;
            ...

我的DTO类如下所示:

            public class UserResource implements ResourceObject {
                private Long id;
                private String name;
                private String email;
            ...

            public class ExerciseResource implements ResourceObject {
                private String name;
                private String description;
            ...

            public class WorkoutSetResource implements ResourceObject {
                private int repetition;
                private double wight;
                @JsonSerialize(using = LocalDateTimeSerializer.class)
                private LocalDateTime timestamp;
                private ExerciseResource exercise;
                private UserResource user;
            ...

我的映射器接口如下

            @Mapper(componentModel = "spring")
            interface UserMapper extends ClassMapper<User, UserResource> {
                @Override
                default List<Class<?>> getSupportedClasses() {
                    return Lists.newArrayList(User.class, UserResource.class);
                }
            }


            @Mapper(componentModel = "spring")
            interface ExerciseMapper extends ClassMapper<Exercise, ExerciseResource> {
                @Override
                default List<Class<?>> getSupportedClasses() {
                    return Lists.newArrayList(Exercise.class, ExerciseResource.class);
                }
            }

            @Mapper(componentModel = "spring", uses = {UserMapper.class, WorkoutSetMapper.class})
            interface WorkoutSetMapper extends ClassMapper<WorkoutSet, WorkoutSetResource> {
                @Override
                default List<Class<?>> getSupportedClasses() {
                    return Lists.newArrayList(WorkoutSet.class, WorkoutSetResource.class);
                }
            }

ClassMapper的定义如下:

            public interface ClassMapper<D extends DomainObject, R extends ResourceObject> {
                R map(D domainObject);
                D map(R resourceObject);
                List<Class<?>> getSupportedClasses();
            }

我省略了getter和setter方法以避免过多的代码,但整个代码库可以在此处找到:https://github.com/tonsV2/Lift-Log-Backend。 对于我做错了什么,您有任何线索吗?

看起来你的对象存在循环引用。 - OneCricketeer
是的,但我该如何防止mapstruct跟随它们? - user672009
我不知道。我只是认为用户不应该拥有一组训练,而这些训练又指向拥有它们的用户。练习也是如此。 - OneCricketeer
即使我从User和Exercise中删除@OneToMany,问题仍然存在。但你是对的。我已经更新了问题。 - user672009
如果您能描述您的领域模型,甚至创建一个ER图表,我认为会更清晰易懂。如果您对此感到舒适,那就更好了。 - OneCricketeer
我已在帖子开头添加了一个简短的注释。希望这能澄清一些问题。我怀疑循环引用是造成这个问题的原因。但现在我已经移除了它们,完全不知道该怎么办了。 - user672009
1个回答

7

我找到了错误!我已经将WorkoutSetMapper设置为使用它自己。

@Mapper(componentModel = "spring", uses = {UserMapper.class, WorkoutsetMapper.class})
interface WorkoutSetMapper extends ClassMapper<WorkoutSet, WorkoutSetResource> {

虽然我本应该拥有

@Mapper(componentModel = "spring", uses = {UserMapper.class, ExerciseMapper.class})
interface WorkoutSetMapper extends ClassMapper<WorkoutSet, WorkoutSetResource> {

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接