Hibernate Annotation on parent fields - java

I have a class that is a POJO with no special Hibernate annotations or information, like so:
public class Parent{
Long id;
String foo;
String bar;
/* ... getters and setters, toString(), etc... */
}
I would like to create a child class that has the Hibernate annotations on it. The idea is that the first class will not have any dependencies on it, and the second will have all of the JPA/Hibernate specific stuff. How can I do that without re-creating all the fields in the parent? I would like to put Hibernate annotations on the class
#Entity
public class PersistentChild extends Parent{
// ????
}

You can use the #MappedSuperclass annotation on the POJO, then add the other annotations, as it were a normal JPA entity. But in this case, the annotations will only affect the entity classes, which are inheriting from it. Example:
#MappedSuperclass
public class Parent implements Serializable {
#Id
Long id;
#Column(name = "foo", required = true)
String foo;
#Column(name = "bar", required = false)
String bar;
/* ... getters and setters, toString(), etc... */
}
If you really do not want to modify the superclass, you can use a mapping file:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
<mapped-superclass class="Parent">
<!-- add your mapping here -->
</mapped-superclass>
</entity-mappings>
Alternative approach
Also, you can just add the #MappedSuperclass annotation, then define all properties like this:
#Entity
#AttributeOverrides({
#AttributeOverride(name = "foo", column=#Column(name = "foo", required = true)),
#AttributeOverride(name = "bar", column=#Column(name = "bar", required = false))
})
public class PersistentChild extends Parent {
#Id #GeneratedValue
Long id;
}

If you want to externalize the mapping you have to use xml-mapping file.

Related

JAXB how to map composite key fields as siblings

I have the following entities defined after my database model:
#Entity
#Table(name = "PERSON")
#XmlRootElement(name = "person")
public class Person implements java.io.Serializable {
#Id
private Long personId;
private String personName;
#XmlElementWrapper(name="children")
#XmlElement(name="child")
private Set<Child> children = new HashSet<Child>(0);
// getters & setters
}
#Entity
#Table(name = "CHILD")
#XmlRootElement(name = "child")
public class Child implements java.io.Serializable {
#EmbeddedId
private ChildId id;
private Date childName;
// getters & setters
}
#Embeddable
public class ChildId implements java.io.Serializable {
#XmlTransient
private Person parentId;
private Date childBirthDate;
private int childOrder;
// getters & setters
}
In the current state of thing, when marshalling using JAXB here is what I get:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<personId>7</personId>
<personName>Foo</personName>
<children>
<child>
<childName>Bar</childName>
<id>
<childBirthDate>2001-06-22</childBirthDate>
<childOrder>1</childOrder>
</id>
</child>
</children>
</person>
What I would like to get instead is something like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<personId>7</personId>
<personName>Foo</personName>
<children>
<child>
<childName>Bar</childName>
<childBirthDate>2001-06-22</childBirthDate>
<childOrder>1</childOrder>
</child>
</children>
</person>
Is there a way for me to get the ChildId's fields to the same level as the other Child's fields?
Please advise what my options are.
Moving comment to answer:
As multiple #Ids are possible in the same class, you could simply move the fields from the ChildId class into the Child class. Then you annotate each field with #Id (the fields which were moved from ChildId). This way you have all fields on the same level as they are in the same class, while also retaining the functionality of #EmbeddedId

Hibernate extending entity for read with additional joins

I have an entity that corresponds to some table in DB
#Entity
#Table
public class MyEntity {
#Id
private Long id;
#Column
private String description;
#OneToMany
private List<Foo> foos;
...
//getters setters
...
}
And I would like to extend that entity for read-only and have additional joins to another table. I need this joins only in one case for specific read user-case:
#Entity
public class ExtendedEntity extends MyEntity {
#ManyToMany(fetch = FetchType.EAGER)
private List<Bar> bars;
}
Just using extensions will create a discriminator column in DB, which I don't need since I'm using the ExtendedEntity only for the read. I found I hack with using #DiscriminatorFormula that will be resolved to the same Integer value like this:
#DiscriminatorFormula("0")
#DiscriminatorValue("0")
public class MyEntity
#DiscriminatorValue("00")
public class ExtendedEntity extends MyEntity
But this really looks like a hack. With using #MappedSuperclass I cannot have associations, but this is the main reason I need to extend my entity.
What other options do I have and what are the best practices for this use-case?

I am trying to extend a base class which has Id in two different subclass to hit JPA query [duplicate]

