How to use Dynamic Proxies with JSF when the method signature contains Object ... args

832 views Asked by At

I'm having some trouble with Spring, JPA and Dynamic Proxy DAO classes which are initialized as Spring Beans. This particular project has been plaguing me on the persistence/transaction side for some time, and I'd like to get this nailed down once and for all.

First, here's a method from the DAO interface:

/**
 * Perform a named query using numbered parameters and return the results as a list
 * @param name
 * @param params
 * @return query results
 */
List getNQasList(String name, Object... params);

This bean is registered automatically with Spring using a postProcessBeanFactory method:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

    this.beanFactory = beanFactory;
    for (Class entityClass : this.getPersistedClassList()) {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        ConstructorArgumentValues constructorVals = new ConstructorArgumentValues();
        constructorVals.addIndexedArgumentValue(0, entityClass);
        beanDefinition.setConstructorArgumentValues(constructorVals);
        beanDefinition.setBeanClass(GenericDAOImpl.class);
        beanDefinition.setAutowireCandidate(true);
        beanDefinition.setLazyInit(true);
        beanDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
        String simpleName = entityClass.getSimpleName();
        String convertedName = "" + simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1) + "Dao";
        registry.registerBeanDefinition(convertedName, beanDefinition);
    }
}

The method getPersistedClassList() reads persistence.xml and finds all of the JPA classes. The above method registers each of these instances with Spring so they can be accessed easily by the variable "entityNameDao". Because this class is a transactional class, it gets initialized as a Dynamic Java Proxy, and that's where my problems begin. JSF doesn't perceive the object by its interfaces anymore, but looks directly at the proxy, which does in fact show the above method definition as:

List getNQasList(String name, Object[] params);

This makes it much more difficult to access from JSF than an Object... params signature method. Is there any way I can get JSF to recognize these objects by their interface, or convince Spring to somehow not make dynamic proxies of them? Alternatively, how does one go about doing the following in EL, it gives me errors about the curly braces if I try:

new Object[] {...}

My spring config relating to persistence, including the transaction advice is included below for good measure.

<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="${JDBC_CONNECTION_STRING}?autoReconnect=true&amp;useUnicode=true&amp;connectionCollation=utf8_general_ci&amp;characterSetResults=utf8"/>
    <property name="username" value="${PARAM1}"/>
    <property name="password" value="${PARAM2}"/>
    <property name="validationQuery" value="select 1"/>
</bean>

<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<context:annotation-config/>

<!-- Enable aspectj based transactions -->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />
<!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
    <tx:attributes>
        <!-- all methods starting with 'get' are read-only -->
        <tx:method name="get*" read-only="true"/>
        <!-- other methods use the default transaction settings (see below) -->
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
  of an operation defined by the GenericDAOImpl class -->
<aop:config>
    <aop:pointcut id="DaoOps" expression="execution(* daos.GenericDAOImpl.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="DaoOps"/>
</aop:config>

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
            <property name="showSql" value="true"/>
        </bean>
    </property>
</bean>
0

There are 0 answers