У меня есть очень простой сервис JAX-RS (класс BookService
), который позволяет создавать объекты типа Book
(также ниже). POST
ИНГ полезной нагрузкиПредотвращение «PersistentObjectException»
{
"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
- Я развертываю в Wildfly, который использует Hibernate, но я хочу сохранить свой код переносимым, поэтому я действительно не хочу поймать это конкретное исключение.
В моем понимании, есть два возможных решения:
- Использование
book.setId(null)
передbookRepo.create(book)
. Это игнорирует тот факт, что атрибут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);
}
}