Eduard Korenschi
Eduard Korenschi

Reputation: 236

Generic way to initialize a JPA 2 lazy association

So, the question at hand is about initializing the lazy collections of an "unknown" entity, as long as these are known at least by name. This is part of a more wide effort of mine to build a generic DataTable -> RecordDetails miniframework in JSF + Primefaces.
So, the associations are usually lazy, and the only moment i need them loaded is when someone accesses one record of the many in the datatable in order to view/edit it. The issues here is that the controllers are generic, and for this I also use just one service class backing the whole LazyLoading for the datatable and loading/saving the record from the details section. What I have with come so far is the following piece of code:

public <T> T loadWithDetails(T record, String... associationsToInitialize) {
    final PersistenceUnitUtil pu = em.getEntityManagerFactory().getPersistenceUnitUtil();
    record = (T) em.find(record.getClass(), pu.getIdentifier(record));
    for (String association : associationsToInitialize) {
        try {
            if (!pu.isLoaded(record, association)) {
                loadAssociation(record, association);
            }
        } catch (..... non significant) {
            e.printStackTrace(); // Nothing else to do
        }
    }
    return record;
}

private <T> void loadAssociation(T record, String associationName) throws IntrospectionException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
    BeanInfo info = Introspector.getBeanInfo(record.getClass(), Object.class);
    PropertyDescriptor[] props = info.getPropertyDescriptors();
    for (PropertyDescriptor pd : props) {
        if (pd.getName().equals(associationName)) {
            Method getter = pd.getReadMethod();
            ((Collection) getter.invoke(record)).size();
        }
    }
    throw new NoSuchFieldException(associationName);
}

And the question is, did anyone start any similar endeavor, or does anyone know of a more pleasant way to initialize collections in a JPA way (not Hibernate / Eclipselink specific) without involving reflection?
Another alternative I could think of is forcing all entities to implement some interface with

Object getId();
void loadAssociations();

but I don't like the idea of forcing my pojos to implement some interface just for this.

Upvotes: 0

Views: 414

Answers (1)

uaiHebert
uaiHebert

Reputation: 1912

With the reflection solution you would suffer the N+1 effect detailed here: Solve Hibernate Lazy-Init issue with hibernate.enable_lazy_load_no_trans

You could use the OpenSessionInView instead, you will be affected by the N+1 but you will not need to use reflection. If you use this pattern your transaction will remain opened until the end of the transaction and all the LAZY relationships will be loaded without a problem.

For this pattern you will need to do a WebFilter that will open and close the transaction.

Upvotes: 1

Related Questions