当前位置: 首页 > 知识库问答 >
问题:

StackOverflowError manytomany:MapStruct-Spring boot-hibernate

傅树
2023-03-14
@Getter @Setter
@NoArgsConstructor
@Entity()
@Table(name = "Actor")
@EqualsAndHashCode(exclude = "films")
public class Actor implements Serializable {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank(message = "name is required")
    private String name;

    @ManyToMany(mappedBy = "actors")
    private Set<Film> films;
}

电影实体

@Getter @Setter
@NoArgsConstructor
@Entity @Table(name = "Film")
@EqualsAndHashCode(exclude = "actors")
public class Film implements Serializable {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "Director_id")
    private Director director;

    @ManyToMany()
    @JoinTable(
            name = "Actor_has_Film",
            joinColumns = @JoinColumn(name = "Film_id"),
            inverseJoinColumns = @JoinColumn(name = "Actor_id"))
    private Set<Actor> actors;

    public void addActor(Actor actor) {
        this.actors.add(actor);
    }
}

Actordto

@Getter @Setter
@NoArgsConstructor
public class ActorDTO {

    private Long id;
    private String name;    
    private Set<FilmDTO> films;
}

FilmdTo

@Getter @Setter
@NoArgsConstructor
public class FilmDTO {

    private Long id;
    private DirectorDTO director;    
    private Set<ActorDTO> actors;
}
public interface DataMapper<D, E> {
    E toEntity(D dto);
    D toDto(E entity);
    List<E> toEntity(List<D> dtoList);
    List<D> toDto(List<E> entityList);
}
@Mapper(componentModel = "spring", uses = { })
public interface ActorMapper extends DataMapper<ActorDTO, Actor> {
}

电影映射器

@Mapper(componentModel = "spring", uses = { })
public interface FilmMapper extends DataMapper<FilmDTO, Film> {
}

FilmServices

@Service("filmServices")
public class FilmServices implements Services<FilmDTO> {

    @Autowired @Qualifier("filmRepository")
    private FilmRepository filmRepository;

    @Autowired @Qualifier("actorRepository")
    private ActorRepository actorRepository;

    private FilmMapper filmMapper;

    public FilmServices(FilmMapper filmMapper) {
        this.filmMapper = filmMapper;
    }

    public FilmDTO addActorToFilm(Long filmId, Long actoId) {
        Optional<Film> filmByIdOptional = filmRepository.findById(filmId);
        Optional<Actor> actorByIdOptional = actorRepository.findById(actoId);
        FilmDTO filmDtoWithNewActor = null;

        if (!filmByIdOptional.isPresent())
            throw new RuntimeException("The Film with id '" + filmId + "' does not exist");

        if (!actorByIdOptional.isPresent())
            throw new RuntimeException("The Actor with id '" + actoId + "' does not exist");

        Film film = filmByIdOptional.get();
        Actor actorToAdd = actorByIdOptional.get();

        boolean hasActorInFilm = film.getActors().stream()
            .anyMatch(actor -> actor.getName().equals(actorToAdd.getName()));

        if (!hasActorInFilm) {
            film.addActor(actorToAdd);
            Film filmWithNewActor = filmRepository.save(film);
            filmDtoWithNewActor = filmMapper.toDto(filmWithNewActor); // HERE THROW EXCEPTION
        } else {
            throw new RuntimeException("The Actor with id '" + actoId + "' already exist in the film");
        }

        return filmDtoWithNewActor;

    }
}

输出日志:

Hibernate: select films0_.Actor_id as actor_id2_1_0_, films0_.Film_id as film_id1_1_0_, film1_.id as id1_3_1_, film1_.Director_id as director4_3_1_, director2_.id as id1_2_2_ from Actor_has_Film films0_ inner join Film film1_ on films0_.Film_id=film1_.id left outer join Director director2_ on film1_.Director_id=director2_.id where films0_.Actor_id=?
2020-04-07 15:27:26.296 ERROR 742 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause

