Migrate from Hades to Spring Data JPA

For the past 18 months I have been utilizing hades for implementing JPA based repositories/DAOs. Hades has now been moved into the Spring Data JPA project. Starting with their 1.0.1 release I tried migrating one of my projects to this release. Following I document the steps that were necessary to achieve this.

Their project page starts off with showing the Maven repositories and dependency descriptors (in case you are using Maven). Obviously the first thing is to replace the hades artifact by the spring-data-jpa artifact.

Domain classes, JPA entities

The project’s domain classes implement the org.synyx.hades.domain.Persistable interface which has to be replaced by org.springframework.data.domain.Persistable (takes a single generics parameter for the id type).

CRUD repositories

DAO interfaces extending org.synyx.hades.dao.GenericDao have to be modified to extend org.springframework.data.repository.CrudRepository. With this modification you will face a couple of compile problems. read*-methods have been renamed to find*-methods. Also you are loosing the paging and sorting capable find* – methods (which I didn’t use). If those are required then extend the org.springframework.data.repository.PagingAndSortingRepository interface.

find* – methods now return iterables rather than list types requiring minor adjustments to existing codebase. To get around this, the interface can also extend from JpaRepository. Using this base interface hands you a pretty powerful DAO that goes far beyond a simple CRUD repository.

CRUD repository instantiation

When I started off with hades many month ago I used an explicit XML-based configuration of DAO components.

<bean id="addressDao" class="org.synyx.hades.dao.orm.GenericDaoFactoryBean" p:daoInterface="at.martinahrer.training.spring.jpa.dao.hades.AddressDao" />

For migration the factory bean class has to be changed:

<bean id="addressDao" class="org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean" p:daoInterface="at.martinahrer.training.spring.jpa.dao.hades.AddressDao" />

With these changes in place all tests were showing the green bar again. However, today I would recommend using repository namespace http://www.springframework.org/schema/data/jpa which significantly reduces the amount of configuration needed by utilizing class path scanning to detect repository components.

<repository:repositories base-package="at.martinahrer.training.spring.jpa.dao" />

Certainly you might encounter more steps during migration depending on the features you have used from the old hades code base. In my case I only had used named JPA queries which just continued to work like before.

Analyzing class metadata with the Springframework

What a shame I haven’t published anything for a long time. To make up for this long pause, I’m going to discuss how Spring can support with analyzing class metadata. These days everybody is crazy about using annotations in their frameworks. Occasionally you need to know what classes/methods are annotated. A good example might be to build a list of class names for all JPA entities (those classes annotated with javax.persistence.Entity and the like).

A simple use-case showing how to detect classes annotated as components

This use-case is using a few Spring APIs and some home grown code that controls resource matching (ClassResourceResolver and AnnotationMetadataMatcher).

import java.io.IOException;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.util.ClassUtils;

public class ClassResourceResolverTest {
	@Test
	public void testSelect() throws IOException {
		// given
		ClassResourceResolver scanner = new ClassResourceResolver(
				ClassUtils.convertClassNameToResourcePath(AComponent.class.getPackage().getName()));
		final MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(
				new PathMatchingResourcePatternResolver());

		// when
		String[] classNames = scanner.select(new AnnotationMetadataMatcher(metadataReaderFactory, false,
				Component.class));
		// then
		Assert.assertArrayEquals(new String[] { AComponent.class.getName() }, classNames);
		Assert.assertTrue(metadataReaderFactory.getMetadataReader(classNames[0]).getAnnotationMetadata()
				.isAnnotated(Component.class.getName()));
	}
}

@Component
class AComponent {
}

@Repository
class ARepository {
}

ClassResourceResolver is doing the resource matching all from a set of resource paths

	public String[] select(ClassResourceMetadataMatcher matcher) throws IOException {
		List<String> result = new ArrayList<String>();

		for (String path : resourcePath) {
			String resourcePattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + path + "/**/*.class";
			Resource[] resources = this.resourcePatternResolver.getResources(resourcePattern);
			for (Resource resource : resources) {
				if (resource.isReadable()) {
					MetadataReader reader = matcher.match(resource, resourcePatternResolver);
					if (reader != null) {
						result.add(reader.getClassMetadata().getClassName());
					}
				}
			}
		}
		return result.toArray(new String[result.size()]);
	}

