Interface-Based Projections the getter method giving exception if the return type is java.sql.Timestamp

Krushna :

I am using the spring boot strater 2.2.0.BUILD-SNAPSHOT with Spirng JPA. I need to used some complex SQL with group by some I am using the native query with interface based projection, I am able retrived all the fields but getting exception for the return type of java.sql.Timestamp

Example : My Entity class

@Entity
@Table(name = "trade")
public class Trade {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "trade_id")
private long tradeId;

@Column(name = "symbol")
private String symbol;

@Column(name = "exchange")
private String exchange;

@Column(name = "segment")
private String segment;

@Column(name = "clinet_trade_id")
private long clientTradeId;

@Column(name = "order_id")
private long orderId;

@Column(name = "price")
private double price;

@Column(name = "sell_type")
private String tradeType;

@Column(name = "quantity")
private int quantity;

@Column(name = "trade_date_time")
private Timestamp tradeDateTime;
}

The repository interface with the projection interface

@Repository("TradeRepository")
public interface TradeRepository extends JpaRepository<Trade, Long> {


// projection

//https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
//Interface-based Projections
//https://www.baeldung.com/spring-data-jpa-projections

@Query(value = "select symbol,date(trade_date_time) as trade_date_time , sum(quantity) as quantity , sum(quantity*price) as price  from trade where sell_type ='sell' \n" + 
        "and trader_date > ?1  and trader_date < ?2 and user_id= ?3 " + 
        "group by symbol, date(trade_date_time) " + 
        "order by symbol, date(trade_date_time) ", nativeQuery = true)
 public List<TradeView> findByNativeQuery(Timestamp fromdate, Timestamp toDate, int userId);

public static interface TradeView {
     public String getSymbol();
     public Timestamp getTradeDateTime();
     public int getQuantity();
     public double getPrice();
  }


}

Here I am getting exception for the method getTradeDateTime()

Excaption trace

java.lang.IllegalArgumentException: Projection type must be an interface!
at org.springframework.util.Assert.isTrue(Assert.java:118)
at org.springframework.data.projection.ProxyProjectionFactory.createProjection(ProxyProjectionFactory.java:100)
at org.springframework.data.projection.SpelAwareProxyProjectionFactory.createProjection(SpelAwareProxyProjectionFactory.java:45)
at org.springframework.data.projection.ProjectingMethodInterceptor.getProjection(ProjectingMethodInterceptor.java:131)
at org.springframework.data.projection.ProjectingMethodInterceptor.invoke(ProjectingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.ProxyProjectionFactory$TargetAwareMethodInterceptor.invoke(ProxyProjectionFactory.java:245)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy123.getTradeDateTime(Unknown Source)
at org.cet.stockAnalysis.repository.TradeRepositoryTest.findAllSaleTradeByDateTest(TradeRepositoryTest.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
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.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
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:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
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:190)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

Can some one guide me what can be done, I have one solution is to change the DB column name to match with entity filed name, But I feel that is not right not, there must be some solution to this.

Debug screen shot

enter image description here

Note :I am getting the exception when calling the getter method to read the value and at that time also it is going to to ProxyProjectionFactory line number 100 and at that time the type id java.sql.Timestamp and ginving the exception

Scren shot

enter image description here

The Junit test class

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE)
public class TradeRepositoryTest {

@Autowired
TradeRepository tradeRepository;

@Test
public void findAllSaleTradeByDateTest() {
    Date fromdate = new GregorianCalendar(2019, Calendar.FEBRUARY, 1).getTime();
    Date todate = new GregorianCalendar(2019, Calendar.MARCH, 31).getTime();

    Timestamp fromTimestamp= new Timestamp(fromdate.getTime());
    Timestamp toTimestamp= new Timestamp(todate.getTime());

    User user = new User();
    user.setId(1);
    List<TradeView> tradeviews =tradeRepository.findByNativeQuery(fromTimestamp, toTimestamp, 1);
    System.out.println(tradeviews.get(0).getSymbol());
    System.out.println(tradeviews.get(0).getPrice());
    System.out.println(tradeviews.get(0).getTradeDateTime() +" >>>>>> ");
    System.out.println(tradeviews.get(0).getQuantity());


    assertNotNull(tradeviews);
}

}

Edit:

With the suggestion of Simon, I change the interface return type to java.sql.Date form java.sql.Timestamp and it's work fine as my native sql return type was date, because of date funtion was used

Hence chnaging the question title and details

Simon Martinelli :

Simply us aliases the match the names in your interface. Don't use _ but tradeDateTime:

@Query(value = "select symbol, date(trade_date_time) as tradeDateTime, sum(quantity) as quantity , sum(quantity*price) as price  from trade where sell_type ='sell' \n" + 
    "and trader_date > ?1  and trader_date < ?2 and user_id= ?3 " + 
    "group by symbol, date(trade_date_time) " + 
    "order by symbol, date(trade_date_time) ", nativeQuery = true)

Reason: The column mapping in your entity is not taken to account when using native queries and interface projection.

Also make sure that you have the correct return types the interface!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=94995&siteId=1