3

How can i get list of tiket with its categories through Jpa Specification

Example model:

@Entity
@Table(name = "tickets")
public class Ticket {

@Id
private Integer id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id")
private Category 
}

Method of service:

public Page<Ticket> findAll(Pageable pageable) {
        return ticketRepository.findAll((root, query, cb) -> {
            root.join("category");
            return query.getRestriction();
        }, pageable);
}
Ivan Smorodin
  • 151
  • 3
  • 14
  • If U want category to by loaded with tickets see this answer: http://stackoverflow.com/questions/15359306/how-to-load-lazy-fetched-items-from-hibernate-jpa-in-my-controller/15360333#15360333 – SkorpEN Dec 09 '15 at 11:57
  • @Si mo, i can't get category! – Ivan Smorodin Dec 09 '15 at 12:19
  • 1
    @SkorpEN that has nothing to do with JPA Specification. – André Onuki Apr 23 '18 at 16:48
  • @AndréOnuki Spring Jpa specification is more about JpaRepository from link "Jpa Specification" is to SpringData-jpa. If U think that link should be changed then change it. anyway this question is to spring-data-jpa as seen in tag and links. – SkorpEN Apr 24 '18 at 12:48
  • 1
    @SkorpEN I understand the confusion. The question is about the Specification class of JPA, not JPA's specification. The question is indeed about JPA, but the link you posted has nothing to do with the Specification class. – André Onuki Apr 25 '18 at 13:31

2 Answers2

2

I was able to eager load the collection by using a fetch instead of a join.

public Page<Ticket> findAll(Pageable pageable) {
    return ticketRepository.findAll((root, query, cb) -> {
        root.fetch("category");
        return query.getRestriction();
    }, pageable);
}

The fetch method will use the default join type (inner). If want to load tickets with no category, you'll have to pass JoinType.LEFT as the second parameter.

André Onuki
  • 428
  • 2
  • 12
0

as they say, stackoverflow giveth, stackoverflow taketh.. I took this class off SO quite some time ago, feel free to recycle it..

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;

import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Hibernate;

public class BeanLoader {
    /**
     * StackOverflow safe, if called before json creation, cyclic object must be avoided
     */
    public static void eagerize(Object obj)  {
        if(!Hibernate.isInitialized(obj))
            Hibernate.initialize(obj);
        PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
        for (PropertyDescriptor propertyDescriptor : properties) {
            Object origProp = null;
            try {
                origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
            } catch (IllegalAccessException e) {
                // Handled, but hopefully dead code  
                origProp=null;
            } catch (InvocationTargetException e) {
                // Single catch for obsolete java developers!
                origProp=null;
            } catch (NoSuchMethodException e) {
                // Single catch for obsolete java developers!
                origProp=null;
            }
            if (origProp != null 
                    && origProp.getClass().getPackage().toString().contains("domain")) {
                eagerize(origProp, new ArrayList<String>());
            }
            if (origProp instanceof Collection) {               
                for (Object item : (Collection) origProp) {
                    if (item.getClass().getPackage().toString().contains("domain")){
                        eagerize(item, new ArrayList<String>());
                    }
                }
            }
        }
    }

    /**
     * StackOverflows if passed a bean containing cyclic fields. Call only if sure that this won't happen!
     */
    public static void eagerizeUnsafe(Object obj)  {
        if(!Hibernate.isInitialized(obj))
            Hibernate.initialize(obj);
        PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
        for (PropertyDescriptor propertyDescriptor : properties) {
            Object origProp = null;
            try {
                origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
            } catch (IllegalAccessException e) {
                // Handled, but hopefully dead code  
                origProp=null;
            } catch (InvocationTargetException e) {
                // Single catch for obsolete java developers!
                origProp=null;
            } catch (NoSuchMethodException e) {
                // Single catch for obsolete java developers!
                origProp=null;
            }
            if (origProp != null 
                    && origProp.getClass().getPackage().toString().contains("domain")) {
                eagerize(origProp);
            }
            if (origProp instanceof Collection) {               
                for (Object item : (Collection) origProp) {
                    if (item.getClass().getPackage().toString().contains("domain")){
                        eagerize(item);
                    }
                }
            }
        }
    }

    private static void eagerize(Object obj, ArrayList<String> visitedBeans)  {
        if (!visitedBeans.contains(obj.getClass().getName())){
            visitedBeans.add(obj.getClass().getName());
        } else {
            return;
        }
        if(!Hibernate.isInitialized(obj))
            Hibernate.initialize(obj);
        PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
        for (PropertyDescriptor propertyDescriptor : properties) {
            Object origProp = null;
            try {
                origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
            } catch (IllegalAccessException e) {
                // Handled, but hopefully dead code  
                origProp=null;
            } catch (InvocationTargetException e) {
                // Single catch for obsolete java developers!
                origProp=null;
            } catch (NoSuchMethodException e) {
                // Single catch for obsolete java developers!
                origProp=null;
            }
            if (origProp != null 
                    && origProp.getClass().getPackage().toString().contains("domain")) {
                eagerize(origProp, visitedBeans);
            }
            if (origProp instanceof User){
                ((User) origProp).setRelatedNra(null);
                User u=(User) origProp;
                if (u.getRelatedMps()!=null)
                    u.getRelatedMps().clear();
                if (u.getRelatedDps()!=null)
                    u.getRelatedDps().clear();
            }
            if (origProp instanceof Collection) {               
                for (Object item : (Collection) origProp) {
                    if (item.getClass().getPackage().toString().contains("domain")){
                        eagerize(item, (ArrayList<String>) visitedBeans.clone());
                    }
                }
            }
        }
    }
}

modify it as you see fit.. the method you'll call is "eagerizeUnsafe". YMMV, but this should to the trick to eagerize all the collections of a lazily initialized bean.

witchedwiz
  • 295
  • 2
  • 10