Showing posts with label Inheritance. Show all posts
Showing posts with label Inheritance. Show all posts

Friday, 7 September 2012

What The !@"#[: Are Maven Parent Projects?

All Maven projects have a parent project. If not declared explicitly, a project will automatically inherit from the super pom.xml. All projects inherit from the configuration of their parent project. It is possible to create relationships between parent and child projects.

Maven Project Inheritance

Assuming a project is divided in several modules, each module is a maven project in itself. The parent's pom.xml would be like:
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mygroupid</groupId>
    <artifactId>myprojectparent</artifactId>
    <version>1.0.0</version>
</project>
This parent project inherits of the super pom.xml. A child module project would declare its parent relationship like this:
<project>
    <parent>
        <groupId>com.mygroupid</groupId>
        <artifactId>myprojectparent</artifactId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>mymoduleproject</artifactId>
</project>
The child module project does not inherit of the super pom.xml. By not specifying a group id or a version, it inherits these from its parent. The parent's pom.xml must be located in the directory above this module project. Else, the location must be specified relative to this module's pom.xml file. For example:
    <relativePath>.../parentDir/pom.xml</relativePath>

Maven Project Aggregation

There is another way to establish a relationship between a parent project and child projects: project aggregation. Instead of declaring a parent project in the child project, the parent project declares modules:
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mygroupid</groupId>
    <artifactId>myprojectparent</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <modules>
        <module>mymoduleproject</module>
    </modules>
</project>
The parent project's packaging must be set to pom and the pom.xml of child module projects must be located in directories bearing the module's name. Else, the module path must be specified relative to the
parent's pom.xml:
    <module>../myModuleDir/mymoduleproject</module>
If one compiles the parent project (or performs any other action on it), all its modules are compiled too.

REM: In this configuration, there is no inheritance between child projects and the parent project (only aggregation). Hence, child projects do not inherit of the parent's configuration. All projects of this aggregation inherit of the super pom.xml. They each have a life of their own.

Wednesday, 22 August 2012

JPA Inheritance Types - Joined, Single Table, Table Per Class

There are three strategies to store data of classes inheriting from each other in JPA. This is defined in the root classes of inheritance structures with the @Inheritance annotation.

Joined

The joined strategy creates a table for the root class of an inheritance structure, and a separate table for each inheriting class in the structure. The data of the root class table is not copied in the inheriting class tables.

This is a root class example:
@Entity
@AutoProperty
@Inheritance(strategy=InheritanceType.JOINED)
public class Joined implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    private String s;

    // Setter, Getters, Constructors, Pojomatic...

}

Single Table

The single table strategy creates a unique table for a given inheritance structure where all classes in the hierarchy are saved. This table contains a discriminating column which will help differentiate between the different classes. Each class must define a discriminating value with @DiscriminatorValue.

For the root class:
@Entity
@AutoProperty
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="discr", discriminatorType=DiscriminatorType.INTEGER)
@DiscriminatorValue("44")
public class SingleTable implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    private String s;

    // Setter, Getters, Constructors, Pojomatic...

}
For an inheriting class:
@Entity
@AutoProperty
@DiscriminatorValue("45")
public class InheritsSingleTable extends SingleTable {

    ...

}

Table Per Class

The table per class strategy create a separate table per class.

Root class example:
@Entity
@AutoProperty
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class TablePerClass implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private long id;
 
    private String s;

    // Setter, Getters, Constructors, Pojomatic...

}
Notice that one must use a TABLE generation type for the Id.

Check

The following:
JPA.INSTANCE.clear();

InheritsJoined ij = new InheritsJoined();
ij.setS("IJ1");
ij.setS2("IJ2");

JPA.INSTANCE.save(ij);

InheritsSingleTable st
    = new InheritsSingleTable();
st.setS("ST1");
st.setS2("ST2");

JPA.INSTANCE.save(st);

InheritsTablePerClass tpc
    = new InheritsTablePerClass();
tpc.setS("TPC1");
tpc.setS2("TPC2");

JPA.INSTANCE.save(tpc);

JPA.INSTANCE.clear();

InheritsJoined retr_ij = JPA.INSTANCE.get(
    InheritsJoined.class, ij.getId());
System.out.println("Source == Retrieved: " + (ij==retr_ij));
System.out.println(retr_ij);

InheritsSingleTable retr_st = JPA.INSTANCE.get(
    InheritsSingleTable.class, st.getId());
System.out.println("Source == Retrieved: " + (st==retr_st));
System.out.println(retr_st);

