JPA Configuration: Annotations vs. XML Mapping
The Evolution of Mapping
Mapping Java classes to database tables has evolved from verbose XML files to concise annotations. While annotations are now the industry standard, understanding XML mapping remains crucial for legacy systems and “clean domain” architectures.
Core Concepts
1. Annotation-based Mapping
Mapping meta-data is stored directly within the Java code using @Entity, @Table, @Column, etc.
- Pros: Easy to read, developer-friendly, co-located with code.
- Cons: “Pollutes” Domain entities with persistence concerns.
2. XML-based Mapping (orm.xml)
Mapping data is defined in an external XML file (usually META-INF/orm.xml).
- Pros: Keeps Domain classes pure (no imports from
javax.persistence), allows overriding mapping without recompiling. - Cons: Verbose, fragile (string-based references to classes/fields), harder to maintain.
Practice Exercise: Decoupling with Programmatic Config
We will take a “God Class” tied to annotations and refactor it to use a cleaner configuration approach (using Hibernate’s MetadataSources or Spring’s LocalContainerEntityManagerFactoryBean).
The Standard Way (Annotations)
@Entity
public class User {
@Id @GeneratedValue private Long id;
@Column(nullable = false) private String email;
}
Refactoring to a Clean Domain
If you want to keep your User class free of JPA annotations, you can define the mapping in orm.xml:
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm" version="2.1">
<entity class="com.example.domain.User">
<table name="app_users"/>
<attributes>
<id name="id">
<generated-value strategy="IDENTITY"/>
</id>
<basic name="email">
<column nullable="false" unique="true"/>
</basic>
</attributes>
</entity>
</entity-mappings>
Programmatic Override (Spring Boot)
In Spring, you can customize the configuration via a HibernatePropertiesCustomizer:
@Configuration
public class DatabaseConfig {
@Bean
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer() {
return hibernateProperties -> {
hibernateProperties.put("hibernate.hbm2ddl.auto", "validate");
// Add custom physical naming strategies here
};
}
}
Why This Works
- Separation of Concerns: XML/Programmatic mapping satisfies the Clean Architecture rule that the core domain should not depend on external frameworks.
- Flexibility: Annotations can define the default behavior, while XML can override it for specific environments (e.g., changing table names for different DB vendors without changing code).
When to choose what?
- Small to Medium Apps: Stick to Annotations. The speed of development and readability outweighs the “pollution”.
- Enterprise/DDD Apps: Consider XML for your core Aggregate Roots to keep them framework-agnostic.
Summary
Mapping is more than just linking fields to columns; it’s an architectural decision. Whether you choose the convenience of Annotations or the purity of XML, consistency across the codebase is key.