What is the best way to handle LazyInitializationException - java

I have been struggling with Hibernate lately. I recently ran into a problem which I would appreciate some help with. I have two entities :
1.User
#Entity
public class User{
#ID
private Long id;
#OneToMany (mappedBy = "user")
private Set<Activity> activities;
...
}
2.Activity:
#Entity
public class Activity {
#ID
private Long id;
#ManyToOne
private User user;
...
}
So here, since I didn't set user activities fetchType to EAGER, when I fetch user entity from the database all the activities will be fetched lazily.
What I did in UserRepository was:
#Override
public User getUserByUserName(String userName) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Query query = entityManager.createQuery
("from User u where u.userName = :user_name", User.class);
query.setParameter("user_name", userName);
try{
return (User) query.getSingleResult();
} catch(NoResultException e) {
return null;
} finally {
entityManager.close();
}
}
Doing this I get The LazyInitializationException when I wanted to use the fetched User's activies. But what I did was removing finaly block from the code :
#Override
public User getUserByUserName(String userName) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Query query = entityManager.createQuery
("from User u where u.userName = :user_name", User.class);
query.setParameter("user_name", userName);
try{
return (User) query.getSingleResult();
} catch(NoResultException e) {
return null;
}
}
This solved The exception. I wanted to know if this is the right way to do it or should I just change user activities fetchType to EAGER?

