2

we have to use JPASQLQueries for complicated queries with joins on arbitrary columns and subqueries. One such query returns a string from the DB and should project this to an enum into a DTO. This mapping fails with "illegal argument type" when trying to call the setter on the DTO for that particular value.
Mapping to an entity with the same structure as the DTO works.

This is the query I use:

    final QOrderHeader orderHeader = QOrderHeader.orderHeader;
    QOrderHeader orderGroup = new QOrderHeader("orderGroup");
    QOrderPosition orderPosition = QOrderPosition.orderPosition;

    SQLTemplates templates = new OracleTemplates();
    JPASQLQuery orderQuery = new JPASQLQuery(em, templates);
    Predicate preds = OrderHeaderPredicate.matchesSearchCriteria(searchCriteria);

    // select from entity metadata, bind onto DTO, use entity metadata
    List<OrderHeaderDTO> orderHeaderWithInfos = orderQuery //
            .from(orderHeader) //
            .list(Projections.bean(OrderHeaderDTO.class, //
                    .. some values left out
                    orderHeader.orderGroup, //
                    orderHeader.orderTypeCode, //
                    orderHeader.stateCode, //
                    orderHeader.stateReason, //
                    orderHeader.testNumber0,
                    orderHeader.testNumber1
                    )); //

The query fails when trying to set the orderTypeCode on the DTO (stateCode dito).
This is the entity:

  @Entity
  @Table(name = "ORDERHEADER", uniqueConstraints = { @UniqueConstraint(columnNames = { "orderCode" }) })
  public class OrderHeader extends BaseEntity {

      protected String orderGroup;            // no problem
      protected OrderTypeCode orderTypeCode;  // illegal argument type when calling setter
      protected OrderHeaderState stateCode;   // illegal argument type when calling setter
      protected float testNumber0;
      protected double testNumber1;

      public OrderHeader() {
          //DO NOT REMOVE. REQUIRED BY HIBERNATE.
      }

      public OrderHeader(OrderHeaderDTO dto) {

          super(dto);

          orderGroup = dto.getOrderGroup();
          orderTypeCode = dto.getOrderTypeCode();
          stateCode = dto.getStateCode();
          testNumber0 =  dto.getTestNumber0();
          testNumber1 = dto.getTestNumber1();
      }

      @Override
      @Id
      @Column(name = "ID")
      @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "HibSOrderheader")
      @SequenceGenerator(name = "HibSOrderheader", sequenceName = "SOrderheader", allocationSize = 1)
      public long getId() {
          return id;
      }

      @Size(max = 30)
      @Column(name = "ORDERGROUP", length = 30)
      public String getOrderGroup() {
          return orderGroup;
      }

      public void setOrderGroup(String orderGroup) {
          this.orderGroup = orderGroup;
      }

      @Enumerated(EnumType.STRING)
      @Column(name = "ORDERTYPECODE")
      public OrderTypeCode getOrderTypeCode() {
          return orderTypeCode;
      }

      public void setOrderTypeCode(OrderTypeCode orderTypeCode) {
          this.orderTypeCode = orderTypeCode;
      }

      @Enumerated(EnumType.STRING)
      @Column(name = "STATECODE", columnDefinition = "varchar2(20)")
      public OrderHeaderState getStateCode() {
          return stateCode;
      }

      protected void setStateCode(OrderHeaderState stateCode) {
          this.stateCode = stateCode;
      }

      @Column(name = "TESTNUMBER0")
      public float getTestNumber0() {
          return testNumber0;
      }

      public void setTestNumber0(float testNumber0) {
          this.testNumber0 = testNumber0;
      }

      @Column(name = "TESTNUMBER1")
      public double getTestNumber1() {
          return testNumber1;
      }

      public void setTestNumber1(double testNumber1) {
          this.testNumber1 = testNumber1;
      }

  } 

and the enum:

   public enum OrderTypeCode {
        NORMAL,
        INVENTORY,
        TRANSFER,
        RELOCATE
    }

