Category Archives: spring

Log input parameters for a Spring StoredProcedure

To view the input parameters passed to an SP through Spring StoredProcedure, enable TRACE log level for org.springframework.jdbc.core.StatementCreatorUtils class. The SP parameters are logged by the setParameterValueInternal() method.

This is in sync with spring version 3.2.

Issues with Spring’s ResourceBundleMessageSource

In Spring, you can use ResourceBundleMessageSource to resolve text messages from properties file, based on the selected locales. Follow this link for an introductory example on how to do so.

This post details on two bottlenecks with this message source’s implementation that we encountered through load tests.

Read the rest of this entry

Advertisement

Spring commits on NOT_SUPPORTED propagation level

If you are working with spring and executing a DML query inside a transaction which has a propagation level of NOT_SUPPORTED, you might get surprised that the DML query gets committed despite the fact that the propagation level is NOT_SUPPORTED.

Read the rest of this entry

Configuring Ehcache with JPA, Hibernate & Spring

This post details on the steps required to configure ehcache as the second level hibernate cache when jpa, hibernate and spring are used in combination

Configuring the cache

Add the below properties to the persistence.xml configuration file

<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/>
<property name="hibernate.generate_statistics" value="true"/>

Read the rest of this entry

Execute before or after a spring transactional method

Spring provides a mechanism through which you can plugin some code which gets executed after the transaction is complete. We need to provide an implementation of the org.springframework.transaction.support.TransactionSynchronization interface which can be registered using TransactionSynchronizationManager. This could be useful in scenario where your code does not have a control over when the transaction starts and ends. For e.g. Your service code always joins an existing transaction started by the calling method (using REQUIRED PROPAGATION LEVEL).

Read the rest of this entry

Static Field Injection In Spring

Injecting static fields in a spring bean doesn’t work by simply adding @Autowired annotation as below.

@Component
public class MessageHelper {
    @Autowired
    private static MessageBean messageBean;

    public static void msg() {
        messageBean.display();
    }
}

It works either by having constructor or setter based injection.

@Component
public class MessageHelper {
    private static MessageBean messageBean;

    @Autowired
    private void setMessageBean(MessageBean messageBean) {
        MessageHelper.messageBean = messageBean;
    }

    public static void msg() {
        messageBean.display();
    }

}

Spring ignores CGLib subclasses when detecting @Transactional

Starting with spring version 3.0.4, cglib sub-classes are ignored when the spring code analyzes a class for @Transactional annotations.

Below is the method from AbstractFallbackTransactionAttributeSource class which determines if the transaction attribute is present on the method invocation. If the transaction attribute is present spring wraps the class around a proxy.

private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// Ignore CGLIB subclasses - introspect the actual user class.
               Class<?> userClass = ClassUtils.getUserClass(targetClass);

		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
		// If we are dealing with method with generic parameters, find the original method.
		specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

		// First try is the method in the target class.
		TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
		if (txAtt != null) {
			return txAtt;
		}

		// Second try is the transaction attribute on the target class.
		txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAtt != null) {
			return txAtt;
		}

		if (specificMethod != method) {
			// Fallback is to look at the original method.
			txAtt = findTransactionAttribute(method);
			if (txAtt != null) {
				return txAtt;
			}
			// Last fallback is the class of the original method.
			return findTransactionAttribute(method.getDeclaringClass());
		}
		return null;
	}

I traced this out after I found that creation of the application context for my junit test cases failed with spring 3.0.4 jars but passed when spring 3.0.3 jars were used. My spring context xml file for the junit test cases looked similar to

    <context:component-scan base-package="sample">
        <context:exclude-filter type="regex" expression="sample.SomeService" />
    </context:component-scan>

    <bean id = "entityBasePackages" class = "java.lang.String">
        <constructor-arg value = "sample"/>
    </bean>

The junit testcase wanted to mock the class SomeService which contained @Transactional annotations hence it was excluded from the component scan.

@Service
public class SomeService {

    @Transactional
    public void transactionalMethod() {
        System.out.println("Transactional Method");
        //perform some database operations
    }
}

When the test case was executed with spring 3.0.4 jars it failed with the below error

Caused by: java.lang.IllegalArgumentException: Can not set sample.SomeService field sample.MyService.someService to $Proxy26
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
	at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
	at java.lang.reflect.Field.set(Field.java:657)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:503)
	... 43 more

The application context creation failed because spring ignored the cglib subclass which was created by EasyMock for SomeService class. Hence a JDK proxy over a CGlib proxy was created which lead to type cast failure as indicated from the error above.

The resolution to the above failure could be any of the two options below
1. Creating an interface for SomeService and replacing the class reference variable in MyService class. This would make the type cast succeed because the JDK proxy created by spring would now include the new interface in the list of proxy interfaces.

2. Remove the @Transactional annotations from the SomeService class so that spring does not create any proxies.

Supporting Custom Isolation Levels With JPA

This post provides a workaround for supporting custom isolation levels with JPA. If you use the HibernateJpaDialect (provided by spring)  and try to set an isolation level different from the default one you would get an exception “Standard JPA does not support custom isolation levels – use a special JpaDialect”

