两个难搞的Java Error/Exception
最佳答案 问答题库798位专家为你答疑解惑
最近维护公司的产品时,我碰到了两个头痛的Java异常。未免以后忘记了,所以写篇blog记录下这些问题和解决方法。
Entity定义
由于不能展示公司的代码,我就用书店、书、作者这些对象来说明。书店与作者之间是m:n的关系,作者与书之间是1:n的关系。各个对象定义如下:
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.*;
import org.hibernate.annotations.*;
import org.hibernate.envers.Audited;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;@Audited
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Entity
@EntityListeners({AuditingEntityListener.class, AuditingEntityListener.class})
@MappedSuperclass
@Table(name = "book_store")
public class BookStore implements Serializable {private static final long serialVersionUID = 1L;@Id@org.springframework.data.annotation.Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name = "name") private String name;@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)@JoinTable(name = "book_store_author",joinColumns =@JoinColumn(name = "book_stores_id", referencedColumnName = "id"),inverseJoinColumns =@JoinColumn(name = "authors_id", referencedColumnName = "id"))private Set<Author> authors = new HashSet<>();public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set<Author> getAuthors() {return authors;}public Author addAuthor(Author author) {this.authors.add(author);return this;}public Author removeAuthor(Author author) {this.authors.remove(author);return this;}public void setAuthors(Set<Author> authors) {this.authors = authors;}
}@Audited
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Entity
@EntityListeners({AuditingEntityListener.class, AuditingEntityListener.class})
@MappedSuperclass
@Table(name = "author")
public class Author implements Serializable {private static final long serialVersionUID = 1L;@Id@org.springframework.data.annotation.Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name = "name") private String name;@OneToMany(cascade = {CascadeType.ALL, CascadeType.PERSIST, CascadeType.MERGE},fetch = FetchType.LAZY, orphanRemoval = true)@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)@JoinColumn(name = "author_id")private Set<Book> books = new HashSet<>();public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set<Book> getBooks() {return books;}public Book addBook(Book book) {this.books.add(book);book.setAuthor(this);return this;}public Book removeBook(Book book) {this.books.remove(book);book.setAuthor(null);return this;}public void setBooks(Set<Book> books) {this.books = books}
}@Audited
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Entity
@EntityListeners({AuditingEntityListener.class, AuditingEntityListener.class})
@MappedSuperclass
@Table(name = "book")
public class Book implements Serializable {private static final long serialVersionUID = 1L;@Id@org.springframework.data.annotation.Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name = "name") private String name;@ManyToOne(optional = false)@JoinColumn(nullable = false)private Author author;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Author getAuthor() {return author;}public void setAuthor(Author author) {this.author = author;}
}
错误及其修正
当尝试创建一个书店,内含两个作者,每个作者三本书的时候,程序抛出了第一个错误:
A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance ...
Google了半天,不少人碰到了同样的问题,但没有人讲清楚根本原因是什么,只是建议将方法setAuthors()做如下修改:
public void setAuthors(Set<Author> authors) {this.authors.clear();this.authors.addAll(authors);
}
我照着修改了下,果然有效。但为啥直接给成员authors赋一个新的实例要出错,而修改其内容却不会?完全搞不清楚Spring Boot在背后检查了什么,以后有空还是要深挖一下Spring Boot的代码。
然而,在后续测试时,又碰到了第二个错误:
JSON parse error: Cannot invoke "java.util.Collection.iterator()" because "c" is null
又Google了一天半,终于发现了原因:setAuthors方法里,没有检查参数authors。若它为null,就会引发这个错误。遂继续修改setAuthors():
public void setAuthors(Set<Author> authors) {this.authors.clear();if (authors != null) {this.authors.addAll(authors);}
}
以防万一,按同样的方式修改Author.setBooks():
public void setBooks(Set<Book> books) {this.books.clear();if (books != null) {this.books.addAll(books);}
}
至此,终于解决了上述两个错误。
解决这两个错误的难点在于,哪怕我把log leve调到最低,程序都只是输出了一行错误信息,没有任何相关的stacktrace,导致我无法迅速定位相关代码。而且这两个错误都是在执行RESTful API callback函数之前就触发了,只能在Spring Boot的代码里打断点,调试起来很不方便。
后续
在后续调试代码的时候,我终于发现并不是不能给成员authors赋一个新的实例,问题还是在于传入的参数,参数本身可能为null,或其内部含有null元素。所以最终,setAuthors()和setBooks()应该修改成:
public void setAuthors(Set<Author> authors) {this.authors =Optional.ofNullable(authors).map(s -> s.stream().filter(Objects::nonNull).collect(Collectors.toSet())).orElse(new HashSet<>());
}public void setBooks(Set<Book> books) {this.books =Optional.ofNullable(books).map(s -> s.stream().filter(Objects::nonNull).collect(Collectors.toSet())).orElse(new HashSet<>());
}
99%的人还看了
相似问题
- 【Vue3】解决Vue打包后上传服务器 资源路径加载错误
- 实时错误’-2147217887‘多步OLB DB 操作产生错误。如果可能,请检查OLE DB状态值
- 解决requests 2.28.x版本SSL错误:证书验证失败
- ODBC配置数据源及相关问题(“找不到工程和库”“实时错误91对象变量或with块变量未设置”等)
- 微信小程序发货信息录入接口 错误上传时间非法,请按照 RFC 3339 格式填写?
- Python基础:错误和异常
- SourceTree提示128错误
- PHPmail 发送邮件错误 550 的原因是什么?
- 一段来自《Verilog HDL 高级数字设计》的错误Verilog代码
- NVS 错误码对应的原因
猜你感兴趣
版权申明
本文"两个难搞的Java Error/Exception":http://eshow365.cn/6-26346-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!