-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Problem setting parameter of NamedQuery via index/value args
PostPosted: Tue Oct 12, 2010 2:27 pm 
Regular
Regular

Joined: Tue Jul 29, 2008 4:15 pm
Posts: 62
Location: Dallas, TX US
Hello,

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?

Thanks!

Tonté

_________________
pouncilt


Top
 Profile  
 
 Post subject: Re: Problem setting parameter of NamedQuery via index/value args
PostPosted: Sun Jun 05, 2011 7:17 pm 
Newbie

Joined: Sun Jun 05, 2011 4:46 pm
Posts: 1
I am stuck with same problem, I was wondering if any one has solved similar problem.

Thanks in advance.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.