jpa mapped superclass without id - java

I'm curious about the following problem. I've two entites, A and B. It stores almost the same information (for example, a name - in real life it's more complex), but the joins, and the foreign keys differs.
Can I do a mapped superclass, without an Id. And class A and class B, extending the mapped superclass, containing only the Id attribute?
For example:
import lombok.Getter;
import lombok.Setter;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToMany;
#MappedSuperclass
#Getter
#Setter
#Data
class superClass {
#Column(name = "name")
private String name;
}
#Entity
#Table(name = "A")
#Data
class A extends superClass {
#Id
#OneToMany
#JoinColumn(name = "id", referencedColumnName = "referencedName")
private SomeClass id;
}
#Entity
#Table(name = "B")
#Data
class B extends superClass {
#Id
#OneToOne
#JoinColumn(name = "id", referencedColumnName = "referencedName")
private SomeOtherClass id;
}
Would it be valid by the JPA? I did read the mappedSuperClass's JavaDocs, and says nothing about it. I would said, that it is valid - but the IntelliJ Idea says, that the super class has to have an Id attribute. I didn't find anything on the internet about this.
edit: sorry, I missed it. I left the Entity annotation on the superClass, and that's why the Idea signed the error. I removed that, and the error disappeared. But I'm not sure, that this is valid, though.

yes, there is no requirement that a MappedSuperclass have anything in it. It is just providing extra annotations for the subclasses.

Yes it is valid. Anyway your superclass will not appear as a table in the DB.

Related

Spring Boot JPA. Removing entity in oneToMany relationships

This is my entity
package com.nimesia.sweetvillas.entities;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.List;
#Entity
#Table(name = "specs", schema = "crm")
public class SpecEntity extends AbsEntity {
#Id
#Column(name = "spec_id")
private #Getter #Setter String id;
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "specs_translations",
schema="crm",
joinColumns = #JoinColumn(name = "spec_id"),
inverseJoinColumns = #JoinColumn(name = "translation_id")
)
private #Getter #Setter
List<TextEntity> texts;
}
As you can see there is a oneToMany relationships with TextEntity. Such relationship is generated through the specs_translations table.
Here comes the problem.
When it comes to creating the specEntity I can create also its subentities (translations, in this case). In the db, a reference in specs_translations and a record in translations (table which contains the records for textEntities) will be created. As it should be.
But when it comes to updating and removing a TextEntity from my SpecEntity, while the reference in specs_translations gets removed, the relative translation record stays.
This leads to a situation such as the one depicted in the following pics
How can I delete the record in translations when I remove its reference in specs_translations? I would like to achieve this through JPA and not through the DB.
I solved it. I just set orphanRemoval to "true".

#Calculation annotation does not work in OpenXava

In my OpenXava application, the #Calculation annotation does not work.
Here my coding for my #Embeddable that uses #Calculation:
import java.math.*;
import java.time.*;
import javax.persistence.*;
import org.openxava.annotations.*;
import lombok.*;
#Getter #Setter
#Embeddable
public class Payment {
#ManyToOne(fetch=FetchType.EAGER)
#DescriptionsList
Paymentfrequency paymentFrequency;
LocalDate firstPaymentDate;
#Stereotype("MONEY")
BigDecimal paymentAmount;
#ManyToOne(fetch=FetchType.LAZY)
#DescriptionsList
Methodofpayment methodOfPayment;
#ReadOnly
#Stereotype("MONEY")
#Calculation("paymentAmount * paymentFrequency.frequencyPerYear")
BigDecimal annualContribution;
}
And this the code for the entity with the collection of embeddables:
import javax.persistence.*;
import lombok.*;
#Entity #Getter #Setter
public class Paymentfrequency extends GenericType {
int frequencyPerYear;
// Payment is used as collection
#ElementCollection
#ListProperties("firstPaymentDate, paymentAmount, paymentFrequency,
methodOfPayment, annualContribution")
Collection<Payment> payments;
}
And this the result:
Note as the last column (annualContribution) is not recalculated when the operands change.
Why does not work #Calculation in this case?
#Calculation only works if all the operands are displayed in the user interface. In your case paymentFrequency.frequencyPerYear is not displayed given paymentFrequency is a reference displayed as #DescriptionsList.
Don't worry, just use a regular Java calculated property instead. In this way:
#Stereotype("MONEY")
#Depends("paymentAmount, paymentFrequency.id")
public BigDecimal getAnnualContribution() {
// You should refine the below code to lead with nulls
return getPaymentAmount().multiply(getPaymentFrequency().getFrequencyPerYear());
}
Learn more about calculated properties here:
https://openxava.org/OpenXavaDoc/docs/basic-business-logic_en.html