A ClassResourceMetadataMatcher is looking at the annotations present on a class resource

	@Override
	public MetadataReader match(Resource resource, ResourceLoader resolver) throws IOException {
		for (Class<? extends Annotation> annotationType : annotationTypes) {
			MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
			if (new AnnotationTypeFilter(annotationType, considerMetaAnnotations).match(metadataReader,
					metadataReaderFactory)) {
				return metadataReader;
			}
		}
		return null;
	}

Under the hood Spring is using the ASM bytecode library for looking into the class files. Not that no class examined by the code above is actually loading any of the class objects so it is fairly lightweight and not filling up your perm gen space. Still you need to make up useful search paths so you don’t end up scanning through you full classpath.

The full code just is available as a gist

git clone git@gist.github.com:73f21e68d24032ad7672.git

Testing static methods…

We all have learned that it is not wise to overuse static methods as these are kind of hard to test and deal with. So in general I strive to get out of their way. Sometimes I’m facing the situation that the use of a framework or that some technical infrastructure requires me to implement static methods.
So for testing I found PowerMock which nicely integrates with EasyMock and Mockito.

ActiveMQ in embedded mode

I’m using Apache ActiveMQ for testing JMS based code. With their Springframework support it’s pretty simple to embed it into a test suite.
Today I encountered a strange problem. After I had broken my test and fixed the bug later I was not able to restart the embedded ActiveMQ container.

Obviously java.io.EOFException: Chunk stream does not exist at page: 0 sounds like some temporary file data was corrupt. JobSchedulerStore creates a directory activemq-data/localhost/scheduler for storing scheduler data. Clean/delete that and it should be startable again. If you don’t need that then you are better off with completely deactivating that feature.

Read more

AspectJ runtime weaving within a Maven build

In order to perform AspectJ runtime weaving, an agent is required. Here we are using the agent (spring-instrument-3.0.3.RELEASE) provided by the Springframework. So for surefire we have to use a command line argument -javaagent: that specifies the JAR file containing the agent. To keep the build portable we copy that artifact to the build directory first using the maven-dependency-plugin.

Read more

Using a blackberry device as a modem on your Mac

While on the windows platform it was sufficient to only provide the username and password for the providers APN, with Mac OSX a generic modem phone number is required. This phone number is “*99***1#“.
For a username and password for the providers APN you have to consult your provider.
The user name for A1 (Austria) is ppp@A1plus.at with the password ppp.

In the “Advanced” settings choose “Research in Motion” as vendor, “BlackBerry IP Modem (GSM)” as model, “a1.net” as APN!

Register ActiveMQ Spring namespace with eclipse 3.6

In a earlier post I described how to setup the eclipse XML editor to validate a Spring context file containing the AMQ namespace.

Looks like with eclipse 3.6 that does not work anymore, I was not able to actually use a JAR file as location like I used to set this up with eclipse 3.4.
So I’m directly associating the AMQ namespace with the XML schema available from the AMQ project.

Read more

Using Nexus and the Nexus REST API for implementing a software update tool

Nexus is using a pretty well documented REST API which is usable externally as well.
For one of my customers I implemented a kind of automatic software update tool that can be embedded into any product. It is based on the Sonatype NEXUS repository manager.

Read more

Java5 Generics are implemented by type erasure, but …

… still it is possible to get hold of the actual type parameters of parameterized types. Even if classical reflection does not deliver type information, this type parameters can still be extremely useful. I have a few pieces of code (DAO, controllers, etc.) that are parameterized by class objects.

Read more

A simple ViewController for JSF

Very early Apache Shale came up with the idea of providing a view controller that allowed to execute dedicated methods (annotated, etc.) during various JSF life-cycle (phase) events for doing initialization work upfront for example. As Shale was hibernated, Apache Orchestra stepped in and added many more useful features.
Both frameworks are based on the idea of having a dedicated page bean (a JSF managed bean per view) that would control important processing steps for the entire view (page).
It requires following naming conventions in order to associate a page bean to a view, optionally a view controller mapper provided the ability of explicitely associating page beans and views.

Read more

green red blue grey