[hibernate-issues] [Hibernate-JIRA] Created: (HHH-5653) Problem setting parameter of NamedQuery via index/value args

Tonté Pouncil (JIRA) noreply at atlassian.com
Wed Oct 13 12:03:00 EDT 2010


Problem setting parameter of NamedQuery via index/value args
------------------------------------------------------------

                 Key: HHH-5653
                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-5653
             Project: Hibernate Core
          Issue Type: Bug
          Components: query-hql
    Affects Versions: 3.5.1
         Environment: Windows XP, Oracle 10g
            Reporter: Tonté Pouncil


See Hibernate Form Topic: https://forum.hibernate.org/viewtopic.php?f=1&t=1007516

I am using Hibernate-core 3.5.1-Final. I have a named query defined in my entity class. Later in my Generic DAO logic, I use the Query API to dynamically look up the named query from the session and then set the parameters on the query.
Code:
    @SuppressWarnings("unchecked")
    private Map<String, Object> getNamedQueryParameters(final String namedQueryName, Object[] queryArgs) {
        System.out.println("GenericDaoHibernateJpa.getNamedQueryParameters(): namedQueryName: " + namedQueryName);
        StringBuffer queryArgsString = new StringBuffer();
        int qaIndex = 0;
        for(Object qa: queryArgs){
            queryArgsString.append("GenericDaoHibernateJpa.getNamedQueryParameters():  queryArgs("+(qaIndex++)+"):" + qa.toString() + "\n");
        }
        System.out.println("GenericDaoHibernateJpa.getNamedQueryParameters(): Query Arguements: " + queryArgsString.toString());
       
        Map<String, Object> namedQueryParams = Collections.synchronizedMap(new HashMap<String, Object>());
        final QueryImpl<?> namedQuery = (QueryImpl<?>) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager em) {
                return em.createNamedQuery(namedQueryName);
            }
        });
               
        System.out.println("GenericDaoHibernateJpa.getNamedQueryParameters(): assigning parameters.");
       
        int i = 0;
        for(Object arguement: queryArgs){           
            namedQuery.setParameter(i++, arguement);
        }
       
       
        for(String namedQueryParamString: namedQuery.getHibernateQuery().getNamedParameters()){           
            System.out.println("GenericDaoHibernateJpa.getNamedQueryParameters(): " + namedQueryParamString + "=" + namedQuery.getParameterValue(namedQueryParamString));
            namedQueryParams.put(namedQueryParamString, namedQuery.getParameterValue(namedQueryParamString));               
        }
       
        System.out.println("GenericDaoHibernateJpa.getNamedQueryParameters(): end result: " + namedQueryParams);       
        return namedQueryParams;
    }


I get the following error message:
Code:
java.lang.IllegalArgumentException: org.hibernate.QueryParameterException: Position beyond number of declared ordinal parameters. Remember that ordinal parameters are 1-based! Position: 0
   at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:435)
   at org.generic.dao.aop.persistence.core.dao.GenericDaoHibernateJpa.getNamedQueryParameters(GenericDaoHibernateJpa.java:245)
   at org.generic.dao.aop.persistence.core.dao.GenericDaoHibernateJpa.executeFinder(GenericDaoHibernateJpa.java:187)
   at org.generic.dao.aop.persistence.core.dao.finder.FinderIntroductionInterceptor.invoke(FinderIntroductionInterceptor.java:32)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
   at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
   at $Proxy30.findProfileWithExpiredPassword(Unknown Source)
   at com.aviall.pw.manager.core.dao.TestPasswordProfileDAO.testFindingExpiredPassword(TestPasswordProfileDAO.java:67)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   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.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
   at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
   at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
   at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:44)
   at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
   at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
   at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
   at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
   at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
   at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
   at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
   at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
   at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
   at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
   at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
   at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
   at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
   at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)
Caused by: org.hibernate.QueryParameterException: Position beyond number of declared ordinal parameters. Remember that ordinal parameters are 1-based! Position: 0
   at org.hibernate.engine.query.ParameterMetadata.getOrdinalParameterDescriptor(ParameterMetadata.java:81)
   at org.hibernate.engine.query.ParameterMetadata.getOrdinalParameterExpectedType(ParameterMetadata.java:87)
   at org.hibernate.impl.AbstractQueryImpl.determineType(AbstractQueryImpl.java:445)
   at org.hibernate.impl.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:417)
   at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:429)
   ... 41 more


I've been looking at the JPA code from Hibernate and there seem to a problem with the QueryImpl class.

