Nuñito Calzada
Nuñito Calzada

Reputation: 2136

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());

Upvotes: 6

Views: 14040

Answers (2)

Aleksandar
Aleksandar

Reputation: 4154

You should check two things:

  1. What is the method DateUtils.monthlyDate() returning? Is it the same Date as the Date from Your repository method, getByHotelAndUpdateDateGreaterThan (Hotel hotel, Date date, PageRequest pageRequest)?
  2. Do You really want the page number one, and not the first page, which is at index zero? You can check that the page index is zero-based at spring's docs for the PageRequest.

Upvotes: 0

Praveen Dhasarathan
Praveen Dhasarathan

Reputation: 668

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();.

Upvotes: 3

Related Questions