Spring JsonIgnore annotation doesn't work in Map

So I'm working in Java, Spring. I have an entity called Pizza, that has two realtionships, one of them is a Set of Ordered Pizzas. Those have #JsonIgnore annotation, and it does work if I just want to return a List of Pizzas, or just one pizza.
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity
#Table(name = "pizza")
public class Pizza implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id")
private Integer id;
....
#JsonIgnore
#OneToMany(mappedBy = "pizza")
private Set<OrderedPizza> oPizza;
However, now I want to return a HashMap<Integer, ArrayList<Pizza>>, and when I do, every single field of Pizza is visible, even though they still have #JsonIgnore annotation. What am I doing wrong? Is there a solution? Also, this oPizza doesn't have a getter so it shouldn't even be visible at all.
You can use below :
import org.codehaus.jackson.annotate.JsonIgnore;

does lombok have side effects on jpa

I am working on converting a jpa entity to use lombok. The resulting code is the following:
#Entity
#Table(name = "TEST")
#Data
#NoArgsConstructor
#AllArgsConstructor
class Test {
...
#Column(name = "FORMATTING")
#Enumerated(EnumType.ORDINAL)
private FormatType formatType;
...
}
The resulting error message contains the following
Caused by: org.hibernate.HibernateException: Missing column: formatType in TEST
I am really not sure what to google here. (I tried pasting everything before formatType into google - didn't see anything)
NOTE:
fields have been renamed and aspects which do not appear relevant have been omitted, for the sake of brevity and privacy. if something looks like a typo, it probably is. please let me know if you notice something so that i can address it.
the 3 lines describing the field are unchanged from the code i'm working with
EDIT:
I just noticed this right before the error message
13:22:19,967 INFO [org.hibernate.tool.hbm2ddl.TableMetadata] (ServerService Thread Pool -- 57) HHH000261: Table found: TABLE
13:22:19,967 INFO [org.hibernate.tool.hbm2ddl.TableMetadata] (ServerService Thread Pool -- 57) HHH000037: Columns: [..., formatType, ...]
13:22:19,968 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 57) MSC000001: Failed to start service jboss.persistenceunit."...": org.jboss.msc.service.StartException in service jboss.persistenceunit."...": javax.persistence.PersistenceException: [PersistenceUnit: ...] Unable to build EntityManagerFactory
Should be functional
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "PARENT")
public abstract class Parent implements Serializable {
private static final long serialVersionUID = 1;
#Id
#Column(name = "ID")
#GeneratedValue
private long id;
#Column(name = "ENABLED")
private boolean enabled;
}
#Entity
#Table(name = "CHILD")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Child extends Parent {
/** XXX: HERE BE DRAGONS */
#Column(name = "ENUM_1")
#Enumerated(EnumType.STRING)
private Enum1 enum1;
#Column(name = "ENUM_2")
#Enumerated(EnumType.ORDINAL)
private Enum2 enum2;
/** XXX: NO MORE DRAGONS */
#Column(name = "FREQUENCY")
private String frequency;
#Column(name = "EMPTY")
private boolean empty;
#Column(name = "MAX_SIZE")
private int maxSize;
}
public enum Enum1 {
A,
B,
C
}
public enum Enum2 {
X,
Y,
Z
}
I have rolled back the lombok changes, I would still like to know what the issue is, but there is no rush. Also, thanks to this lovely little bug i am about 4 hours behind so i may be a little slow on the responses.
The pk of the child table is an fk to the parent table, and without lombok everything appears to work, despite the fact that the Child class has no id.
SOLUTION:
I completely forgot about asking this. Not long ago I revizited this problem. To explain the solution lets look at a slightly simplified version of the first example i included.
#Entity
#Table(name = "TEST")
#Setter
#Getter
class Test {
...
#Column(name = "FORMATTING")
#Enumerated(EnumType.ORDINAL)
private FormatType formatType;
...
}
It would appear that Lombok will give you this:
#Entity
#Table(name = "TEST")
class Test {
...
#Column(name = "FORMATTING")
#Enumerated(EnumType.ORDINAL)
private FormatType formatType;
public FormatType getFormatType() {
return formatType;
}
public void setFormatType(FormatType formatType) {
this.formatType = formatType;
}
...
}
Note that the annotations are still attached to the field. Now, I am not certain if it is just the version or implementation of JPA that we are using but I gather that if an accessor is defined jpa just ignores any annotations besides #Column (as well as any parameters specified for #Column - which is why jpa was looking for the wrong column name). So we actually need:
#Entity
#Table(name = "TEST")
class Test {
...
private FormatType formatType;
#Column(name = "FORMATTING")
#Enumerated(EnumType.ORDINAL)
public FormatType getFormatType() {
return formatType;
}
public void setFormatType(FormatType formatType) {
this.formatType = formatType;
}
...
}
After a great deal of confusion trying to find examples and fill in some specifics regarding how lombok does its thing (to be fair I am very easily confused) i discovered this little gem: onMethod=#__({#AnnotationsHere}). Utilizing this feature I came up with the following:
#Entity
#Table(name = "TEST")
#Setter
class Test {
...
#Getter(onMethod=#__({
#Column(name = "FORMATTING"),
#Enumerated(EnumType.ORDINAL)
}))
private FormatType formatType;
...
}
And presto it works. Now that we have what is apparently the only available solution I would like to address the question we are all pondering at the moment: is that really any cleaner than just writing the method manually and attaching the annotations there? Answer: ... I have no idea. I am just happy I found a solution.
Its strange. Can you show more code?
I'm trying to write a simple project with part of code like in your question and it worked. I used Spring Boot and MySQL. Try to check your configuration. There is my code:
Enum:
public enum FormatType {
FIRST_TYPE, SECOND_TYPE
}
Table in MySQL:
create table TEST
(
ID int auto_increment primary key,
FORMATTING int not null
);
Entity:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
#Entity
#Table(name = "TEST")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Test {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "FORMATTING")
#Enumerated(EnumType.ORDINAL)
private FormatType formatType;
}
Repository:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface TestRepository extends JpaRepository<Test, Integer> {
}
Service:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class TestService {
private TestRepository repository;
#Autowired
public TestService(TestRepository repository) {
this.repository = repository;
}
public List<Test> getAllTestEntities() {
return repository.findAll();
}
}
Is unlikely that lombok causes runtime problems, as it works on precompile time, you might find useful to decompile the generated code, I sometimes find that the order in which lombok annotations are placed in the source code affect the final result, so, you use #Data and #NoArgsConstructor , I guess you can remove #NoArgsConstructor an try to see if that solves your problem.
I faced the same problem with Lombok and JPA but I setup the Lombok and it worked as expected. Below is the code:
Controller
package com.sms.controller;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.sms.model.StudentModel;
import com.sms.persistance.StudentRepository;
#RestController
public class StudentController {
#Autowired
private StudentRepository sr;
#PostMapping("/addstudent")
public String addStudent(#Valid #RequestBody StudentModel studentModel) {
StudentModel result = sr.save(studentModel);
return result.equals(null)?"Failed":"Successfully Saved student data";
}
}
Model
package com.sms.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
import lombok.RequiredArgsConstructor;
#Data
#RequiredArgsConstructor
#Entity
#Table(name="student", schema="development")
public class StudentModel {
#Id
#Column(name="student_id")
private int id;
#Column(name="student_name")
private String studentname;
#Column(name="student_address")
private String studentaddress;
}
Repository
package com.sms.persistance;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.sms.model.StudentModel;
#Repository
public interface StudentRepository extends JpaRepository<StudentModel, Integer>{
}