I guess the problem you're having comes from closing the entityManager.close();.
As User's reference to Activity is LAZY, JPA will load it only once you try to access it via code, like anything accessing the variable User.activities in any way.
This makes JPA load the referenced Activitys.
What I think happens there:
When you create (read from Database) those Users in your getUserByUserName() method, JPA keeps (has those created Users keep) a reference to the EntityManager entityManager they were created with.
So if you later on try to access User.activities, JPA will try to load those activities using the EntityManager entityManager.
If you have already closed that EntityManager entityManager (as you did in your final statement), then the loading will fail with that LazyInitializationException you then get.
Solution:
As I am not sing Hibernate, nor checking its codebase, I do not know whether entityManagerFactory.createEntityManager(); is actually creating separate instances if already present, and how all the EntityManager instances are managed.
But probably it's simply best to never close any EntityManager; instead, let the JPA implementation (Hibernate) take care of that. With all the possibilities of dependency-injecting stuff into your classes, I bet Hibernate has some pretty good mechanisms in place for dealing with that kind of resource management.
As an alternative, let Hiberante inject the EntityManager, so you don't even have to take care of creating it in the first place.
Finally, you can still stick to the LAZY loading, if that improves initial and long-term performance for you. Just don't close those EntityManagers.
If you need deeper insights into that matter,
check Hibernate's source code / preprocessors / code injection / bytecode weaving mechanisms
or use some JVM memory analysis tool to see if the number of instantiated EntityManagers increase linearly with calls to your getUserByUserName() method.
Update: Showing a completely different alternative
I personally use Payara, and use #EJB private UserCRUD mUserCRUD; to inject Data Access Objects, that I called CRUD (for Create Retriece Update Delete) a long time ago and still stick to them.
The basic principle is these 3 steps:
Step 1: I have a universal base class in a library, injecting the #PersistenceContext protected EntityManager mEM;
#Stateless
public abstract class TemplateCRUD_Simple<T> implements TemplateCRUD_Simple_Interface<T> {
#PersistenceContext protected EntityManager mEM;
protected final Class<T> mType;
public TemplateCRUD_Simple(final Class<T> pClass) {
mType = pClass;
}
/*
* INTERNALS
*/
#Override public String getTableName() {
return mType.getSimpleName();
}
#Override public String getNativeTableName() {
final Table table = mType.getAnnotation(Table.class);
if (table != null) return table.name();
return getTableName();
}
#Override public EntityManager getEntityManager() {
return mEM;
}
/*
* CREATE
*/
#Override public T create(final T t) {
return createAny(t);
}
#Override public <U> U createAny(final U u) {
mEM.persist(u);
mEM.flush();
mEM.refresh(u);
return u;
}
/*
* RETRIEVE
*/
#Override public T find(final long pID) throws JcXEntityNotFoundException {
final T ret = find(pID, null);
if (ret == null) throw new JcXEntityNotFoundException(getTableName() + " with ID " + pID + " cannot be found!");
return ret;
}
#Override public T find(final long pID, final T pDefault) {
final T ret = mEM.find(mType, Long.valueOf(pID));
if (ret == null) return pDefault;
return ret;
}
#Override public T find(final Long pID, final T pDefault) {
if (pID == null) return pDefault;
return find(pID.longValue(), pDefault);
}
#Override public T findCreate(final long pID) throws InstantiationException, IllegalAccessException {
final T item = find(pID, null);
if (item != null) return item;
final T item2 = mType.newInstance();
return create(item2);
}
// a lot more methods here
}
And its interface definition, also in the library:
public interface TemplateCRUD_Simple_Interface<T> {
EntityManager getEntityManager();
String getTableName();
String getNativeTableName();
// create
T create(T t);
<U> U createAny(U t);
// retrieve
T find(long pID) throws JcXEntityNotFoundException;
T find(long pID, T pDefault);
T find(Long pID, T pDefault);
T findCreate(long pID) throws InstantiationException, IllegalAccessException;
List<T> findAll(String pColName, Object pValue, final boolean pCaseSensitive);
List<T> findAll(String pColName, Object pValue);
List<T> findAll(String pColName, String pValue, final boolean pCaseSensitive);
List<T> findAll(String pColName, String pValue);
List<T> findAll(String pColName, long pValue);
List<T> findAllByFieldName(String pFieldName, Object pValue, final boolean pCaseSensitive);
List<T> findAllByFieldName(String pFieldName, Object pValue);
List<T> findWhereContains(final String pColName, final String pValue, final boolean pCaseSensitive);
List<T> findWhereContains(final String pColName, final String pValue);
List<T> getAll();
List<Long> getAllIds();
List<T> getByIds(final Collection<Long> pIds);
// update
T update(T t);
void updateProperties(T pItem, Map<String, String[]> pMatches);
T updateItem(Map<String, String[]> pMatches, long pID) throws InstantiationException, IllegalAccessException;
ArrayList<T> updateItems(String pEntityParamName, Map<String, String[]> pMap) throws InstantiationException, IllegalAccessException;
// delete
T delete(long pId);
// misc
long countAll();
Object getID(T pItem);
long getIDLong(T pItem);
boolean contains(T pItem);
void detach(final T pItem);
#Deprecated String getFieldNameInDb(final String pFieldName, final String pDefault);
// private List<T> getOverdueForXIn(final int pDays, final String pVarName);
List<T> getOverdueForDeletion(final boolean pAddAlreadyWarned);
List<T> getOverdueForUpdate(final boolean pAddAlreadyWarned);
}
Step 2: For each custom Class I have a CRUD (in this example, the 'User' Class):
CrudBase_BaseEntity is basically derived drom TemplateCRUD_Simple, just a few more steps in between for more flexibility
UserCRUD extends TemplateCRUD_Simple, so I can easily use those general methods
If I need specialized methods, I simply add them to the UserCRUD's code
This is an example for handling the User entity:
#Entity
#Table(name = "PT_User")
public class User extends _BaseEntity<User> {...}
And this is its CRUD/DAO:
#Stateless
public class UserCRUD extends CrudBase_BaseEntity<User> {
public UserCRUD() {
super(User.class);
}
public long getRegisteredUsersCount() {
final String sql = "SELECT COUNT(d) FROM " + getTableName() + " d";
final Query q = mEM.createQuery(sql);
final Long count = (Long) q.getSingleResult();
if (count == null) return 0;
return count.longValue();
}
public User findUserByUsernameOrEmail(final String pUid, final String pMail) {
final TypedQuery<User> query = mEM.createQuery("SELECT i FROM " + getTableName() + " i WHERE lower(i.email)=lower(:userid) OR lower(i.email)=lower(:usermail)", mType);
query.setParameter("userid", pUid);
query.setParameter("usermail", pMail);
final List<User> list = query.getResultList();
if (list == null || list.size() < 1) return null;
return list.get(0);
}
public List<User> getAllAdmins() {
final TypedQuery<User> query = mEM.createQuery("SELECT i FROM " + getTableName() + " i WHERE i.isAdmin = TRUE", mType);
final List<User> list = query.getResultList();
return list;
}
public List<User> getInvalidUsers() {
final TypedQuery<User> query = mEM.createQuery("SELECT i FROM " + getTableName() + " i "
+ "WHERE (i.username IS NULL"
+ " OR i.fullname IS NULL)"
+ " AND i.email IS NULL", mType);
final List<User> list = query.getResultList();
return list;
}
}
Step 3: In servlets, I simply inject it via #EJBannotation and then use it like this:
#WebServlet("/dyn/user/getAll")
#WebServletParams({})
#WebServletDescription()
public class GetAll extends BaseServlet {
private static final long serialVersionUID = -4567235617944396165L;
#EJB private UserCRUD mCRUD;
#Override protected void doGet_(final HttpServletRequest pReq, final HttpServletResponse pResp) throws IOException {
USessionManager.ensureUserLoggedInAndAdmin(pReq);
final List<User> items = mCRUD.getAll();
items.sort((final User pO1, final User pO2) -> JcUString.compareTo(pO1.getFullname(), pO2.getFullname(), false));
JSON.send(items, pResp);
}
}
This is the way I implemented it and use it.
At first it's lot of overhead
But it's really easy to set up new Classes und CRUDs
It's safe to use them
I use this in my JEE library, so I do not have to duplicate code, and any patch or addition I make is then available to all projects that use it
If need be, I could always access the (again: injected) EntityManager instance inside the TemplateCRUD.
I believe Spring uses a quite similar system, and calls it something like '...Repository'. If you want, you can also check that out and take its source code and adapt it. Usually when doing that, the #EJB and #PersistenceContext and #Inject do not transfer well between GlassFish/Payara, Spring or Hibernate, because not all support all of those Annotations in every context. As I said, this is quite Payara specific, and I've never tested it in other containers, but the approach should work everywhere.
To recap: this all depends a lot on dependency injection, me letting the container do all the work.