I am creating entities that are the same for two different tables. In order do table mappings etc. different for the two entities but only have the rest of the code in one place - an abstract superclass. The best thing would be to be able to annotate generic stuff such as column names (since the will be identical) in the super class but that does not work because JPA annotations are not inherited by child classes. Here is an example:
public abstract class MyAbstractEntity {
#Column(name="PROPERTY") //This will not be inherited and is therefore useless here
protected String property;
public String getProperty() {
return this.property;
}
//setters, hashCode, equals etc. methods
}
Which I would like to inherit and only specify the child-specific stuff, like annotations:
#Entity
#Table(name="MY_ENTITY_TABLE")
public class MyEntity extends MyAbstractEntity {
//This will not work since this field does not override the super class field, thus the setters and getters break.
#Column(name="PROPERTY")
protected String property;
}
Any ideas or will I have to create fields, getters and setters in the child classes?
Thanks,
Kris
You might want to annotate MyAbstractEntity with #MappedSuperclass class so that hibernate will import the configuration of MyAbstractEntity in the child and you won't have to override the field, just use the parent's. That annotation is the signal to hibernate that it has to examine the parent class too. Otherwise it assumes it can ignore it.
Here is an example with some explanations that may help.
#MappedSuperclass:
Is a convenience class
Is used to store shared state & behavior available to child classes
Is not persistable
Only child classes are persistable
#Inheritance specifies one of three mapping strategies:
Single-Table
Joined
Table per Class
#DiscriminatorColumn is used to define which column will be used to distinguish between child objects.
#DiscriminatorValue is used to specify a value that is used to distinguish a child object.
The following code results in the following:
You can see that the id field is in both tables, but is only specified in the AbstractEntityId #MappedSuperclass.
Also, the #DisciminatorColumn is shown as PARTY_TYPE in the Party table.
The #DiscriminatorValue is shown as Person as a record in the PARTY_TYPE column of the Party table.
Very importantly, the AbstractEntityId class does not get persisted at all.
I have not specified #Column annotations and instead are just relying on the default values.
If you added an Organisation entity that extended Party and if that was persisted next, then the Party table would have:
id = 2
PARTY_TYPE = "Organisation"
The Organisation table first entry would have:
id = 2
other attribute value associated specifically with organisations
#MappedSuperclass
#SequenceGenerator(name = "sequenceGenerator",
initialValue = 1, allocationSize = 1)
public class AbstractEntityId implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "sequenceGenerator")
protected Long id;
public AbstractEntityId() {}
public Long getId() {
return id;
}
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "PARTY_TYPE",
discriminatorType = DiscriminatorType.STRING)
public class Party extends AbstractEntityId {
public Party() {}
}
#Entity
#DiscriminatorValue("Person")
public class Person extends Party {
private String givenName;
private String familyName;
private String preferredName;
#Temporal(TemporalType.DATE)
private Date dateOfBirth;
private String gender;
public Person() {}
// getter & setters etc.
}
Hope this helps :)
Mark the superclass as
#MappedSuperclass
and remove the property from the child class.
Annotating your base class with #MappedSuperclass should do exactly what you want.
This is old, but I recently dealt with this and would like to share my solution. You can add annotations to an overridden getter.
#MappedSuperclass
public abstract class AbstractEntity<ID extends Serializable> implements Serializable {
#Column(name = "id", nullable = false, updatable = false)
#Id
private ID id;
public ID getId() {
return id;
}
...
}
#Entity
#Table(name = "address")
public final class Address extends AbstractEntity<UUID> implements Serializable {
...
#Override
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
public final UUID getId() {
return super.getId();
}
...
}

Spring Data Repository for Inheritance.JOINED subclass with PrimaryKeyJoinColumn and Composite Key in Super