Code:
    public TypedQuery<X> setParameter(int position, Object value) {
        try {
            if ( isJpaPositionalParameter( position ) ) {
                this.setParameter( Integer.toString( position ), value );
            }
            else {
                query.setParameter( position - 1, value );
                registerParameterBinding( getParameter( position ), value );
            }
            return this;
        }
        catch (QueryParameterException e) {
            throw new IllegalArgumentException( e );
        }
        catch (HibernateException he) {
            throw getEntityManager().convert( he );
        }
    }


Which calls the AbstractQueryImpl.setParameter(int position, Object val) method:
Code:
   public Query setParameter(int position, Object val) throws HibernateException {
      if (val == null) {
         setParameter( position, val, Hibernate.SERIALIZABLE );
      }
      else {
         setParameter( position, val, determineType( position, val ) );
      }
      return this;
   }


Which calls the AbstractQueryImpl.determineType(int paramPosition, Object paramValue) method:
Code:
   protected Type determineType(int paramPosition, Object paramValue) throws HibernateException {
      Type type = parameterMetadata.getOrdinalParameterExpectedType( paramPosition + 1 );
      if ( type == null ) {
         type = guessType( paramValue );
      }
      return type;
   }


Which uses the Ordinal to determine the ordinal expected type. But instead of return null, this method throws the above exception. See ParameterMetadata.getOrdinalParameterExpectedType(int position) method.

Code:
   public OrdinalParameterDescriptor getOrdinalParameterDescriptor(int position) {
      if ( position < 1 || position > ordinalDescriptors.length ) {
         String error = "Position beyond number of declared ordinal parameters. " +
               "Remember that ordinal parameters are 1-based! Position: " + position;
         throw new QueryParameterException( error );
      }
      return ordinalDescriptors[position - 1];
   }

   public Type getOrdinalParameterExpectedType(int position) {
      return getOrdinalParameterDescriptor( position ).getExpectedType();
   }


Lastly, I found that the QueryTranslatorImpl.getWalker() returns a walker with a positionalParameterCount of 0 (zero) and parameterCount of 3 (three); which seem to be the root of the problem. Because when the HQLQueryPlan build the parameter meta data via the buildParameterMetaData() method the ordinalParamCount is 0 (zero). However the recognizer.getNamedParameterDescriptionMap() return 3 (three) entries for the 3 (three) parameters. It seems to me the ordinalParamCount should be overridden to include these 3 (three) entries from the recognizer.getNamedParameterDescriptionMap().

Code:
    private ParameterMetadata buildParameterMetadata(ParameterTranslations parameterTranslations, String hql) {
        long start = System.currentTimeMillis();
        ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( hql );
        long end = System.currentTimeMillis();
        if ( log.isTraceEnabled() ) {
            log.trace( "HQL param location recognition took " + (end - start) + " mills (" + hql + ")" );
        }

        int ordinalParamCount = parameterTranslations.getOrdinalParameterCount();
        int[] locations = ArrayHelper.toIntArray( recognizer.getOrdinalParameterLocationList() );
        if ( parameterTranslations.supportsOrdinalParameterMetadata() && locations.length != ordinalParamCount ) {
            throw new HibernateException( "ordinal parameter mismatch" );
        }
        ordinalParamCount = locations.length;
        OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount];
        for ( int i = 1; i <= ordinalParamCount; i++ ) {
            ordinalParamDescriptors[ i - 1 ] = new OrdinalParameterDescriptor(
                    i,
                    parameterTranslations.supportsOrdinalParameterMetadata()
                            ? parameterTranslations.getOrdinalParameterExpectedType( i )
                            : null,
                    locations[ i - 1 ]
            );
        }

        Iterator itr = recognizer.getNamedParameterDescriptionMap().entrySet().iterator();
        Map namedParamDescriptorMap = new HashMap();
        while( itr.hasNext() ) {
            final Map.Entry entry = ( Map.Entry ) itr.next();
            final String name = ( String ) entry.getKey();
            final ParamLocationRecognizer.NamedParameterDescription description =
                    ( ParamLocationRecognizer.NamedParameterDescription ) entry.getValue();
            namedParamDescriptorMap.put(
                    name,
                    new NamedParameterDescriptor(
                            name,
                            parameterTranslations.getNamedParameterExpectedType( name ),
                            description.buildPositionsArray(),
                            description.isJpaStyle()
                    )
            );
        }

        return new ParameterMetadata( ordinalParamDescriptors, namedParamDescriptorMap );
    }


So is this a bug?
How do I ensure the ParameterMetadata is set correctly with the appropriate values; so the ParameterMetadata.getOrdinalParameterExpectedType(int position) method can stop throwing the above exception?

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

       



More information about the hibernate-issues mailing list