- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一个非常基本的 JAX-RS 服务(下面的 BookService
类),它允许创建 Book
类型的实体(也在下面)。 POST
负载
{
"acquisitionDate": 1418849700000,
"name": "Funny Title",
"numberOfPages": 100
}
成功保留 Book
并返回 201 CREATED
。但是,在有效负载上包含具有任何非空值的 id
属性会触发 org.hibernate.PersistentObjectException
消息 detached entity passed to persist
。 我明白这意味着什么,并且在创建对象(在本例中)时在有效负载中包含一个 id
是没有意义的。但是,在这种情况下,我更愿意阻止此异常一直冒泡并向我的用户显示例如 400 BAD REQUEST
(或者至少完全忽略该属性) .但是,有两个主要问题:
create
的异常是一个EJBTransactionRolledbackException
,我必须沿着堆栈跟踪一路爬行才能发现根本原因;org.hibernate.PersistentObjectException
- 我正在部署到使用 Hibernate 的 Wildfly,但我想保持我的代码可移植,所以我真的不想捕获这个特定的问题异常(exception)。据我了解,有两种可能的解决方案:
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);
}
}
最佳答案
我不知道这是否真的是您正在寻找的答案,但我只是在尝试这个想法并实现了一些东西。
JAX-RS 2 规范定义了一个用于 bean 验证的模型,所以我想也许您可以利用它。所有错误的验证都将映射到 400。您说“我更愿意阻止此异常一直冒泡并向我的用户显示,例如,400 BAD REQUEST”,但是如果验证不正确,您无论如何都会得到它。因此,无论您计划如何处理验证异常(如果有的话),您都可以在此处执行相同的操作。
基本上我只是创建了一个约束注释来验证 id 字段中的空值。您可以通过 idField
注释属性在注释中定义 id 字段的名称,因此您不受 id
的限制。这也可以用于其他对象,因此您不必像在第二个解决方案中建议的那样重复检查该值。
你可以玩玩它。只是想我会把这个选项放在那里。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
@Constraint(validatedBy = NoId.NoIdValidator.class)
@Target({ElementType.PARAMETER})
@Retention(RUNTIME)
public @interface NoId {
String message() default "Cannot have value for id attribute";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String idField() default "id";
public static class NoIdValidator implements ConstraintValidator<NoId, Object> {
private String idField;
@Override
public void initialize(NoId annotation) {
idField = annotation.idField();
}
@Override
public boolean isValid(Object bean, ConstraintValidatorContext cvc) {
boolean isValid = false;
try {
Field field = bean.getClass().getDeclaredField(idField);
if (field == null) {
isValid = true;
} else {
field.setAccessible(true);
Object value = field.get(bean);
if (value == null) {
isValid = true;
}
}
} catch (NoSuchFieldException
| SecurityException
| IllegalArgumentException
| IllegalAccessException ex) {
Logger.getLogger(NoId.class.getName()).log(Level.SEVERE, null, ex);
}
return isValid;
}
}
}
用法:
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createBook(@Valid @NoId(idField = "id") Book book) {
book.setId(1);
return Response.created(URI.create("http://blah.com/books/1"))
.entity(book).build();
}
注意默认的idField
是id
,所以如果你不指定它,它会在对象中寻找id
字段类(class)。您还可以像指定任何其他约束注释一样指定 message
:
@NoId(idField = "bookId", message = "bookId must not be specified")
// default "Cannot have value for id attribute"
关于java - 防止 'PersistentObjectException',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27582083/
我有一个非常基本的 JAX-RS 服务(下面的 BookService 类),它允许创建 Book 类型的实体(也在下面)。 POST负载 { "acquisitionDate": 14188
此处为 Spring Boot/Hibernate/JPA/MySQL。我有以下两个 JPA 实体: @MappedSuperclass public abstract class BaseEntit
我有一个引用实体 Bar 的实体 Foo: @Entity public class Foo { @OneToOne(cascade = {PERSIST, MERGE, REFRESH},
我尝试了线程中提到的许多事情。但似乎没有一个能解决我的问题。请告诉我哪里出错了。 模型 @Entity public class MySession { @Id @GeneratedV
我正在尝试连接 MySQL 数据库并向数据库插入一个新用户。我的数据库名称是 bookstoredb,表名称是 users。我尝试使用 hibernate 和 jpa 创建模型类,但我收到 Persi
我在我的项目中使用 Hibernate。服务器启动时出现错误: org.hibernate.PersistentObjectException: detached entity passed to p
我正在开发 Spring-boot+ ReactJs 应用程序。基本上我有 2 个具有一对多关系的实体(品牌和系列)。 @Entity @Table(name = "brands") public c
这是关系 @OneToOne(optional = true, fetch = FetchType.LAZY, cascade = CascadeType.PERSIST ) @Join
JPA:多对多连接。 场景: 多个产品可以保存在多个类别下。喜欢:芒果可以作为水果类和沙漠类。 Product == [COMMODITY] Category == [GENRE] 异常: detac
我有两个表(即 Hibernate 中的实体),它们的关联如下: @Entity @Table(name = "table_one") public class TableOne { pri
我在一个 JPA 项目中有 2 个实体: 一个类别和一个问题。所以每个类别都会有一个问题列表,每个问题都是一个类别的一部分(一对多关系)。我通过两个实体中的设置/添加方法来管理双向关系: 问题:
在 Hibernate 中使用 JPA,运行以下代码时出现异常。我第一次运行它时,一切正常,数据已插入数据库。第二次,应该更新数据的时候,失败了: @AdminTx public void proce
我已经成功地用 hibernate 编写了我的第一个主子示例。几天后我又拿了它并升级了一些库。不知道我做了什么,但我再也无法让它运行了。有人可以帮我找出返回以下错误消息的代码有什么问题吗: org.h
当我尝试在注册期间保存用户对象时,出现以下错误 用户服务 > @Service public class UserServiceImpl implements UserService { > >
我正在使用 hibernate orm 填充数据库,并且无法传递多个对象。 我尝试在对象集合中使用级联合并,从oneToMany重新组织到manyToMany关系,但似乎问题与hibernate无关.
我正在使用 Spring Roo 生成基于表(在 MS SQL Server 上创建)的实体。以下是我的sql脚本: CREATE TABLE [dbo].[JMSMessage]( [Me
我正在尝试在数据库中保留一个实体类,为此我为我的类尝试了几种不同的实现,但仍然面临错误(但不同的错误)。我的实体类现在是这样的: @Entity @Table(name="pagina") publi
我收到异常 org.hibernate.PersistentObjectException:传递给持久化的分离实体。从这个论坛和其他地方的众多帖子中,我了解到这种情况发生在两种情况下(不考虑一对一注释
我正在创建一个简单的应用程序,用于使用 Java JPA 向表中插入一行(如果表不存在,请创建它)。 我附上了它的可运行示例的一些代码。 这是我得到的异常和堆栈跟踪: EXCEPTION -- > o
我对 Spring 还很陌生,我一直在使用 this帮助我建立 @ManyToMany 关系的教程。我试图在 User 和 Role 之间建立多对多关系,然后在 Role 和 Permission 之
我是一名优秀的程序员,十分优秀!