【发布时间】:2014-12-20 16:22:39
【问题描述】:
我有一个非常基本的 JAX-RS 服务(下面的 BookService 类),它允许创建 Book 类型的实体(也在下面)。 POST有效载荷
{
"acquisitionDate": 1418849700000,
"name": "Funny Title",
"numberOfPages": 100
}
成功持久化Book 并返回201 CREATED。但是,包含id 属性以及负载上的任何非空值都会触发带有消息detached entity passed to persist 的org.hibernate.PersistentObjectException。 我明白这意味着什么,并且在创建对象时(在这种情况下)在有效负载上包含 id 是没有意义的。但是,我更愿意防止此异常一直冒泡,并在这种情况下向我的用户呈现 400 BAD REQUEST (或者,至少完全忽略该属性)。但是,有两个主要问题:
- 到达
create的异常是EJBTransactionRolledbackException,我必须一直爬到堆栈跟踪才能发现根本原因; - 根本原因是
org.hibernate.PersistentObjectException- 我正在部署到使用 Hibernate 的 Wildfly,但我想保持我的代码可移植,所以我真的不想捕获这个特定的异常。
据我了解,有两种可能的解决方案:
- 在
bookRepo.create(book)之前使用book.setId(null)。这将忽略id属性带有值并继续请求这一事实。 - 检查
book.getId() != null是否抛出类似IllegalArgumentException的东西,可以映射到400状态码。似乎是更好的解决方案。
但是,来自其他框架(例如 Django Rest Framework),我真的更希望由框架本身来处理这个问题……我的问题是,是否有任何内置方法可以实现这种行为我可能会失踪吗?
这是BookService 类:
@Stateless
@Path("/books")
public class BookService {
@Inject
private BookRepo bookRepo;
@Context
UriInfo uriInfo;
@Consumes(MediaType.APPLICATION_JSON)
@Path("/")
@POST
@Produces(MediaType.APPLICATION_JSON)
public Response create(@Valid Book book) {
bookRepo.create(book);
return Response.created(getBookUri(book)).build();
}
private URI getBookUri(Book book) {
return uriInfo.getAbsolutePathBuilder()
.path(book.getId().toString()).build();
}
}
这是Book 类:
@Entity
@Table(name = "books")
public class Book {
@Column(nullable = false)
@NotNull
@Temporal(TemporalType.TIMESTAMP)
private Date acquisitionDate;
@Column(nullable = false, updatable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Integer id;
@Column(nullable = false)
@NotNull
@Size(max = 255, min = 1)
private String name;
@Column(nullable = false)
@Min(value = 1)
@NotNull
private Integer numberOfPages;
(getters/setters/...)
}
这是BookRepo 类:
@Stateless
public class BookRepo {
@PersistenceContext(unitName = "book-repo")
protected EntityManager em;
public void create(Book book) {
em.persist(book);
}
}
【问题讨论】:
标签: java jakarta-ee jpa jax-rs