Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data JPA: return empty List instead of null

I have a basic SpringBoot app. using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file. I have this method defined in a Repository that extends from

CrudRepository<HotelPrice, Long>, PagingAndSortingRepository<HotelPrice, Long> {

This is the method

List<HotelPrice> getByHotelAndUpdateDateGreaterThan (Hotel hotel, Date date, PageRequest pageRequest);

and the service:

public List<HotelPrice> getMonthlyMinPriceDate(Hotel hotel) {
        return hotelPriceRepository.getByHotelAndUpdateDateGreaterThan
                (hotel, DateUtils.monthlyDate(), new PageRequest(1, 1,new Sort(Sort.Direction.DESC, "price")));
    }

But when I run a Junit Test I got this error:

 java.util.NoSuchElementException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1042)
at org.springframework.data.jpa.repository.query.CriteriaQueryParameterBinder.bind(CriteriaQueryParameterBinder.java:65)
at org.springframework.data.jpa.repository.query.ParameterBinder.bind(ParameterBinder.java:101)
at org.springframework.data.jpa.repository.query.ParameterBinder.bindAndPrepare(ParameterBinder.java:161)
at org.springframework.data.jpa.repository.query.ParameterBinder.bindAndPrepare(ParameterBinder.java:152)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.invokeBinding(PartTreeJpaQuery.java:236)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.createQuery(PartTreeJpaQuery.java:157)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.doCreateQuery(PartTreeJpaQuery.java:86)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.createQuery(AbstractJpaQuery.java:190)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:123)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:87)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:116)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:499)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:477)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy118.getByHotelAndUpdateDateGreaterThan(Unknown Source)
at com.booking.backend.service.HotelPriceService.getWeeklyMinPriceDate(HotelPriceService.java:85)
at com.booking.backend.service.HotelPriceService$$FastClassBySpringCGLIB$$cabd5c58.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
at com.booking.backend.service.HotelPriceService$$EnhancerBySpringCGLIB$$9dd8e53b.getWeeklyMinPriceDate(<generated>)
at com.booking.HotelPriceServiceTests.testGetWeeklyMaxPriceDate(HotelPriceServiceTests.java:125)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)Hotel
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:539)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:761)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:461)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:207)

Would be possible to return an empty list instead of a null ????

I also set the app. property spring.jpa.properties.hibernate.format_sql=true

But I don't see that any sql in the console

@Entity
@Table(name="t_Hotel_price")
public class HotelPrice implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public HotelPrice() {
    }


    public HotelPrice(Hotel Hotel) {
        this.Hotel = Hotel;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;


    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "Hotel_id")
    Hotel Hotel;

    float price;

    @Column(name = "update_date")
    private Date updateDate;

    public Hotel getHotel() {
        return Hotel;
    }

    public void setHotel(Hotel Hotel) {
        this.Hotel = Hotel;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }



    public Long getId() {
        return id;
    }


    public void setId(Long id) {
        this.id = id;
    }


    public Date getUpdateDate() {
        return updateDate;
    }


    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }


    @Override
    public String toString() {
        return "HotelPrice [Hotel=" + Hotel + ", price=" + price + ", updateDate=" + updateDate + "]";
    }
}

and

