-
Notifications
You must be signed in to change notification settings - Fork 45
Repository
Starting with Spring Boot 2.0, the repository method findOne(id)
was changed to getOne(id)
. I've noticed that when I converted my code from spring boot 1.5 to 2.0. However, what I did not notice was that not only the name of the method changed but its implementation changed very significantly.
I've created a handful of the integration tests to show what is going on.
Spring boot 2.0+ getOne(id)
implementation is based on EntityManager.getReference(getDomainClass(), id)
but its java doc for is not very clear:
/**
* Returns a reference to the entity with the given identifier.
*
* @param id must not be {@literal null}.
* @return a reference to the entity with the given identifier.
* @see EntityManager#getReference(Class, Object)
* @throws javax.persistence.EntityNotFoundException if no entity exists for given {@code id}.
*/
Spring boot 2.0+ getOne(id) implementation based on em.getReference(getDomainClass(), id):/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaRepository#getOne(java.io.Serializable)
*/
@Override
public T getOne(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
return em.getReference(getDomainClass(), id);
}
The exception is not thrown until the "state" of the entity is accessed. According to my tests that means calling any getter other than getId()
!
Java doc for EntityManager
method <T> T getReference(Class<T> entityClass, Object primaryKey)
is a little better:
/**
* Get an instance, whose state may be lazily fetched.
* If the requested instance does not exist in the database,
* the <code>EntityNotFoundException</code> is thrown when the instance
* state is first accessed. (The persistence provider runtime is
* permitted to throw the <code>EntityNotFoundException</code> when
* <code>getReference</code> is called.)
* The application should not expect that the instance state will
* be available upon detachment, unless it was accessed by the
* application while the entity manager was open.
* @param entityClass entity class
* @param primaryKey primary key
* @return the found entity instance
* @throws IllegalArgumentException if the first argument does
* not denote an entity type or the second argument is
* not a valid type for that entity�s primary key or
* is null
* @throws EntityNotFoundException if the entity state
* cannot be accessed
*/
public <T> T getReference(Class<T> entityClass,
Object primaryKey);
But it still would imply that getId()
should throw EntityNotFoundException
since I consider it to be part of the entity state.
Spring boot 1.5 findOne(id)
implementation was based on EntityManager.find(id)
:
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findOne(java.io.Serializable)
*/
public T findOne(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
Class<T> domainType = getDomainClass();
if (metadata == null) {
return em.find(domainType, id);
}
LockModeType type = metadata.getLockModeType();
Map<String, Object> hints = getQueryHints();
return type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints);
}
At a bare minimum, be very careful when using entityManager.getReference()
in your code. The proxy reference returned in not very easy to work with and might be error prone:
- it's not null but not pointing to an existing entity
-
getId()
would return id passed in as a primary key - access to any other getters will throw
EntityNotFoundException