Basically, we want to move the JPA XML mappings outside of the application JAR so that we can change the mapping without affecting the jar file.
The JPA 2.1 Specification
The JPA specification is pretty clear about the location of the associated persistence.xml and XML mappings files (e.g. orm.xml):
An object/relational mapping XML file named orm.xml may be specified in the META-INF directory in the root of the persistence unit or in the META-INF directory of any jar file referenced by the persistence.xml.
Alternatively, or in addition, one or more mapping files may be referenced by the mapping-file elements of the persistence-unit element. These mapping files may be present anywhere on the classpath.
So, the XML mappings files are supposed to be located on the classpath, so that the Classloader can load them as resources.
Therefore, the XML mappings can be located outside of a JAR file, but the containing folder must be included in the Java class path.
The Hibernate way
When using Hibernate, you don’t even need to include the XML mappings folder in the Java classpath because Hibernate can resolve any valid mapping-file URL.
Therefore, our persistence.xml mappings looks as follows:
The mapping-file can take any URL. In this particular example, the mappings folder is located outside of the directory where the application code resides.
Considering we have the following Post entity:
public class Post {
private Long id;
private String title;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
public class PostTest {
protected final Logger LOGGER =
LoggerFactory.getLogger( getClass());
private EntityManagerFactory entityManagerFactory;
@Before
public void setup() {
entityManagerFactory = Persistence
.createEntityManagerFactory( "externalMapping");
}
@After
public void tearDown() {
if ( entityManagerFactory != null &&
entityManagerFactory.isOpen()) {
entityManagerFactory.close();
}
}
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
@Test
public void HHH10385Test() throws Exception {
doInJPA( this::getEntityManagerFactory, entityManager -> {
Post post = new Post();
post.setId(1L);
post.setTitle("High-Performance Java Persistence");
entityManager.persist(post);
});
doInJPA( this::getEntityManagerFactory, entityManager -> {
Post post = entityManager.find(Post.class, 1L);
LOGGER.debug("Fetched post: {}", post.getTitle());
});
}
}
The following outcome is obtained:
INSERT INTO Post
(title , id)
VALUES
('High-Performance Java Persistence', 1)
SELECT
p.id as id1_1_0_,
p.title as title2_1_0_
FROM
Post p
WHERE
p.id = 1
-- Fetched post: High-Performance Java Persistence
Great!
Online Workshops
If you enjoyed this article, I bet you are going to love my upcoming Online Workshops.
While JPA demands the XML file mappings to be located in the Java classpath, Hibernate allows you to store the XML file mappings everywhere you want. As long as the mapping-file URL is accessible, everything will be just fine.