The above error would be seen when your configuration is as below

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

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
          lazy-init="true">
        <property name="persistenceUnitName" value="spmsoftwareunit"/>
        <property name="persistenceXmlLocation" value="classpath:com/spmsoftware/sampleapp/conf/persistence.xml"/>
        <property name="dataSource" ref="oracleDataSourceFactoryBean"/>
        <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        </property>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.id.new_generator_mappings">true</prop>
                <prop key="hibernate.cache.use_second_level_cache">false</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibernate.jdbc.batch_size">3</prop>
                <prop key="hibernate.jdbc.batch_versioned_data">true</prop>
                <prop key="hibernate.jdbc.factory_class">com.spmsoftware.sampleapp.persistence.OracleBatchingBatcherFactory</prop>
                <prop key="hibernate.hbm2ddl.auto">none</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

and the transaction is applied as

@Transactional(isolation=Isolation.SERIALIZABLE, propagation=Propagation.REQUIRED)

WorkAround

We can extend HibernateJpaDialect to modify the connection instance before the transaction starts

import org.hibernate.Session;
import org.hibernate.jdbc.Work;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import java.sql.Connection;
import java.sql.SQLException;

public class HibernateExtendedJpaDialect extends HibernateJpaDialect {

    private Logger logger = LoggerFactory.getLogger(HibernateExtendedJpaDialect.class);

    /**
     * This method is overridden to set custom isolation levels on the connection
     * @param entityManager
     * @param definition
     * @return
     * @throws PersistenceException
     * @throws SQLException
     * @throws TransactionException
     */
    @Override
    public Object beginTransaction(final EntityManager entityManager,
            final TransactionDefinition definition) throws PersistenceException,
            SQLException, TransactionException {
        Session session = (Session) entityManager.getDelegate();
        if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
            getSession(entityManager).getTransaction().setTimeout(definition.getTimeout());
        }

        entityManager.getTransaction().begin();
        logger.debug("Transaction started");

        session.doWork(new Work() {

            public void execute(Connection connection) throws SQLException {
                logger.debug("The connection instance is {}", connection);
                logger.debug("The isolation level of the connection is {} and the isolation level set on the transaction is {}",
                        connection.getTransactionIsolation(), definition.getIsolationLevel());
                DataSourceUtils.prepareConnectionForTransaction(connection, definition);
            }
        });

        return prepareTransaction(entityManager, definition.isReadOnly(), definition.getName());
    }

}

The above implementation takes care of setting the isolation level specified on the transaction definition by calling DataSourceUtils.prepareConnectionForTransaction(connection, definition);

Since the isolation level is changed on the connection instance, resetting it is important. This would have to be done in the data source since the connection gets closed as soon as the transaction is committed. There is no way to intercept the JpaTransactionManager code flow to reset the isolation level after commit is done.
By decorating the data source and setting the isolation level before the connection is given by the connection pool, one can achieve resetting of the isolation level on the connection instance to default (which in most of the cases is read committed).

Self Injection in Spring

Since Spring AOP is proxy based, only ‘external’ method calls coming in through the proxy will be intercepted. i.e. This means that ‘self-invocation’, i.e. a method within the target object calling some other method of the target object, won’t lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.

Why @Autowired does not work


@Service
public class UserService implements Service{
   @Autowired
   private Service self;
}

The above code throws a NoSuchBeanDefinitionException. Logically speaking @Autowired doesn’t work because the bean can’t be injected until it has been fully constructed. This means that Spring has to have injected all properties of the bean. Effectively the above code creates a circular dependency because Spring tries to instantiate the bean and when it does, it discovers that it needs to Autowire another bean. When it tries to find that bean it can’t because the bean hasn’t been added to the list of initialized beans (because it’s currently being initialized).

Alternatives

Below are couple of approaches which work.

@Service(value = "someService")
public class UserService implements Service{
   @Resource(name = "someService")
   private Service self;
}

or

@Service
public class UserService implements Service {

    @Autowired
    private ApplicationContext applicationContext;

    private Service self;

    @PostConstruct
    private void init() {
        self = applicationContext.getBean(UserService);
    }
}

Spring transaction behavior in private & internal methods

This post is to detail on the spring behavior when @Transactional annotations are applied on private methods or when transactional methods are called from within a method in the same class.

Transactional Private Methods

public class Bean {
  public void doStuff() {
     doPrivateStuff();
  }
  @Transactional
  private void doPrivateStuff() {

  }
}

...

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

@Transactional will have no effect if used to annotate private methods. The proxy generator will ignore them.
As per the Spring manual

Method visibility and @Transactional
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ if you need to annotate non-public methods.

Calling internal transactional methods

public class Bean {
   public void doStuff() {
     doTransactionStuff();
   }

   @Transactional
   public void doTransactionStuff() {

   }
}

This will open a transaction:

Bean bean = (Bean)appContext.getBean("bean");
bean.doTransactionStuff();

This will not:

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

As per the Spring manual
Note: In proxy mode (which is the default), only ‘external’ method calls coming in through the proxy will be intercepted. This means that ‘self-invocation’, i.e. a method within the target object calling some other method of the target object, won’t lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!

Consider the use of AspectJ mode if you expect self-invocations to be wrapped with transactions as well. In this case, there won’t be a proxy in the first place; instead, the target class will be ‘weaved’ (i.e. its byte code will be modified) in order to turn @Transactional into runtime behavior on any kind of method.

Summary

The @Transactional annotation defines a transaction boundary, and Spring will start/rollback/commit the transaction every time a @Transactional-annotated method is entered or exited.
If you execute a @Transactional-annotated method, and that method then calls another method in another class, and that one calls another one, which eventually does some database work, then you’re still inside the transaction.