Issue
In c# (dotnet core), I can defined an assembly/csproj that
- Contains only POCO (aka POJO) classes.
- Has zero references to any other library.
- Have zero ORM attributes (aka, annotations) on the Poco objects.
Then in another assembly/csproj, I can "fluently" define mappings between the poco and the ORM. (Entity Framework or NHibernate for example).
Example like this: (entity framework core)
public class SchoolDBContext: DbContext
{
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//Write Fluent API configurations here
//Property Configurations
modelBuilder.Entity<Student>()
.Property(s => s.StudentId)
.HasColumnName("Id")
.HasDefaultValue(0)
.IsRequired();
}
}
(above from https://www.entityframeworktutorial.net/efcore/fluent-api-in-entity-framework-core.aspx)
or NHibernate (below)
public class CarMap : ClassMap<Car>
{
public CarMap()
{
Table( "Vehicles.dbo.Car" );
Id( x => x.CarId );
Map( x => x.Name );
Map( x => x.Year );
HasOne( x => x.SteeringWheel ).PropertyRef( x => x.Car);
}
}
public class SteeringWheelMap : ClassMap<SteeringWheel>
{
public SteeringWheelMap()
{
Table( "Vehicles.dbo.SteeringWheel" );
Id( x => x.SteeringWheelId );
Map( x => x.Diameter );
Map( x => x.Color );
References( x => x.Car, "CarId" ).Unique();
}
}
( above from https://github.com/FluentNHibernate/fluent-nhibernate/wiki/fluent-mapping )
In java, I typically see JPA code like this:
package com.mycompany.pojosandjpaannotationsmixed;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.OffsetDateTime;
@Entity
@Table(name = "SomeEntityTable")
public class SomeEntity {
@Id
@Column(name = "SomeEntityKey", unique = true)
@GeneratedValue(strategy = GenerationType.AUTO)
private long someEntityKey;
@Column(name = "SomeEntityName", unique = true)
private String someEntityName;
@Column(name = "CreateOffsetDateTime", columnDefinition = "TIMESTAMP WITH TIME ZONE" )
private OffsetDateTime createOffsetDateTime;
public long getSomeEntityKey() {
return someEntityKey;
}
public void setSomeEntityKey(long someEntityKey) {
this.someEntityKey = someEntityKey;
}
public String getSomeEntityName() {
return someEntityName;
}
public void setSomeEntityName(String someEntityName) {
this.someEntityName = someEntityName;
}
public OffsetDateTime getCreateOffsetDateTime() {
return createOffsetDateTime;
}
public void setCreateOffsetDateTime(OffsetDateTime createOffsetDateTime) {
this.createOffsetDateTime = createOffsetDateTime;
}
}
All in the same module (I am using gradle, FYI), aka, all in the same .jar.
Is there anyway in java (8 or 11 or whatever) to separate the POCO from the ORM?
A pojo like this:
public class SomeEntity {
private long someEntityKey;
private String someEntityName;
private OffsetDateTime createOffsetDateTime;
public long getSomeEntityKey() {
return someEntityKey;
}
public void setSomeEntityKey(long someEntityKey) {
this.someEntityKey = someEntityKey;
}
public String getSomeEntityName() {
return someEntityName;
}
public void setSomeEntityName(String someEntityName) {
this.someEntityName = someEntityName;
}
public OffsetDateTime getCreateOffsetDateTime() {
return createOffsetDateTime;
}
public void setCreateOffsetDateTime(OffsetDateTime createOffsetDateTime) {
this.createOffsetDateTime = createOffsetDateTime;
}
}
and the ORM mapping code somewhere else? (in a different module/.jar)?
I found this:
https://vladmihalcea.com/fluent-api-entity-building-with-jpa-and-hibernate/
But again, it looks like the POJO is riddled with annotations.
Solution
Yes. The JPA specs states:
The object/relational mapping information can take the form of annotations on the managed persistence classes included in the persistence unit, an orm.xml file contained in the META-INF directory of the root of the persistence unit, one or more XML files on the classpath and referenced from the persistence. xml file, or a combination of these.
Annotations is only an option. All mapping information can be defined in xml files, or a combination of both. In the later case, the mapping information on the xml files overrides the annotations.
For example, this could be a META-INF/orm.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
version="2.2">
<entity class="com.mycompany.pojosandjpaannotationsmixed.SomeEntity">
<table name="SomeEntityTable" />
<attributes>
<id name="someEntityKey">
<column name="SomeEntityKey" unique="true" />
<generated-value strategy="AUTO" />
</id>
<basic name="someEntityName">
<column name="SomeEntityName" unique="true" />
</basic>
<!--
....
-->
</attributes>
</entity>
</entity-mappings>
Answered By - areus
Answer Checked By - David Marino (JavaFixing Volunteer)