@Entity
@Table(name="t_Hotel")
public class Hotel  implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;    

    private String HotelId;

    private String symbol;

    private float histMaxPrice;

    private int numMaxPriceEvents=0;

    @Column(name = "update_date")
    @Convert(converter = LocalDateTimeAttributeConverter.class)
    private LocalDateTime histMaxPriceDate;

    @OneToMany(mappedBy="Hotel", fetch=FetchType.LAZY, orphanRemoval=true)
    private List<HotelDailyPrice> dailyPrice;

    @OneToMany(mappedBy="Hotel", fetch=FetchType.LAZY, orphanRemoval=true)
    private List<HotelPrice> price;

    @OneToMany(mappedBy="Hotel", fetch=FetchType.LAZY, orphanRemoval=true)
    private List<HotelPriceSummary> summary;


    public Hotel() {
        super();
    }

    public Hotel(String HotelId) {
        super();
        this.HotelId = HotelId;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getHotelId() {
        return HotelId;
    }

    public void setHotelId(String HotelId) {
        this.HotelId = HotelId;
    }

    public float getHistMaxPrice() {
        return histMaxPrice;
    }

    public void setHistMaxPrice(float histMaxPrice) {
        this.histMaxPrice = histMaxPrice;
    }

    public LocalDateTime getHistMaxPriceDate() {
        return histMaxPriceDate;
    }

    public void setHistMaxPriceDate(LocalDateTime histMaxPriceDate) {
        this.histMaxPriceDate = histMaxPriceDate;
    }

    public String getSymbol() {
        return symbol;
    }

    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((HotelId == null) ? 0 : HotelId.hashCode());
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Hotel other = (Hotel) obj;
        if (HotelId == null) {
            if (other.HotelId != null)
                return false;
        } else if (!HotelId.equals(other.HotelId))
            return false;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Hotel [id=" + id + ", HotelId=" + HotelId + ", histMaxPrice=" + histMaxPrice
                + ", histMaxPriceDate=" + histMaxPriceDate + "]";
    }

    public int getNumMaxPriceEvents() {
        return numMaxPriceEvents;
    }

    public void setNumMaxPriceEvents(int numMaxPriceEvents) {
        this.numMaxPriceEvents = numMaxPriceEvents;
    }

    public List<HotelDailyPrice> getDailyPrice() {
        return dailyPrice;
    }

    public void setDailyPrice(List<HotelDailyPrice> dailyPrice) {
        this.dailyPrice = dailyPrice;
    }

    public List<HotelPrice> getPrice() {
        return price;
    }

    public void setPrice(List<HotelPrice> price) {
        this.price = price;
    }

    public List<HotelPriceSummary> getSummary() {
        return summary;
    }

    public void setSummary(List<HotelPriceSummary> summary) {
        this.summary = summary;
    }
}

I also tried to use Page<HotelPrice> but then I got the error:

Paging query needs to have a Pageable parameter!

This is the function DateUtils.monthlyDate()

LocalDate now = LocalDate.now().minusDays(numDaysToSubstract); return Date.from(now.atStartOfDay(ZoneId.systemDefault()).toInstant());

like image 500
Nunyet de Can Calçada Avatar asked Feb 28 '18 14:02

Nunyet de Can Calçada


People also ask

Does Spring Data JPA return empty list or null?

Spring JPA Query returns Null instead of List.

How do I ignore NULL values in JPA?

You can ignore null fields at the class level by using @JsonInclude(Include. NON_NULL) to only include non-null fields, thus excluding any attribute whose value is null. You can also use the same annotation at the field level to instruct Jackson to ignore that field while converting Java object to json if it's null.

How does JPA handle null values?

The JPA specification defines that during ordering, NULL values shall be handled in the same way as determined by the SQL standard. The standard specifies that all null values shall be returned before or after all non-null values. It's up to the database to pick one of the two options.

What does findById return in JPA?

Its findById method retrieves an entity by its id. The return value is Optional<T> . Optional<T> is a container object which may or may not contain a non-null value. If a value is present, isPresent returns true and get returns the value.


1 Answers

I have noticed few thing in the question: (update the answer)

  1. No need to extends both CrudRepository<HotelPrice, Long>, PagingAndSortingRepository<HotelPrice, Long>. PagingAndSortingRepository<HotelPrice, Long> internally extends CrudRepository<HotelPrice, Long>.
  2. Instead of passing the entire Hotel object you can pass only primary key of Hotel (id). Below given the syntax for it: Page<HotelPrice> getByHotelIdAndUpdateDateGreaterThan (Long id, Date date, Pageable pageable);. You can send the PageRequest from service but you must have Pageable in Repository.
  3. When you use pagination, you won't get the response as List<HotelPrice>, Instead of that you will get the Page<HotelPrice> object. To extract the List<HotelPrice> use the below: List<HotelPrice> hotelPrice = hotelPricePage.get().getContent();.
like image 89
Praveen D Avatar answered Oct 14 '22 18:10

Praveen D