Issue in JPA Cascade Save with EmbeddedId in child

I am having three class. Person,vehicle and a association class to link the person and vehicle
Person
package entity;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
#Entity
#Table(name ="PERSON")
public class Person {
#EmbeddedId
private PKperson pkPerson;
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(cascade=CascadeType.ALL,mappedBy="person")
private Set<PersonVehAssnVO> personVehAssnVOSet=new HashSet<PersonVehAssnVO>();
//getters & setters
}
PKperson
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Embeddable;
#Embeddable
public class PKperson implements Serializable {
#Column(name="NAME", nullable=false)
private String name;
#Column(name="DOB_DT", nullable=false)
private Date dobDt;
}
Vehicle
package entity;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.OneToMany;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
#Entity
#Table(name ="VEHICLE")
public class Vehicle {
#Id
#Column(name="VEHICLE_ID",unique=true, nullable=false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_name")
#SequenceGenerator(allocationSize = 1, name = "seq_name", sequenceName = "SEQ_VEHICLE_ID")
private Long vehicleId;
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(cascade=CascadeType.ALL,mappedBy="vehicle")
private Set<PersonVehAssnVO> personVehAssnVOSet=new HashSet<PersonVehAssnVO>();
private String vehicleName;
//getters & setters
}
Person Vehicle Association
package entity;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
#Entity
#Table(name ="PERSON_VEHICLE_ASSOC")
public class PersonVehAssnVO {
#EmbeddedId
private PKperson pkPerson;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "pkPerson.name",referencedColumnName ="NAME"),
#JoinColumn(name = "pkPerson.dobDt",referencedColumnName ="DOB_DT")})
private Person person;
#ManyToOne
#JoinColumn(name = "VEHICLE_ID", referencedColumnName = "VEHICLE_ID")
private Vehicle vehicle;
//getters & setters
}
//**Save Method**
PKperson pkPerson = new PKperson();
SimpleDateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = dtFormat.parse("1984-12-14");
pkPerson.setName("Magesh");
pkPerson.setDobDt(date1);
Person person = new Person();
person.setPKperson(pkPerson);
Vehicle vehicle = new Vehicle();
vehicle.setName("Honda350");
PersonVehAssnVO perVehAssnVO = new PersonVehAssnVO();
PersonVehAssnVO.setPKperson(pkPerson);
PersonVehAssnVO.setVehicle(vehicle);
Set<PersonVehAssnVO> assocSet = new HashSet<PersonVehAssnVO>();
assocSet.add(PersonVehAssnVO);
person.setpersonVehAssnVOSet(assocSet);
vehicle.setpersonVehAssnVOSet(assocSet);
Session session = getHibernateTemplate().getSessionFactory().openSession();
transaction = session.beginTransaction();
transaction.begin();
session.save(person);
transaction.commit();
//=============================================================
While Executing the above save logic I am getting error ": [entity.PersonVehAssnVO#component[name,dobDt]{dobDt=magesh, dobDt=1984-12-14 00:00:00}]"
Show Sql Gives "select personVehAssnVO_.NAME, personVehAssnVO_.DOB_DT, personVehAssnVO_.VEHICLE_ID as vehicle_34 from PERSON_VEHICLE_ASSOC where personVehAssnVO_.NAME=? and personVehAssnVO_.DOB_DT=?"
I want to save Person,Vehicle and association in a single save means CASCADE ALL When I save Person.
Any help appreciated
Mark the date in PKPerson with the #Temporal annotation:
#Temporal(TemporalType.TIME)
#Column(name="DOB_DT", nullable=false, length = 8)
private Date dobDt;
According to the Java Doc
This annotation must be specified for persistent fields or properties
of type java.util.Date and java.util.Calendar. It may only be
specified for fields or properties of these types.
The Temporal annotation may be used in conjunction with the Basic
annotation, the Id annotation, or the ElementCollection annotation
(when the element collection value is of such a temporal type.
And according to this SO question:
In plain Java APIs, the temporal precision of time is not defined.
When dealing with temporal data you might want to describe the
expected precision in database. Temporal data can have DATE, TIME, or
TIMESTAMP precision (ie the actual date, only the time, or both). Use
the #Temporal annotation to fine tune that.
I hope this solves your problem. You can interchange the TemporalType with others that match your field type in the database. The column length also can be changed accordingly.
Edit
I think you also need to remove the mappedBy="person" and mappedBy="vehicle" from the annotation of the PersonVehAssnVO sets in the Person and Vehicle classes and replace them with full column properties so that these classes can be the owners of the relationship. Otherwise when you save a person, it will ignore updating any properties marked with the mappedby annotation because this means the Person is not the owner of that relationship.

Categories