java.lang.StackOverflowError: null
    at ar.com.ada.sb.relationship.model.mapper.FilmMapperImpl.actorSetToActorDTOSet(FilmMapperImpl.java:188) ~[classes/:na]
    at ar.com.ada.sb.relationship.model.mapper.FilmMapperImpl.toDto(FilmMapperImpl.java:53) ~[classes/:na]
    at ar.com.ada.sb.relationship.model.mapper.FilmMapperImpl.filmSetToFilmDTOSet(FilmMapperImpl.java:165) ~[classes/:na]
    at ar.com.ada.sb.relationship.model.mapper.FilmMapperImpl.actorToActorDTO(FilmMapperImpl.java:182) ~[classes/:na]
    at ar.com.ada.sb.relationship.model.mapper.FilmMapperImpl.actorSetToActorDTOSet(FilmMapperImpl.java:194) ~[classes/:na]

我将非常感谢你的帮助

共有1个答案

孔鸿远
2023-03-14

尝试这个方法,实例化这两个属性的hashset<>(),您只需要一个方向映射,保留actor端映射的注释。

电影

@Entity @Table(name = "Film") 
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Film implements Serializable {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Film_id", updatable = false, nullable = false)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "Director_id")
    private Director director;

    @ManyToMany(fetch = FetchType.LAZY,
        cascade = {
                CascadeType.ALL
        },
        targetEntity= ActorModel.class
    )
    @JoinTable(name = "Actor_has_Film",
        joinColumns = { @JoinColumn(name = "Film_id") },
        inverseJoinColumns = { @JoinColumn(name = "Actor_id") })
    @JsonProperty("actors")
    private Set<Actor> actors = new HashSet<>();

    public void addActor(Actor actor) {
      this.actors.add(actor);
    }
}

演员

@Entity()
@Table(name = "Actor")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Actor implements Serializable {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Actor_id", updatable = false, nullable = false)
    private Long id;

    @NotBlank(message = "name is required")
    private String name;

    /*@ManyToMany(mappedBy = "actors")
    @JsonIgnore
    private Set<Film> films = new HashSet<>();*/
}
 类似资料:
  • 当我只保留一个主键--无论是CFO_ID还是LAST_UPDATE_DTS,并完全删除Idclass时,它工作得非常好。这让我认为idclass有问题,但我找不到任何问题。有人能帮忙吗?

  • 已与目标VM断开连接,地址:“javadeBug”,传输:“共享内存” 进程已完成,退出代码为0 PessoAcontroller:

  • 使用 springboot 改造 jeesite,只保留最简单的系统配置 。 介绍 1、运行主类,登录  admin/admin com.wolfking.jeesite.WolfkingJeesiteDriver 2、砍掉了所有的冗余的东西,只保留系统配置,数据库脚本 wolfking-jeesite.sql 3、使用 springboot 集成,使用 HikariDataSource 数据源

  • WeChat-SpringBoot 是使用 Spring Boot 开发的微信开发后端脚手架

  • 生产制造执行系统,基于 springBoot 开发。 精益生产+ISA-95 标准。 结合 MESA 战略计划方向设计框架。

  • 一个简单便捷的基于springboot+RabbitMQ中间件实现的RPC调用框架 远程调用过程如下 首先:消费者和生产者spring容器初始化的时候,会根据配置的的api在RabbitMQ上建立相应的队列,消费者会监听相关队列 1)生产者(client)调用以本地调用方式调用服务; 2)client 接收到调用后通过Hessian将方法、参数等组装成能够进行网络传输的消息体; 3)client

  • SpringBoot + 前端MVVM 基于Java的微服务全栈快速开发实践。 如今Web开发领域,当有人提到Java时,总会让人觉得臃肿、古老而过时且开发效率没有某些动态语言高效,甚至在此之前还有人高喊“Java 已死!”,但是事实真是如此吗?其实如果你一直关注着Java,那你的感悟会更深,尽管它有很多的缺点和啰嗦,但不可否认,Java依然是工业界中最优秀的语言,而且它一直保持着与时俱进。本项目

  • SpringBoot-Plus 是一个基于SpringBoot 2 的管理后台系统,包含了用户管理,组织机构管理,角色管理,功能点管理,菜单管理,权限分配,数据权限分配,代码生成,子系统生成,文档管理和预览等功能.不同于其他简单的开源后台管理系统,SpringBoot-Plus具备适当的企业应用深度。 系统基于Spring Boot 2技术,前端采用了Layui 2。数据库以MySQL/Oracl