The rule is
the entities should not escape transaction bounds
The lazy loading is a killer feature of Hibernate, one should not afraid of it.
So, the repository/DAO should return the entity(es).
The service should be transactional(*), manage the entities but return DTOs outside.
Consider using any java bean mapper for that purpose to avoid monkey work.
That allows you not load unnecessary properties if they are not needed.
(*) if there are no long-living operations such as http calls.

Related

How to dynamic search with Criteria API in Java?

I want to dynamic search with Criteria API in Java.
In the code I wrote, we need to write each entity in the url bar in JSON. I don't want to write "plaka".
The URL : <localhost:8080/api/city/query?city=Ankara&plaka=> I want to only "city" or "plaka"
Here we need to write each entity, even if we are going to search with only 1 entity. Type Entity and it should be empty.
My code is as below. Suppose there is more than one entity, what I want to do is to search using a single entity it wants to search. As you can see in the photo, I don't want to write an entity that I don't need. can you help me what should I do?
My code in Repository
public interface CityRepository extends JpaRepository<City, Integer> , JpaSpecificationExecutor<City> {
}
My code in Service
#Service
public class CityServiceImp implements CityService{
private static final String CITY = "city";
private static final String PLAKA = "plaka";
#Override
public List<City> findCityByNameAndPlaka(String cityName, int plaka) {
GenericSpecification genericSpecification = new GenericSpecification<City>();
if (!cityName.equals("_"))
genericSpecification.add(new SearchCriteria(CITY,cityName, SearchOperation.EQUAL));
if (plaka != -1)
genericSpecification.add(new SearchCriteria(PLAKA,plaka, SearchOperation.EQUAL));
return cityDao.findAll(genericSpecification);
}
#Autowired
CityRepository cityDao;
My code in Controller
#RestController
#RequestMapping("api/city")
public class CityController {
#Autowired
private final CityService cityService;
public CityController(CityService cityService) {
this.cityService = cityService;
#GetMapping("/query")
public List<City> query(#RequestParam String city, #RequestParam String plaka){
String c = city;
int p;
if (city.length() == 0)
c = "_";
if (plaka.length() == 0) {
p = -1;
}
else
p = Integer.parseInt(plaka);
return cityService.findCityByNameAndPlaka(c,p);
}
My code in SearchCriteria
public class SearchCriteria {
private String key;
private Object value;
private SearchOperation operation;
public SearchCriteria(String key, Object value, SearchOperation operation) {
this.key = key;
this.value = value;
this.operation = operation;
}
public String getKey() {
return key;
}
public Object getValue() {
return value;
}
public SearchOperation getOperation() {
return operation;
}
My code in GenericSpecification
public class GenericSpecification<T> implements Specification<T> {
private List<SearchCriteria> list;
public GenericSpecification() {
this.list = new ArrayList<>();
}
public void add(SearchCriteria criteria){
list.add(criteria);
}
#Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
List<Predicate> predicates = new ArrayList<>();
for (SearchCriteria criteria : list) {
if (criteria.getOperation().equals(SearchOperation.GREATER_THAN)) {
predicates.add(builder.greaterThan(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.LESS_THAN)) {
predicates.add(builder.lessThan(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.GREATER_THAN_EQUAL)) {
predicates.add(builder.greaterThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.LESS_THAN_EQUAL)) {
predicates.add(builder.lessThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.NOT_EQUAL)) {
predicates.add(builder.notEqual(
root.get(criteria.getKey()), criteria.getValue()));
} else if (criteria.getOperation().equals(SearchOperation.EQUAL)) {
predicates.add(builder.equal(
root.get(criteria.getKey()), criteria.getValue()));
} else if (criteria.getOperation().equals(SearchOperation.MATCH)) {
predicates.add(builder.like(
builder.lower(root.get(criteria.getKey())),
"%" + criteria.getValue().toString().toLowerCase() + "%"));
} else if (criteria.getOperation().equals(SearchOperation.MATCH_END)) {
predicates.add(builder.like(
builder.lower(root.get(criteria.getKey())),
criteria.getValue().toString().toLowerCase() + "%"));
}
}
return builder.and(predicates.toArray(new Predicate[0]));
}
My code in SearchOperation
public enum SearchOperation {
GREATER_THAN,
LESS_THAN,
GREATER_THAN_EQUAL,
LESS_THAN_EQUAL,
NOT_EQUAL,
EQUAL,
MATCH,
MATCH_END,
}
The good thing about the Criteria API is that you can use the CriteriaBuilder to build complex SQL statements based on the fields that you have. You can combine multiple criteria fields using and and or statements with ease.
How I approached something similar int he past is using a GenericDao class that takes a Filter that has builders for the most common operations (equals, qualsIgnoreCase, lessThan, greaterThan and so on). I actually have something similar in an open-source project I started: https://gitlab.com/pazvanti/logaritmical/-/blob/master/app/data/dao/GenericDao.java
https://gitlab.com/pazvanti/logaritmical/-/blob/master/app/data/filter/JPAFilter.java
Next, the implicit DAO class extends this GenericDao and when I want to do an operation (ex: find a user with the provided username) and there I create a Filter.
Now, the magic is in the filter. This is the one that creates the Predicate.
In your request, you will receive something like this: field1=something&field2=somethingElse and so on. The value can be preceded by the '<' or '>' if you want smaller or greater and you initialize your filter with the values. If you can retrieve the parameters as a Map<String, String>, even better.
Now, for each field in the request, you create a predicate using the helper methods from the JPAFilter class and return he resulted Predicate. In the example below I assume that you don't have it as a Map, but as individual fields (it is easy to adapt the code for a Map):
public class SearchFilter extends JPAFilter {
private Optional<String> field1 = Optional.empty();
private Optional<String> field2 = Optional.empty();
#Override
public Predicate getPredicate(CriteriaBuilder criteriaBuilder, Root root) {
Predicate predicateField1 = field1.map(f -> equals(criteriaBuilder, root, "field1", f)).orElse(null);
Predicate predicateField2 = field2.map(f -> equals(criteriaBuilder, root, "field2", f)).orElse(null);
return andPredicateBuilder(criteriaBuilder, predicateField1, predicateField2);
}
}
Now, I have the fields as Optional since in this case I assumed that you have them as Optional in your request mapping (Spring has this) and I know it is a bit controversial to have Optional as input params, but in this case I think it is acceptable (more on this here: https://petrepopescu.tech/2021/10/an-argument-for-using-optional-as-input-parameters/)
The way the andPredicateBuilder() is made is that it works properly even if one of the supplied predicates is null. Also, I made s simple mapping function, adjust to include for < and >.
Now, in your DAO class, just supply the appropriate filter:
public class SearchDao extends GenericDAO {
public List<MyEntity> search(Filter filter) {
return get(filter);
}
}
Some adjustments need to be made (this is just starter code), like an easier way to initialize the filter (and doing this inside the DAO) and making sure that that the filter can only by applied for the specified entity (probably using generics, JPAFIlter<T> and having SearchFilter extends JPAFilter<MyEntity>). Also, some error handling can be added.
One disadvantage is that the fields have to match the variable names in your entity class.

DAO design pattern: where should the database access be implemented?

I am building a Java application that uses a database and I'm using a DAO design pattern: in my code, all objects classes have an associated DAO class that implements an interface with get, save and update methods.
For instance, for a User object, I will have the following class (ConnectionDB implements the connection to the database):
public class UserDAO implements Dao<User, String> {
private final static String TABLE_NAME = "users";
private final static UserDAO instance = new UserDAO();
public static UserDAO getInstance() {
return instance;
}
private UserDAO() {
}
#Override
public User get(String username) throws SQLException {
String query = "SELECT * FROM " + TABLE_NAME + " WHERE username = ?";
PreparedStatement stmt = ConnectionDB.getInstance().prepareStatement(query);
stmt.setString(1, username);
ResultSet result = stmt.executeQuery();
if (!result.next())
return null;
User user = new User(
result.getInt("id"),
username,
);
stmt.close();
result.close();
return user;
}
/* same thing for save and update */
}
Here is the Dao interface for reference:
public interface Dao<T, S> {
T get(S id) throws SQLException;
ArrayList<T> getAll() throws SQLException;
void save(T t) throws SQLException;
void update(T t) throws SQLException;
}
This way works pretty fine but as I have more and more classes in my application, and a DAO class for each one of them, I have a lot of repetitive code. For instance, the only difference between the get implementation on different objects is the name and type of the primary key and the call to the constructor.
In order to make the code more generic, I tried to implement a fetchItem method in the ConnectionDB class that would be able to query an item from the database:
public <T> HashMap<String, Object> fetchItem(String table_name, String pk, T id) throws SQLException {
String query = "SELECT * FROM " + table_name + " WHERE " + pk + " = ?";
PreparedStatement stmt = prepareStatement(query);
stmt.setObject(1, id);
ResultSet result = stmt.executeQuery();
if (!result.next())
return null;
HashMap<String, Object> values = buildObject(result);
stmt.close();
result.close();
return values;
}
public HashMap<String, Object> buildObject(ResultSet result) throws SQLException {
ResultSetMetaData metadata = result.getMetaData();
int columnCount = metadata.getColumnCount();
HashMap<String, Object> values = new HashMap<>();
for (int i = 1; i <= columnCount; i++) {
values.put(metadata.getColumnName(i), result.getObject(i));
}
return values;
}
With this implementation, I can now replace my first get method in the UserDAO class by the following simplified code:
public User get(String username) throws SQLException {
HashMap<String, Object> values = ConnectionDB.getInstance()
.fetchItem(TABLE_NAME, "username", username);
if (values == null || values.isEmpty())
return null;
return new User(
id,
(String) values.get("String")
);
}
While this new implementation is simpler and allows the get methods to only do what they're supposed to do (here, create a User object with the right parameters from the DB), I find it a bit dangerous as I'll have to make a lot of casts; as I have a lot of Object variables in my code I'm not sure whether it'll be easy to debug the code if something fails in any of these function calls.
So here's my question: which implementation is better, easier to maintain and safer?
Connection DB is a very bad place to define such implementation. It is just a link with a specific database thats all. You violate single responsibility rule. Better to implement base generic class for all DAO's and place common logic there.
Also if you will use Hibernate framework, you will not need to work with query strings and Object variables casts.

Correct class hierarchy

I was wondering what is the correct way to organize my class hierarchy in the following situation.
I wanted to build an abstraction around postgresql advisory lock.
Note just for context: An advisory lock is a lock that you can obtain at a session or transaction level. Postgres handle all the complexity for you.
The code that I've written so far is something like
interface DBLockService
interface SessionLockService : DBLockService {
fun acquire(id: Long)
fun unlock(id: Long): Boolean
}
interface TransactionalLockService : DBLockService {
fun txAcquire(id: Long)
}
abstract class BaseDBLockService(protected val entityManager: EntityManager): DBLockService {
protected fun executeAcquire(preparedStatement: String, id: Long) {
executeAcquire<Any>(preparedStatement, id)
}
protected inline fun <reified T> executeAcquire(preparedStatement: String, id: Long) =
entityManager
.createNativeQuery(preparedStatement, T::class.java)
.setParameter("id", id)
.singleResult as T
}
#Component
class LockServiceImpl(
entityManager: EntityManager
) : BaseDBLockService(entityManager),
SessionLockService {
companion object {
const val acquireStatement = "SELECT pg_advisory_lock(:id)"
const val unlockStatement = "SELECT pg_advisory_unlock(:id)"
}
override fun acquire(id: Long) {
executeAcquire(acquireStatement, id)
}
override fun unlock(id: Long) =
executeAcquire<Boolean>(unlockStatement, id)
}
#Component
class TransactionalLockServiceImpl(
entityManager: EntityManager
) : BaseDBLockService(entityManager),
TransactionalLockService {
// very similar implementation
}
Looking at this code there is something that tell's me that there is something wrong:
DBLockService is a bit useless interface, there is no method
Are SessionLockService and TransactionalLockService just an implementation detail? Is it correct that there is a different interface for every "type" of lock?
But at the same time, if I remove the DBLockService seems very odd to me that there are 2 interfaces (SessionLockService and TransactionalLockService) with very similar context that are not related in any way.
Moreover, removing DBLockService, I'll have the 2 implementations (LockServiceImpl and TransactionalLockServiceImpl) that extends from the abstract class BaseDBLockService to implement these 2 interfaces but at the same time the abstract class is not related to them.
What to you think?
Thanks
Update
As requested I'll add an example of a real case scenario
#Service
class SomethingService(private val lockService: TransactionalLockService){
#Transactional
fun aMethod(entityId: Long){
lockService.txAcquire(entityId)
//code to be synchronized or there will be problems
}
}
I would like to inject a class of a generic LockService but I cannot find a way to abstract that because imho a lock that disappear after the transaction ends is a lock different from a lock that disappear after the connection to the db is closed (session lock) that is different from a lock that need to be unlocked automatically.
It's possible that there are a lot of other implementations of lock, for example a TimeoutLock that remove the lock after some time.
But I'm not able to think how to separate these implementation details from the general concept of a Lock.
Okay, thanks for the example. I still find it a bit odd to call what you want to implement a Service. I'd probably call it a Strategy, but that's not really that important. It's just a semantic preference.
Anyway, what I would do is probably something like the following (untested/pseudo code):
interface LockService {
Boolean acquire(Long id);
Boolean unlock(Long id);
}
abstract class BaseLockService
implements LockService {
protected EntityManager entityManager;
BaseLockService(EntityManager entityManager) {
this.entityManager = entityManager;
}
protected Boolean executeAcquire(String preparedStatement, Long id) {
// your generic implementation
}
}
class SessionLockService
extends BaseLockService {
private static class Statements {
static final String acquireStatement = "...";
static final String unlockStatement = "...";
}
SessionLockService(EntityManager entityManager) {
super(entityManager);
}
#Override
Boolean acquire(Long id) {
return executeAcquire(Statements.acquireStatement, id);
}
#Override
Boolean unlock(Long id) {
return executeAcquire(Statements.unlockStatement, id);
}
}
class TransactionalLockService
extends BaseLockService {
private static class Statements {
static final String acquireStatement = "...";
}
TransactionalLockService(EntityManager entityManager) {
super(entityManager);
}
#Override
Boolean acquire(Long id) {
return executeAcquire(Statements.acquireStatement, id);
}
#Override
Boolean unlock(Long id) {
// simply return true
return true;
// or if there's some Postgres or EntityManager mechanism to find out if the transaction is still active:
return !entityManager.isInTransaction(id);
}
}
class SomeService {
private final LockService lockService;
SomeService(LockService lockService) {
this.lockService = lockService;
}
void aMethod(Long entityId) {
if(!lockService.acquire(entityId)) {
throw new SomeException();
}
// do code that needs lock
if(!lockService.unlock(entityId)) {
throw new SomeException();
}
}
}
So basically, I would use a common interface and just make TransactionalLockService.unlock() sort of a no-op function that always returns true or, if achievable, more desirable: return the result of some probe mechanism to find out if the transaction with id has correctly ended.
Another idea would be to have a Lock interface, that a LockService returns (very abbreviated example):
interface Lock {
Boolean unlock();
}
interface LockService {
Lock acquire(Long id);
}
class TransactionalLock
implements Lock {
private Long id;
TransactionalLock(Long id) {
this.id = id;
}
#Override
Boolean unlock() {
// again, either simply return true
return true;
// ...or some result that verifies the transaction has ended
return verifyTransactionHasEnded(id);
}
}
class SomeService {
private final LockService lockService;
SomeService(LockService lockService) {
this.lockService = lockService;
}
void aMethod(Long entityId) {
Lock lock = lockService.acquire(entityId);
if(lock == null) {
throw new SomeException();
}
// do code that needs lock
if(!lock.unlock()) {
throw new SomeException();
}
}
}
...etc., but that could get very complex very fast, because the Lock implementations need their own mechanism to unlock themselves.
This might still not be exactly what you're looking for, but hopefully it gives you some ideas.

Sorting with SortableDataProvider and Hibernate

I have the following code:
PersonDao.java
#Repository
#Transactional
public class PersonDao implements PersonDaoIface {
Object property;
String order;
#Autowired
private SessionFactory sessionFactory;
public PersonDao() {
}
public PersonDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#SuppressWarnings("unchecked")
#Override
public List<Person> getAll(long first, long count) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class);
this.setPaging(criteria, first, count);
addSort(criteria);
return criteria.list();
}
#Override
public long getAllCount() {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class)
.setProjection(Projections.rowCount());
Long i = (Long) criteria.uniqueResult();
return i;
}
#Override
public List<Person> getByFilter(Person person, int first, int count) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class);
criteria.add(Restrictions.eq("firstName", person.getFirstName()));
criteria.add(Restrictions.eq("lastName", person.getLastName()));
this.setPaging(criteria, first, count);
return criteria.list();
}
#Override
public long getByFilterCount(Person person) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Person.class);
criteria.add(Restrictions.eq("firstName", person.getFirstName()));
criteria.add(Restrictions.eq("lastName", person.getLastName()));
criteria.setProjection(Projections.rowCount());
Long result = (Long) criteria.uniqueResult();
return result;
}
private void setPaging(Criteria criteria, long first, long count) {
criteria.setFirstResult((int) first);
criteria.setMaxResults((int) count);
}
private void addSort(Criteria criteria) {
if (property != null) {
if (order.equalsIgnoreCase(SortOrder.ASCENDING.toString())) {
criteria.addOrder(Order.asc((String)property));
} else {
criteria.addOrder(Order.desc((String)property));
}
}
}
#Override
public void setSort(Object property, String order) {
this.property = property;
this.order = order;
}
}
SortableDataProvider
public class PersonSortableDataProvider extends SortableDataProvider {
private transient PersonDaoIface personDao;
public PersonSortableDataProvider(PersonDaoIface personDao) {
this.personDao = personDao;
}
public PersonSortableDataProvider() {
}
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Iterator<Person> iterator(long first, long count) {
System.out.println(getSort());
return personDao.getAll(first, count).iterator();
}
#Override
public long size() {
long result = personDao.getAllCount();
return result;
}
#Override
public IModel<Person> model(final Object object) {
return new AbstractReadOnlyModel<Person>() {
#Override
public Person getObject() {
return (Person) object;
}
};
}
}
A panel with a data table using the sortable data provider
public DataDisplayPanel(String id) {
super(id);
List<IColumn> columns = new ArrayList<IColumn>();
columns.add(new PropertyColumn(new Model<String>("First Name"), "firstName"));
columns.add(new PropertyColumn(new Model<String>("Last Name"), "lastName"));
AjaxFallbackDefaultDataTable table = new AjaxFallbackDefaultDataTable("personData", columns,
personSortableDataProvider, 8);
table.addTopToolbar(new HeadersToolbar(table, personSortableDataProvider));
add(table);
}
I have paging done no problem but I am having trouble understanding how to get sorting working with hibernate, I can see how you could do the sorting from the java side of things but given that I could potentially get large data sets back I don't like this idea.
Given my code above does anyone have a way of getting the data table, on click of either first name or last name to then make the same query found in the iterator with the additional order by clause.
You are almost there. You just need an:
addOrder(Order.asc(columnName))
The doc is here.
To anyone that encounters this situation I have the following setup:
hibernate 4, spring 4 and wicket 6
I inject using Spring and it seems wicket and spring get confused if you inject within the SortableDataProvider.
I don't know what exactly happens; when i step over the project I will have a better idea but it appears setSort is not getting set correctly, when i move the Dao class out of sortable data provider and into the page and inject it there, then pass the dao instance into sortable data provider the sorting works correctly.