I have two entities that map to two DB tables. One inherits from the other. The subclass also shares a composite foreign key with the parent.
Foo Entity
#Entity
#Table(name = "foo")
#IdClass(FooKey.class)
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "discriminator_flag", discriminatorType = DiscriminatorType.CHAR)
#DiscriminatorValue("F")
#Customizer(FooCustomizer.class)
public class Foo {
#Id
#Column(name = "id_col_1")
private String idCol1;
#Id
#Column(name = "id_col_2")
private String idCol2;
...
}
Bar Entity
#Entity
#Table(name = "bar")
#DiscriminatorValue("B")
#PrimaryKeyJoinColumns({ #PrimaryKeyJoinColumn(name = "foo_id_col_1", referencedColumnName = "id_col_1"), #PrimaryKeyJoinColumn(name = "foo_id_col_2", referencedColumnName = "id_col_2") })
public class Bar extends Foo {
...
}
Foo Repository
public interface FooRepository extends CrudRepository<Foo, FooKey> {
}
Bar Repository
public interface BarRepository extends CrudRepository<Bar, FooKey> {
}
The FooRepository works like a charm. No problems. But the BarRepository causes an exception in EclipseLink 2.5.2 (Spring-data 1.7.2.RELEASE)
No #IdClass attributes exist on the IdentifiableType [EntityTypeImpl#28997437:Bar [ javaType: class com.example.Bar descriptor: RelationalDescriptor(com.example.Bar --> [DatabaseTable(foo), DatabaseTable(bar)]), mappings: 49]]. There still may be one or more #Id or an #EmbeddedId on type.
I tried adding an #IdClass(FooKey.class) annotation to Bar but it complains that it can't see the matching #Id fields on the entity (of course they are on the super class)
Anyone have any ideas how to implement a BarRepository successfully for this?
UPDATE
I believe this to be a problem with EclipseLink and its handling of composite keys in an inheritance structure. I tried doing this with a MappedSuperclass and moved the key and common items out of Foo into AbstractFoo and found that both concrete implementations of it (Foo and Bar) both threw the error. Adding in the #IdClass annotation onto both as a workaround proved just as useless.
What did work was removing the composite key and replacing it with a simple single property #Id. Everything just worked normally.
So faced with the option of refactoring everything to use a single key and then enforcing a unique constraint on my two composite key columns at the database level or removing the inheritance and applying a #OneToOne mapping from Bar to Foo with #PrimaryKeyJoinColumns and cascading all operations, I went with the cop-out option 2. So my Bar entity now looks like
Bar Entity
#Entity
#Table(name = "bar")
#IdClass(BarKey.class)
public class Bar extends Foo {
#Id
#Column(name = "foo_id_col_1")
private String fooIdCol1;
#Id
#Column(name = "foo_id_col_2")
private String fooIdCol2;
#OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#PrimaryKeyJoinColumns({ #PrimaryKeyJoinColumn(name = "foo_id_col_1", referencedColumnName = "id_col_1"), #PrimaryKeyJoinColumn(name = "foo_id_col_2", referencedColumnName = "id_col_2") })
Private Foo foo;
...
}
Now my BarRepository works fine with the caveat that I have to create a Foo entity and attach it to a Bar entity before I persist. For me this was far, far less work.

JPA Relation between classes, referring to their Interfaces

I have two classes with their respective interfaces between which I want to create a JPA #OneToOne Relation. This fails with [class EmployeeImpl] uses a non-entity [class Adress] as target entity in the relationship attribute [field adress].
First Interface / Class:
public interface Employee {
public long getId();
public Adress getAdress();
public void setAdress(Adress adress);
}
#Entity(name = "EmployeeImpl")
#Table(name = "EmployeeImpl")
public class EmployeeImpl implements Employee {
#Id
#Column(name = "employeeId")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToOne(cascade = CascadeType.PERSIST)
private Adress adress;
// snip, getters and setters
}
Second Interface / Class:
public interface Adress {
public long getId();
public String getStreet();
public void setStreet(String street);
}
#Entity(name = "AdressImpl")
#Table(name = "AdressImpl")
public class AdressImpl implements Adress {
#Id
#Column(name = "AdressId")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "Street")
private String street;
// Snip getters and setters
}
The persistence.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="employee"
transaction-type="RESOURCE_LOCAL">
<class>EmployeeImpl</class>
<class>AdressImpl</class>
<properties>
<property name="eclipselink.create-ddl-jdbc-file-name"
value="create-matterhorn-employee.jdbc" />
<property name="eclipselink.drop-ddl-jdbc-file-name"
value="drop-matterhorn-employee.jdbc" />
</properties>
</persistence-unit>
</persistence>
I shortened out package names and imports and such. Exception occurs when trying to create the EntityManagerFactory (where you hand over the persistence unit). I am using eclipse link 2.0.2.
Actually JPA does allow such interface relationships, but in this case you have to provide an entity class implementing the interface, in you case this will look as follows:
#OneToOne(targetEntity = AddressImpl.class)
private Adress adress;
JPA standard does not allow for interface fields (or Collection of interface fields) being entity relationships. Some JPA implementations do support it (e.g DataNucleus JPA), but its a vendor extension to the spec. Consequently you either use one of those implementations or change your model (or add extra annotations/XML to define what type is actually stored there).

Categories

Resources