and the DTO:

    public class OrderHeaderDTO extends BaseEntityDTO {

        private String orderGroup;
        private OrderTypeCode orderTypeCode;
        private OrderHeaderState stateCode;
        private float testNumber0;
        private double testNumber1;

        public OrderHeaderDTO() {
            super();
        }

        @QueryProjection
        public OrderHeaderDTO(IBaseEntity base, String orderCode,
                String orderGroup, OrderTypeCode orderTypeCode, int hostId, int priority, String creationMode,
                String shippingMode, String stagingArea, Date requestedDeliveryTime, String deliveryNote,
                String deliveryCode, String customerCode, String customerOrderCode, String headerText,
                OrderHeaderState stateCode, String stateReason, Date stateTime, List<OrderPositionDTO> orderPosition, float testNumber0,
        double testNumber1) {
            super(base);
            this.orderGroup = orderGroup;
            this.orderTypeCode = orderTypeCode;
            this.stateCode = stateCode;
            this.testNumber0 = testNumber0;
            this.testNumber1 = testNumber1;
        }

        @QueryProjection
        public OrderHeaderDTO(long id, long version, Date creationTime, Date lastUpdateTime,
                String orderGroup, OrderTypeCode orderTypeCode, OrderHeaderState stateCode,
                float testNumber0, double testNumber1) {
            super(id, version, creationTime, lastUpdateTime);
            this.orderGroup = orderGroup;
            this.orderTypeCode = orderTypeCode;
            this.stateCode = stateCode;
            this.testNumber0 = testNumber0;
            this.testNumber1 = testNumber1;
        }

        /**
         * Copy constructor (shallow copy)
         * @param arg Original value
         */
        public OrderHeaderDTO(OrderHeaderDTO arg) {
            super(arg);
            orderGroup = arg.orderGroup;
            orderTypeCode = arg.orderTypeCode;
            creationTime = arg.creationTime;
            stateCode = arg.stateCode;
            testNumber0 = arg.testNumber0;
            testNumber1 = arg.testNumber1;
        }

        public String getOrderGroup() {
            return orderGroup;
        }

        @Enumerated(EnumType.STRING)
        public OrderTypeCode getOrderTypeCode() {
            return orderTypeCode;
        }

        public OrderHeaderState getStateCode() {
            return stateCode;
        }
        public void setOrderGroup(String orderGroup) {
            this.orderGroup = orderGroup;
        }

        public void setOrderTypeCode(OrderTypeCode orderTypeCode) {
            this.orderTypeCode = orderTypeCode;
        }
        public void setStateCode(OrderHeaderState stateCode) {
            this.stateCode = stateCode;
        }

        public float getTestNumber0() {
            return testNumber0;
        }

        public void setTestNumber0(float testNumber0) {
            this.testNumber0 = testNumber0;
        }

        public double getTestNumber1() {
            return testNumber1;
        }

        public void setTestNumber1(double testNumber1) {
            this.testNumber1 = testNumber1;
        }

    }

and finally the stack trace thrown:

      org.springframework.dao.InvalidDataAccessApiUsageException: argument type mismatch; nested exception is java.lang.IllegalArgumentException: argument type mismatch
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:296)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:107)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy55.searchOrderWithInfoForCriteria(Unknown Source)
    at com.stoecklin.wms.dbunittest.implementation.repository.OrderHeaderCustomRepoIT.test_noCriteria(OrderHeaderCustomRepoIT.java:188)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
  Caused by: java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.mysema.util.BeanMap.put(BeanMap.java:330)
    at com.mysema.util.BeanMap.put(BeanMap.java:51)
    at com.mysema.query.types.QBean.newInstance(QBean.java:250)
    at com.mysema.query.support.NumberConversions.newInstance(NumberConversions.java:65)
    at com.mysema.query.jpa.FactoryExpressionTransformer.transformTuple(FactoryExpressionTransformer.java:50)
    at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:95)
    at org.hibernate.loader.custom.CustomLoader.getResultList(CustomLoader.java:431)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2342)
    at org.hibernate.loader.Loader.list(Loader.java:2337)
    at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:338)
    at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:1827)
    at org.hibernate.internal.AbstractSessionImpl.list(AbstractSessionImpl.java:231)
    at org.hibernate.internal.SQLQueryImpl.list(SQLQueryImpl.java:157)
    at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:268)
    at com.mysema.query.jpa.sql.AbstractJPASQLQuery.getResultList(AbstractJPASQLQuery.java:193)
    at com.mysema.query.jpa.sql.AbstractJPASQLQuery.list(AbstractJPASQLQuery.java:224)
    at com.stoecklin.wms.repository.implementation.OrderHeaderRepositoryImpl.searchJPASQLIntoDTO(OrderHeaderRepositoryImpl.java:347)
    at com.stoecklin.wms.repository.implementation.OrderHeaderRepositoryImpl.searchOrderWithInfoForCriteria(OrderHeaderRepositoryImpl.java:517)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:344)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:319)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    ... 37 more

Here are now the questions:

  1. How can we provide type conversion expressions for some columns, namely enums, in projections?
  2. Is it feasible to use the generated entity metadata (from apt-maven-plugin) for JPASQL?

Any help is appreciated.

I also explored various other variants with not much better results:

  1. Using native SQL metatdata (from querydsl-maven-plugin) for the projection did not change much but revealed additional type mapping problems.
  2. Selecting from native SQL metatdata had the same behavior.
  3. Projecting into the entity works but this is not the intention, because we want directly fill DTOs (also with synthesized values). If we use entities then we have to copy the entity into the DTO afterwards.

EDIT: Versions used:

QueryDSL: 3.2.4
Spring: 3.2.2.RELEASE
Hibernate:4.2.6.Final

The finaly query we want to use should be this (SQL only):

   SELECT
   oh.*,
   (select count(id)                 -- correlated subquery
      from orderposition p
     where p.orderHeaderID = oh.id) as nofPosPerOrder,
   og.mostImportantPrioInGroup,
   og.earliestDeliveryTime,
   og.earliestCreationTime
  FROM orderHeader oh LEFT JOIN      -- left join with aggregating query for order group
       (SELECT g.orderGroup,
               min(g.priority)             as mostImportantPrioInGroup,
               min(g.requestedDeliveryTime as earliestDeliveryTime,
               min(g.requestedCreationTime as earliestCreationTime
          FROM orderHeader g
          GROUP by g.orderGroup) og
     ON oh.orderGroup = og.orderGroup
  WHERE ?????
  ORDER BY .
M. Lindenmann
  • 81
  • 1
  • 2
  • 6

0 Answers0