Map some boolean properties as enum Set in Hibernate

I have an entity which has some BIT fields into the database:
editable
needs_review
active
These fields are mapped against boolean fields in its Java class using Hibernate 3.6.9 version. That forces me to write an interface method for each List of entities I want to get:
List<Entity> listEditables();
List<Entity> listReviewNeeded();
List<Entity> listActives();
Or write a general interface method to achieve a combination of them:
List<Entity> listEntities(boolean editables, boolean reviewNeeded, boolean actives);
That second choice looks greater, but if I add another field in the future there will be a need to modify the interface itself (and every line of code coupled to it).
So I decided I can express it as an enumeration Set:
public enum EntityType{
EDITABLE, REVIEW_NEEDED, ACTIVE
}
//That way there's no need to change interface method's signature
List<Entity> listEntities(Set<EntityType> requiredTypes);
It makes sense that being an enumeration match what I want to achieve, the Entity type itself should have its own Set<EntityType>:
public class Entity{
Set<EntityType> entityTypes;
}
However instead of that I have the mapped booleans which logically match that Set. Then my question, is there any way to map Set<EntityType> entityTypes in hibernate based in that BIT fields or do I have to manage that logic myself having them as boolean?
UPDATE
Having them mapped as a Set implies the possibility of querying for a List using an in clause, if not it would imply an extra step for conversion between my controller and model codes.
Set<EntityType> typesSet = Sets.newHashSet(EntityType.EDITABLE, EntityType.REVIEW_NEEDED);
//Obtains a list of every single entity which is EDITABLE or REVIEW_NEEDED
session.createCriteria(Entity.class).addRestriction(Restrictions.in("entityTypes",typeSet)).list();
I think I have a solution for you. What you are interested in is a CompositeUserType.
As an example lets use a InetAddress composite user type I wrote lately to map a 128bit IPv6 Address / IPv4Address object to two 64bit long properties inside a user account entity.
The signupIp:InetAddress is mapped towards two columns (there is no column count limit or alike) using:
#Columns(columns = {#Column(name = "ip_low", nullable = true), #Column(name = "ip_high", nullable = true)})
private InetAddress signupIp;
And the interesting part of the implementation looks like this:
public class InetAddressUserType implements CompositeUserType {
#Override
public String[] getPropertyNames() {
return new String [] {"ipLow", "ipHigh"};
}
#Override
public Type[] getPropertyTypes() {
return new Type [] { LongType.INSTANCE, LongType.INSTANCE};
}
#Override
public Object getPropertyValue(Object component, int property) throws HibernateException {
if(component != null)
return toLong((InetAddress)component)[property];
else
return null;
}
#Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws HibernateException, SQLException {
if(value != null) {
long [] longs = toLong((InetAddress)value);
st.setLong(index, longs[0]);
st.setLong(index + 1, longs[1]);
}
else {
st.setNull(index, LongType.INSTANCE.sqlType());
st.setNull(index + 1, LongType.INSTANCE.sqlType());
}
}
#Override
public void setPropertyValue(Object component, int property, Object value)
throws HibernateException {
throw new RuntimeException("This object is immutable");
}
#Override
public Class<?> returnedClass() {
return InetAddress.class;
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
return x != null ? x.equals(y) : null == y;
}
#Override
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
#Override
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Long ipLow = rs.getLong(names[0]);
if(!rs.wasNull()) {
Long ipHigh = rs.getLong(names[1]);
try {
return fromLong(new long [] {ipLow, ipHigh});
} catch (UnknownHostException e) {
throw new HibernateException("Failed to get InetAddress: ip = " + ipHigh + " + " + ipLow, e);
}
}
else
return null;
}
#Override
public Object deepCopy(Object value) throws HibernateException {
if(value != null)
try {
return InetAddress.getByAddress(((InetAddress)value).getAddress());
} catch (UnknownHostException e) {
throw new RuntimeException("Impossible Exception: " + e.getMessage(), e);
}
else
return null;
}
#Override
public boolean isMutable() {
return false;
}
...
}
Note that I flexibly switch between Inet4Address and Inet6Address instances depending on the values of ipLow and ipHigh. The composite is marked as immutable and you need to check the documentation and the examples in the Hibernate source code (build in composite user types).
In a similar way you can map your meaningful bit properties. You can query those bits by using a single Restriction.eq refering to your EnumType. You can use the equals method to check the properties object. And if you need to refer to a special mapped bit you can use the dot notation like in signupIp.ipLow to refer to the ipLow property/column.
I guess this is what you are looking for.
Update:
In the end it boils down to define the right order of your properties. Hibernate will always use integer index values to access each property:
//immutable for simplicity
class Status {
private final boolean editable;
private final boolean needsReview;
private final boolean active;
//... constructor + isEditable etc..
}
In your StatusCompositeType class:
public String[] getPropertyNames() {
return new String [] {"editable", "needsReview", "active"};
}
public Type[] getPropertyTypes() {
return new Type [] { BooleanType.INSTANCE, LongType.INSTANCE};
}
public Object getPropertyValue(Object component, int property) throws HibernateException {
if(component != null) {
Status status = (Status)component;
switch(property) {
case 1: return status.isEditable();
case 2: return status.isReviewNeeded();
case 3: return status.isActive();
default: throw new IllegalArgumentException();
}
}
else
return null; //all columns can be set to null if you allow a entity to have a null status.
}
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws HibernateException, SQLException {
if(value != null) {
Status status = (Status)value;
st.setBoolean(index, status.isEditable());
st.setBoolean(index + 1, status.isReviewNeeded());
st.setBoolean(index + 2, status.isActive());
}
else {
st.setNull(index, BooleanType.INSTANCE.sqlType());
st.setNull(index + 1, BooleanType.INSTANCE.sqlType());
st.setNull(index + 2, BooleanType.INSTANCE.sqlType());
}
}
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Boolean isEditable = rs.getBoolean(names[0]);
if(!rs.wasNull()) {
Boolean isReviewNeeded = rs.getBoolean(names[1]);
Boolean isActive = rs.getBoolean(names[2]);
return new Status(isEditable, isReviewNeeded, isActive);
}
else
return null;
}
The rest is straight forward. Remember to implement equals and hashcode for the user type and add the type to the configuration before you create your sessionFactory.
Once you have everything in place you can create a criteria search and use:
//search for any elements that have a status of editable, no reviewNeeded and is not active (true false false).
criteria.add(Restrictions.eq("status", new Status(true, false, false));
Now your listEntities method may become either: listEntities(Status status) or listEntities(boolean editable, boolean reviewNeeded, boolean isActive).
If you need additional information just check the CompositeType and BasicType implementations Hibernate provides within its own sourcecode (look for implementors of CompositeType and BasicType). Understanding those helps alot to use and learn this intermediate level knowledge of Hibernate.
After some brainstorming, I've gone to a workaround which I consider the second best one being imposible to map an enum for the booleans in Hibernate. This is how I have my Entity class looks now:
public class Entity{
private boolean editable;
private boolean needsReview;
private boolean active;
//getters and setters
}
My listing method is implemented as this:
public List<Entity> listEntities(Set<EntityType> requiredTypes){
Criteria cri = session.createCriteria(Entity.class);
if (requiredTypes.contains(EntityType.EDITABLE)){
cri.addRestriction(Restrictions.eq("editable",true));
}
if (requiredTypes.contains(EntityType.NEEDS_REVIEW)){
cri.addRestriction(Restrictions.eq("needsReview",true));
}
if (requiredTypes.contains(EntityType.ACTIVE)){
cri.addRestriction(Restrictions.eq("active",true));
}
return cri.list();
}
Not bad, but don't know if it's the only way to go with that!
I don't think hibernate provides a way to manage the mappings the way you're describing. You can create your own UserType (https://community.jboss.org/wiki/Java5EnumUserType) but every time you add a new enum value you will have to change the logic in the UserType to map the new field as well.
The alternative will be to convert this into a one to many relationship. Your point is basically that if you want to add more fields you will have to change the signature of listEntities but also you will have to modify your table.
So, instead you can create a table that will contain your entity types and have a #OneToMany` relationship to it from your entity. For example:
Define your flags as required:
public enum Flags {
EDITABLE, REVIEW_NEEDED, ACTIVE
}
Create a one-to-many relationship to EntityType:
#Entity
#Table( name="entity" )
public class Entity implements Serializable {
#OneToMany(mappedBy = "entity")
public Set<EntityType> getEntityTypes() {
return entityTypes;
}
And a many-to-one to Entity:
#Entity
#Table( name="entityType" )
public class EntityType implements Serializable {
#Id
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ENTITY_ID")
private Entity entity;
#Enumerated(EnumType.STRING)
private Flag entityType;
...
}
PD: Please note the code is just an example and is not complete or tested.

Categories

Resources