user6778654 user6778654 - 4 years ago 297
Java Question

Spring Data Jpa and Specification - how to work with ManyToOne and ManyToMany relations?

I have a simple model in my project.

[UpdatePackage] >- (ManyToOne) - [Version] -< [UseCase] - (ManyToMany)

public class UpdatePackage implements Comparable<UpdatePackage> {

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = COLUMN_ORIG_VERSION, nullable = true)
private Version origVersion;

// setters and getters
}

@Entity
@Table(name = Version.TABLE_NAME)
public class Version {

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name = JVUC_TABLE, joinColumns = { @JoinColumn(name = JVUC_COLUMN_VERSION, referencedColumnName = COLUMN_ID) }, inverseJoinColumns = { @JoinColumn(name = JVUC_COLUMN_USECASE, referencedColumnName = UseCase.COLUMN_ID) })
private final Set<UseCase> useCases = new HashSet<UseCase>();

// setters and getters
}

@Entity
@Table(name = UseCase.TABLE_NAME)
public class UseCase {

@Column(name = COLUMN_NAME, nullable = false)
private String name;

// setters and getters
}


For implementation of filter I would like to use Spring Data Jpa and Specification from spring.data.jpa.domain

For instance I would like to find list of UpdatePackage with given usecase names.

I understand that for ManyToOne relation I need use Join and for ManyToMany I need to use Fetch.

My implementation of Specification interface looks like this:

public static Specification<UpdatePackage> useCaseNames(final List<String> useCaseNames) {
return new Specification<UpdatePackage>() {

@Override
public Predicate toPredicate(Root<UpdatePackage> root, CriteriaQuery<?> query,
CriteriaBuilder cb) {
final Join<UpdatePackage, Version> version = root.join(UpdatePackage_.destVersion,
JoinType.LEFT);

Fetch<Version, UseCase> useCase = version.fetch(Version_.useCases, JoinType.LEFT);
return null;
// return useCase.get(UseCase_.name).in(useCaseNames);

}
};
}


When I run a integration test I got NPException in line:

Fetch<Version, UseCase> useCase = version.fetch(Version_.useCases, JoinType.LEFT);


because fields joins and fetches of object version are null.

I don't know what I do in wrong way and I cannot find any answer in Internet.

Does anyone know what is wrong in this code?

Stack:
java.lang.NullPointerException
at org.hibernate.ejb.criteria.path.AbstractFromImpl.constructJoin(AbstractFromImpl.java:261)
at org.hibernate.ejb.criteria.path.AbstractFromImpl.fetch(AbstractFromImpl.java:549)

Answer Source

I've found a solution. I had a bug in static model.

static model From:

public static volatile SingularAttribute<Version, UseCase> useCases;

To:

public static volatile SetAttribute<Version, UseCase> useCases;

and in implementation of specification:

public static Specification<UpdatePackage> useCaseNames(final List<String> useCaseNames) {
        return new Specification<UpdatePackage>() {

            @Override
            public Predicate toPredicate(Root<UpdatePackage> root, CriteriaQuery<?> query,
                    CriteriaBuilder cb) {               
                final Join<UpdatePackage, Version> version = root.join(UpdatePackage_.destVersion,
                        JoinType.LEFT);
                final Join<Version, UseCase> useCase = version.join(Version_.useCases);
                return useCase.get(UseCase_.name).in(useCaseNames);
            }
        };
    }
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download