I need to override a getter of an entity object, on which the db column is defined, in it's superclass, so I can add additional annotations.
Example:
#MappedSuperclass
public class Person {
String name;
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
#Table(name="employee")
#XmlType(name="employee")
public class Employee extends Person {
#Override
#XmlAttribute(name = "name")
public String getName() {
return super.getName();
}
}
Class Person contains common attributes for several entities. Class Employee extends person and defines a database table (table per class strategy). I also want to serialize class Employee to XML, so I need to add additional annotations to its getters, and therefore I'm overriding them.
The problem is that when I try to run this code, I get a Hibernate MappingException saying: Duplicate property mapping of name found in Employee.
Is there a way to tell Hibernate that the name getter in Employee is not duplicate but just overriden (perhaps with some annotation). Or is there another way to do what I need?
Try adding #Transient to the overriding property:
#Entity
#Table(name="employee")
#XmlType(name="employee")
public class Employee extends Person {
#Override
#XmlAttribute(name = "name")
#Transient
public String getName() {
return super.getName();
}
}
this is untested code but i hope it will work, use #AttributeOverride annotation like this
#Entity
#Table(name="employee")
#XmlType(name="employee")
#AttributeOverride(name = "name", column = #Column(name = "name"))
public class Employee extends Person {
#Override
#XmlAttribute(name = "name")
public String getName() {
return super.getName();
}
}
Related
I have defined customer entity
#Entity
#Table(name = "customer")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and CrudRepository
public interface CustomerRepo extends CrudRepository<Customer, Long> {
}
if I use CustomerRepo.findById method for finding Customer
#Autowired
CustomerRepo repo;
Optional<Customer> dbCustomer = repo.findById(id);
how can I get name of that customer. I cannot use getter then.
so I'm interested is there any solution of using getters of Optional, or I need to use other method for finding Customer by id?
Optional<Customer> is returned, because it is not guaranteed that there will be such a customer with the requested ID in the database.
Instead of returning null it simply means that Optional.isPresent() will return false when the ID does not exist.
According to the API Docs (https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html#findById-ID-):
Returns:
the entity with the given id or Optional#empty() if none found
You will therefore probably want to simply use the methods on Optional to check whether it contains a Customer (i.e. a Customer with that ID exists), and then get the name like so:
Optional<Customer> dbCustomer = repo.findById(id);
if(dbCustomer.isPresent()) {
Customer existingCustomer = dbCustomer.get();
String nameWeWanted = existingCustomer.getName();
//operate on existingCustomer
} else {
//there is no Customer in the repo with 'id'
}
Alternatively you can try callback style (shown with Java 8 Lambda):
Optional<Customer> dbCustomer = repo.findById(id);
dbCustomer.ifPresent(existingCustomer -> {
String nameWeWanted = existingCustomer.getName();
//operate on existingCustomer
});
It is worth noting that it is possible to check existence of the ID without actually retrieving/loading the entity by using the interface method:
boolean CrudRepository.existsById(ID id)
This saves an entity load, but it still requires a database roundtrip.
Try to use another method for finding Customer:
#Autowired
CustomerRepo repo;
Customer dbCustomer = repo.findOne(id);
I have an entity class which inherits from four level of inheritance in which the top level parent defines the primary key (#Id) and I'm having trouble figuring out what I did wrong as I get this error:
Entity class [class D] has no primary key specified. It should define either an #Id, #EmbeddedId or an #IdClass. If you have defined PK using any of these annotations then make sure that you do not have mixed access-type (both fields and properties annotated) in your entity class hierarchy.
Here's the hierarchy:
A->B->C->(Entity)D
This is my non-entity class that gives the values to its children:
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
#MappedSuperclass
public class A implements Serializable {
#Id
#GeneratedValue
protected Long id;
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
protected Date deleted;
public Date getDeleted() {
return deleted;
}
public void setDeleted(Date deleted) {
this.deleted = deleted;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
and this is one of its child :
#MappedSuperclass
public abstract class B extends A implements Serializable {
}
B->C
import javax.persistence.Entity;
import javax.persistence.Transient;
#MappedSuperclass
public class C extends B{
protected String name;
protected String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
And finally C-> (Entity)D
#Entity
public class D extends C{
private String codeD;
public String getCodeD(){return codeD;}
public String setCodeD(String codeD) {this.codeD = codeD;}
}
According to every source I've found, normally with the #MappedSuperclass and implementing Serializable it should work. Thought I've tried implementing Serializable even every step of the hierarchy but I received the same error message.
I'm currently using Payara 4.1.1.1621. I don't know if that might be the problem as I've seen this kind of error in Payara on some thread but they all miraculously resolved themselves.
I resolved this error by adding my base class to persistence.xml.
The configuration seems to be as the specification suggests.
The only thing that comes to my mind that can be added is the #Column annotation to explicitly declare the database column names:
#Id
#GeneratedValue
#Column(name = "id")
protected Long id;
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
#Column(name = "deleted")
protected Date deleted;
Try it out. If it still doesnt work try to annotate all the fields in the classes marked as #MappedSuperClass.
Also, class C should have its fields marked as protected not private?
I have a database with common audit columns in each table but with different column names.
e.g
The Person table has the following audit columns,
(per_creation_user, per_creation_date, per_update_user, per_update_date), and the address table has audit columns called (add_creation_user, add_creation_date, add_update_user, add_update_date).
I am trying to map these using JPA annotations and use an event listener class to populate these audit columns automatically whenever they are persisted in the database.
I have a base abstract class containing these audit columns, I could then annotate this with #MappedSuperclass and put the entity listener annotation on here too. All neat and tidy, unfortunately the column names differ for each audited entity. I think the only option is to have the audit columns mapped separately on each entity?
Can anybody suggest a better method for doing this?
#EntityListeners(BaseDTOEventListener.class)
#MappedSuperclass
public abstract class BaseDTO {
private String creationUser;
private Date creationDate;
}
#Entity
#Table(name="PERSON")
public class Person extends BaseDTO{
}
#Entity
#Table(name="ADDRESS")
public class Address extends BaseDTO{
}
public class BaseDTOEventListener {
#PrePersist
public void onPreInsert(BaseDTO baseDTO){
baseDTO.setCreationUser("TEST");
baseDTO.setCreationDate(new Date());
}
}
Thanks to Alan for the hint, by specifying column names on each object as below. This worked :)
#Entity
#AttributeOverrides({#AttributeOverride(name="creationUser", column=#Column(name="PER_CREATION_USER", insertable=true, updatable=false)),
#AttributeOverride(name="creationDate", column=#Column(name="PER_CREATION_DATE" insertable=true, updatable=false})
#Table(name="PERSON")
public class Person extends BaseDTO{
}
Use the #Embeddable in combination with #MappedSuperClass:
First define the BaseDTO interface:
#EntityListeners(BaseDTOEventListener.class)
#MappedSuperclass
public abstract class BaseDTO {
public abstract getAuditEmbeddable();
public void setCreationDate(Date date){
getAuditEmbeddable().setCreationDate(date);
}
public void setCreationUser(String user){
getAuditEmbeddable().setCreationUser(user);
}
}
Then define the embeddable which will hold the audited fields.
User most common column names here.
#Embeddable
public class AuditEmbeddable{
#Column(name = "creationUser")
private String creationUser;
#Column(name = "creationDate")
private Date creationDate;
public String getCreationUser() {
return creationUser;
}
public void setCreationUser(String creationUser) {
this.creationUser = creationUser;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
}
Then you inject an embedded to each of the audited entities, overriding the column names where necessary:
#Entity
#Table(name="PERSON")
public class Person extends BaseDTO{
#Embedded
private AuditEmbeddable auditEmbeddable;
public AuditEmbeddable getAuditEmbeddable() {
return auditEmbeddable;
}
public void setAuditEmbeddable(AuditEmbeddable auditEmbeddable) {
this.auditEmbeddable = auditEmbeddable;
}
}
#Entity
#Table(name="ADDRESS")
public class Address extends BaseDTO{
// lets say here you have custom names for audit fields
#Embedded
#AttributeOverrides(
#AttributeOverride(name = "creationUser", column = #Column(name = "creationUser123")),
#AttributeOverride(name = "creationDate", column = #Column(name = "creationDate123"))
)
private AuditEmbeddable auditEmbeddable;
public AuditEmbeddable getAuditEmbeddable() {
return auditEmbeddable;
}
public void setAuditEmbeddable(AuditEmbeddable auditEmbeddable) {
this.auditEmbeddable = auditEmbeddable;
}
}
Finally the listener can stay as you wrote it:
public class BaseDTOEventListener {
#PrePersist
public void onPreInsert(BaseDTO baseDTO){
baseDTO.setCreationUser("TEST");
baseDTO.setCreationDate(new Date());
}
}
Hope that helps.
You can use hibernate envers for the same purpose. You can annotate with #Audited. Apply #NotAudited to the entities you do not want to be
#Entity
#Table(name="PERSON")
#Audited
public class Person extends BaseDTO{
}
#Entity
#Audited
#Table(name="ADDRESS")
public class Address extends BaseDTO{
}
I have a mapped super class that I use to define a method it's persistence mapping. I am using the table-per-class inheritance strategy. For example here is some simple class inheritance:
#MappedSuperclass
public class Feline {
private Long id;
private String identifier;
#GeneratedValue(strategy = "GenerationType.AUTO")
#Id
public Long getId() {
return id;
}
public String getIdentifier() {
return identifier;
}
// other getters and setters, methods, etc.
}
The next class does not override the getIdentifier() method and saves the Cat's identifier in the "identifier" column of it's entity table.
#Entity
public class Cat extends Feline {
private Date dateOfBirth;
private Set<Kitten> kittens;
#OneToMany(mappedBy = "mother")
public Set<Kitten> getKittens() {
return kittens;
}
// other getters and setters, methods, etc.
}
In the Kitten class I want to change the identifier to return the Kitten.identifier + " kitten of " + mohter.getIdentifier() or for example "Boots kitten of Ada" and persist this String in the "identifier" column of the entity's table.
#Entity
public class Kitten extends Cat {
private Cat mother;
#ManyToOne
public Cat getMother() {
return mother;
}
#Override
public String getIdentifier() {
return this.getIdentifier() + " kitten of " + mother.getIdentifier();
}
}
When I run this code I get an error message "Caused by: org.Hibernate.MappingException: Duplicate property mapping of identifier found in com.example.Kitten."
Since I am extending a #Mappedsuperclass the identifier field should be mapped to the "identifier" column of each entity table but for some reason this doesn't happen and it tries to map the identifier field twice when I override the getIdentifier() method in the Kitten class.
Both the Cat and Kitten tables have "identifier" columns. I do not understand why I cannot override a method if it returns the correct type to map to the same column.
That won't work. But you can define a discriminator.
Have a look at http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/inheritance.html
I have really got stuck with using Hibernate in my project. Some issues I have described here: Hibernate: getting too many rows I have started wondering if my code is correct. I am working on a huge project and I have had to define mapping classes with annotations on my own. But when the problems have began to occur I have decided to recreate part of database separate to the project and try to generate entities in IDE.
I have two tables: My and Option. My has primary key: column qwerty and property. Propertyis the foreign key from Option table. And of course Option has property as a primary key.
In my solution I have created #Embeddable MyPK class with two properties: String qwerty and String property. In my My entity I have of course #EmbeddedId MyPK and also property (the same column name as in the MyPK) but is this Option object, not String as in the MyPK.
#ManyToOne
#JoinColumn(name = "property", nullable = false, insertable = false, updatable = false)
protected Option option;
This is entity generated by Hibernate Tools in Intellij Idea. There isn't EmbeddedId, but there is #IdClass. I have thought that #IdClass is only for basic types. But I have a object as a part of my primary key. However there is also OptionEntity object here. Is this correct to keep basic type and object type for one column?
#javax.persistence.IdClass(test.go.MyEntityPK.class)
#javax.persistence.Table(name = "MY", schema = "PUBLIC", catalog = "PUBLIC")
#Entity
public class MyEntity {
private String qwerty;
#javax.persistence.Column(name = "QWERTY")
#Id
public String getQwerty() {
return qwerty;
}
public void setQwerty(String qwerty) {
this.qwerty = qwerty;
}
private String text;
#javax.persistence.Column(name = "TEXT")
#Basic
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
private String lang;
#javax.persistence.Column(name = "PROPERTY")
#Id
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property= property;
}
#Override
public boolean equals(Object o) {
//equals
}
#Override
public int hashCode() {
//hashCode
}
private OptionEntity optionByProperty;
#ManyToOne
#javax.persistence.JoinColumn(name = "PROPERTY", referencedColumnName = "PROPERTY", nullable = false)
public OptionEntity getOptionByProperty() {
return optionByProperty;
}
public void setOptionByProperty(OptionEntity optionByProperty) {
this.optionByProperty = optionByProperty;
}
}
This is MyEntityPK generated class:
public class MyEntityPK implements Serializable {
private String qwerty;
#Id
#Column(name = "qwerty")
public String getQwerty() {
return qwerty;
}
public void setQwerty(String qwerty) {
this.qwerty = qwerty;
}
private String property;
#Id
#Column(name = "PROPERTY")
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
#Override
public boolean equals(Object o) {
//equals
}
#Override
public int hashCode() {
//hashCode
}
}
OptionEntity below. No special points aren't in this entity. I would like only #Version annotation on version property and also List<MyEntity> instead of Collection<MyEntity>.
#javax.persistence.Table(name = "OPTION", schema = "PUBLIC", catalog = "PUBLIC")
#Entity
public class OptionEntity {
private Long version;
#javax.persistence.Column(name = "VERSION")
#Basic
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
private String property;
#javax.persistence.Column(name = "PROPERTY")
#Id
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
#Override
public boolean equals(Object o) {
//equals
}
#Override
public int hashCode() {
//hashcode
}
private Collection<MyEntity> myByProperty;
#OneToMany(mappedBy = "optionByProperty")
public Collection<MyEntity> getMyByProperty() {
return myByProperty;
}
public void setMyByProperty(Collection<MyEntity> myByProperty) {
this.myByProperty = myByProperty;
}
}
What option is the most proper and less problematic? The one that I have described or the one that pasted?
get rid of property private String lang;/private String property; it is already defined by the manytoone. you also don't need a class for the primary key of MyEntity. MyEntity can be its own id class with the two properties qwerty and option as its key-property, key-manytoone.
Check out JPA 2.0 examples using derived Ids:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/2.0/DerivedIdentifiers
which seem to be what you are after.
In JPA, you do not need an embeddedId for your ids, but if using a composite PK, you do need a class to hold the multiple values that make up the pk. Instances of this class are passed to the em.find method, and it can be either an EmbeddedId or a PKClass. I prefer using PKClass myself, but its up to you - using an embedded just places the fields within the embeddedable class, so you use the embedded object to set the mappings and access the values. If using a pkClass, you do not need the fields/properties annotated within it since they are accessed and mapped within the entity directly.