InheritsTablePerClass retr_tpc = JPA.INSTANCE.get(
    InheritsTablePerClass.class, tpc.getId());
System.out.println("Source == Retrieved: " + (tpc==retr_tpc));
System.out.println(retr_tpc);
Generates the following output:
Source == Retrieved: false
InheritsJoined{id: {1}, s: {IJ1}, s2: {IJ2}}
Source == Retrieved: false
InheritsSingleTable{id: {1}, s: {ST1}, s2: {ST2}}
Source == Retrieved: false
InheritsTablePerClass{id: {1}, s: {TPC1}, s2: {TPC2}}
The above example is available from Github in the JPA directory. It relies on Pojomatic too. Some errors messages will be displayed because of a known and harmless issue.

JPA Inheritance - Non Entity Super Class

An entity can inherit of a non-entity super class. The consequence is that the non-entity class data is not persisted.

For example:
@AutoProperty
public class NonEntitySuperClass {

 private String s;

    // Setter, Getters, Constructors, Pojomatic...

}
A class extends this non-entity class:
@Entity
@AutoProperty
public class InheritingNonEntitySuperClass
    extends NonEntitySuperClass
        implements Serializable {
 
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;
 
    private String s2;

    // Setter, Getters, Constructors...

}
The following code:
JPA.INSTANCE.clear();

InheritingNonEntitySuperClass insc
    = new InheritingNonEntitySuperClass();
insc.setS("P1P");
insc.setS2("AZ3");
  
JPA.INSTANCE.save(insc);
JPA.INSTANCE.clear();
  
InheritingNonEntitySuperClass retr = JPA.INSTANCE.get(
    InheritingNonEntitySuperClass.class, insc.getId());

System.out.println("Source == Retrieved: " + (insc==retr));
System.out.println(retr);
Generates the following output:
Source == Retrieved: false
InheritingNonEntitySuperClass{s: {null}, id: {1}, s2: {AZ3}}
Notice that the s value is null, instead of P1P.

The above example is available from Github in the JPA directory. It relies on Pojomatic too. Some errors messages will be displayed because of a known and harmless issue.

JPA Inheritance - Mapped Super Class

Mapped super classes are just like entities, but cannot be used like entities. They have ids and data to persist, but there is no corresponding table in the database. 

For example:
@MappedSuperclass
@AutoProperty
public class MappedSuperClass implements Serializable {

 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 private long id; 
 
 private String s;

    // Setter, Getters, Constructors, Pojomatic...

}
A class extends the mapped super class:
@Entity
@AutoProperty
public class InheritingMappedSuperClass extends MappedSuperClass {

 private String s2;

    // Setter, Getters, Constructors...

}
The following code:
JPA.INSTANCE.clear();

InheritingMappedSuperClass ce = new InheritingMappedSuperClass();
ce.setS("QQQ");
ce.setS2("DDD");

JPA.INSTANCE.save(ce);
JPA.INSTANCE.clear();
  
InheritingMappedSuperClass retr = JPA.INSTANCE.get(
    InheritingMappedSuperClass.class, ce.getId());

System.out.println("Source == Retrieved: " + (ce==retr));
System.out.println(retr);
Generates the following output:
Source == Retrieved: false
InheritingMappedSuperClass{id: {1}, s: {QQQ}, s2: {DDD}}
The above example is available from Github in the JPA directory. It relies on Pojomatic too. Some errors messages will be displayed because of a known and harmless issue.

JPA Inheritance - Abstract Entity

An abstract class can be made a JPA entity. The only difference is that such classes cannot be instantiated.

For example:
@Entity
@AutoProperty
public abstract class AbstractEntity implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    private String s;

    // Setter, Getters, Constructors, Pojomatic...

}
A class extends the abstract class:
@Entity
@AutoProperty
public class ConcreteEntity extends AbstractEntity {

    private String s2;

    // Setter, Getters, Constructors...

}
The following code:
JPA.INSTANCE.clear();

ConcreteEntity ce = new ConcreteEntity();
ce.setS("AAA");
ce.setS2("BBB");

JPA.INSTANCE.save(ce);
JPA.INSTANCE.clear();

ConcreteEntity retr = JPA.INSTANCE.get(
    ConcreteEntity.class, ce.getId());

System.out.println("Source == Retrieved: " + (ce==retr));
System.out.println(retr);
Generates the following output:
Source == Retrieved: false
ConcreteEntity{id: {1}, s: {AAA}, s2: {BBB}}
The above example is available from Github in the JPA directory. It relies on Pojomatic too. Some errors messages will be displayed because of a known and harmless issue.