I have a problem with abstract class where we implement an interface.
Now the interface is in our implementation of the abstract class other than the other implementation.
I'll show you the code here:
#MappedSuperclass
public abstract class AbstractOrder {
#Id
#GeneratedValue
private Long idOrder;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="datum")
private Date date = new Date();
#OneToMany(targetEntity=IOrderLine.class)
private List<IOrderLine> orderLines = new ArrayList<IOrderLine>();
private String refOrder;
...
}
#Entity
#Table(name="supplyorders")
public class SupplyOrder extends AbstractOrder implements Comparable<SupplyOrder>, Serializable {
#ManyToOne
private Supplier supplier;
#Enumerated(EnumType.STRING)
private SupplyOrderStatus status = SupplyOrderStatus.TOBESUPPLIED;
#ElementCollection
private Set<CustomerOrder> customerOrders = new HashSet<CustomerOrder>();
...
}
#Entity
#Table(name="customerorders")
public class CustomerOrder extends AbstractOrder implements commparable<CustomerOrder>,Serializable {
#ManyToOne
private Customer customer;
#ManyToOne
private Place place;
#ManyToOne
private User vendor;
private double deposit;
#Enumerated(EnumType.STRING)
private OrderStatus status = OrderStatus.CREATED;
}
#MappedSuperclass
public interface IOrderLine {
double getSubTotal();
int getQuantity();
Furniture getFurniture();
}
#Entity
#Table(name="supplyorderlines")
public class SupplyOrderLine implements IOrderLine, Serializable {
#Id
#GeneratedValue
private Long id;
#OneToMany
private List<CustomerOrderLine> customerOrderLines = new ArrayList<CustomerOrderLine>();
...
}
and of course a class CustormerOrderLine that implements IOrderLine.
Now for the supplyOrder they have supplyOrderLines in them and the customerOrder has the CustomerOrderLine in them.
The fault we get is that the abstract class doesn't know what implementation to take of the interface IOrderLine.
How can I override the field of orderLines from the abstract class in the implementation class and point to the implementation of the IOrderLine with annotations?
Thx in advance.
Chillworld
In Java you cannot instantiate an interface.
You can only instantiate actual classes that implement interfaces.
There's actually no such thing as IOrderLine.class.
You probably want to declare your orderLines field in your sub-classes.
In the sub-classes you can declare the field with a concrete class (that will map to a real database table).
If you need/want to use the abstract class to refer to your line items generically (this seems like a really good idea), you could use an abstract method that returns an interface.
Here's an example:
#MappedSuperclass
public abstract class AbstractOrder {
#Id
#GeneratedValue
private Long idOrder;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="datum")
private Date date = new Date();
// This abstract method will be implemented by sub-classes
public abstract List<IOrderLine> getOrderLines();
}
Then you can add the fields in your sub-classes and implement the abstract method that returns them:
#Entity
#Table(name = "supplyorderlines")
public class SupplyOrderLine implements IOrderLine, Serializable {
#Id
#GeneratedValue
private Long id;
#OneToMany(targetEntity = SupplyOrderLine.class)
private List<SupplyOrderLine> customerOrderLines;
#Override
public List<IOrderLine> getOrderLines() {
return customerOrderLines;
}
}
If this wasn't about JPA entities, you could also do something like this:
public abstract class PojoClass {
private Long idOrder;
private Date date = new Date();
private List<? extends IOrderLine> orderLines = new ArrayList<? extends IOrderLine>();
}
However, I don't think this is an option in a JPA entity.
That's because your entity class needs to map to a concrete class and database table.
Related
Overview
I've got an #Entity with an #EmbeddedId composite key. The entities are exposed over a REST api which uses a BackendIdConverter to convert the id string back to an instance of the #Embeddable composite key. My understanding is that this is then used to identify an instance of the #Entity, but that isn't happening.
Question
How is the #Embeddable composite key resolved back to an #Entity?
Code
#Entity
public class MyEntity {
#EmbeddedId
private MyEntityIdentifier id;
#Embeddable
public class MyEntityIdentifier implements Serializable {
public static final String COMPOSITE_KEY_DELIMITER = "_#_";
#Column
private String idPartOne;
#Column
#Temporal(TemporalType.DATE)
private Date idPartTwo;
#Component
public class StringToMyEntityIdentifierConverter implements BackendIdConverter {
#Override
public Serializable fromRequestId(String id, Class<?> aClass) {
String[] split = id.split(COMPOSITE_KEY_DELIMITER);
String idPartOne = split[0];
Date idPartTwo = Date.valueOf(split[1]);
return new MyEntityIdentifier(fullName, lastUpdated);
}
public interface MyEntityRepository extends JpaRepository<MyEntity, MyEntityIdentifier> {
}
I inherited some pretty awful code that I am looking to refactor to make more reusable. There is a set of reporting tables which are primarily composed of 3 columns: id, report_type_fk, and report_description. I would like to merge all the reporting tables into one for ease of use.
I am refactoring the code and think that it would be better to break our current entities up so that Report is an abstract class with type implementations. For example a DmvReport extends Report, CreditScoreReport extends Report, etc.
The problem I am running into is that there would only be 1 report table that all entities would need to save to. Is there a way to make all concrete implementations of the abstract Report object save into the same table?
Here's an example of the bad code I inherited
Report class
#Entity
#Table(name = "report")
public class Report<E extends Exception> {
private long id;
private ReportType type;
private String description;
...
...
}
CreditReport class
#Entity
#Table(name = "credit_report")
public class CreditScore Report<E extends Exception> extends Report<E> {
private long id;
private ReportType type;
private String description;
...
...
}
I am looking to turn it into:
#MappedSuperclass
#Table(name = "report")
public abstract class Report<E extends Exception> {
#Id #Column(name="id")
private long id;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "report_type_id")
private ReportType type;
#column(name="description")
private String description;
...
...
}
#Entity
#Table(name = "report")
public class CreditScoreReport<E extends Exception> extends Report<E> {
public void doCreditScoreStuff(){
...
}
}
#Entity
#Table(name = "report")
public class DmvReport<E extends Exception> extends Report<E> {
public void doDmvStuff(){
...
}
}
I think you should use #Inheritance instead of #MappedSuperClass. Your code would look like this:
#Entity
#Table(name = "report")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "report_type_id", discriminatorType = DiscriminatorType.INTEGER)
public abstract class Report<E extends Exception> {
#Id #Column(name="id")
private long id;
#column(name="description")
private String description;
...
...
}
#Entity(name = "CreditScoreReport")
#DiscriminatorValue("1") // the id corresponding to the credit score report
public class CreditScoreReport<E extends Exception> extends Report<E> {
#Column(name = "specific_credit_score_report_1)
private Integer specificCreditScoreReport1;
public void doCreditScoreStuff(){
...
}
}
#Entity(name = "DmvReport")
#DiscriminatorValue("2") // the id corresponding to the DMV report
public class DmvReport<E extends Exception> extends Report<E> {
#Column(name = "specific_dmv_score_report_1)
private Integer specificDmvScoreReport1;
public void doDmvStuff(){
...
}
}
This strategy allows you to store credit score report and DMV report data in one table (report), but instanciate the proper entity according to the report_value_id field. You don't have to define the report_value_id in your parameters because it was already used to create the required entity.
Is this what you're looking for?
I have superclass:
#MappedSuperclass
public abstract class BaseEntity {
#Id #GeneratedValue
private Long id;
#Version
private long version;
}
and two subclasses:
#Entity
#Table(name = "\"user\"")
public class User extends BaseEntity {
private String username;
#org.hibernate.annotations.Type(type = "yes_no")
private boolean isAdmin;
// constructor/getters/setters etc.
}
#Entity
public class Product extends BaseEntity {
public String name;
public BigDecimal price;
// constructor/getters/setters etc.
}
I can query for all subclasses using code:
entityManager.unwrap(Session.class)
.createCriteria(BaseEntity.class)
.list()
.forEach(x -> System.out.println(x));
how I can get the same results via JPA (without unwrap, is it possible?). I tried using createQuery("from BaseEntity") but get BaseEntity not mapped exception.
EDIT: I know that this will result in two SELECT statement. And it must be MappedSuperclass - I would like to not change that.
I have some entities extended with a generic BaseEntity which have a Id property and I want to do a method where I pass an entity and retrieve that id, i.e.
BaseEntity
public abstract class BaseEntity implements Serializable {
#Id
#GeneratedValue
private Long id;
// Getters and setters
}
Entity
public class Entidad extends BaseEntity {
protected String name;
protected String image;
protected Set<ContactForm> contactForms = new HashSet<ContactForm>();
}
(ContactForm also extends from BaseEntity)
And I want do something like this:
List<Long> longlist;
longlist = retrieveIds(entidad.getContactForms);
[...]
public List<Long> retrieveIds(Set<BaseEntity> entidades){
List<Long> lista = new ArrayList<Long>();
for(BaseEntity entidad : entidades){
lista.add(entidad.getId());
}
return lista;
}
It's possible? How?
Yes. That is possible.
Just create a method in your super class and override that method in all child's which return id of that class.
Create a method getId() to return the Id of BaseEntity
BaseEntity
public abstract class BaseEntity implements Serializable{
private Long id;
public Long getId() {
return this.id;
}
}
I have an interface called Person as below
public interface Person {
String getName();}
I have an abstract class, AbstractPerson which implement Person. Abstar
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="PERSON_TYPE")
#Table(name="PERSON")
public class AbstractPerson implements Person{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
.....
#Override
public String getName() {
return firstName + " " + lastName;
}
My concrete class is Member so it extends AbstractPerson.
#Entity
#DiscriminatorValue(value="MEMBER")
public class Member extends AbstractPerson{
#OneToMany(mappedBy="commentOwner")
#MapKey(name="id" )
private Map<Long, CommentImpl> commentList;
....
The code that creates the ManyToOne relation in CommentImpl is below
public class CommentImpl implements Comment, Serializable{
#ManyToOne
private Member commentOwner;
....
My problem is I want to write the code against interfaces instead of concrete class. So The value type in HashMap will be Comment in Member class and the commentOwner will be Person type in CommentImpl class.
When I do that, I get a unknowm mapping exception. How can I set this relationship with interfaces and concrete classes?
The one-to-many side becomes:
#OneToMany(mappedBy="commentOwner", targetEntity = "CommentImpl.class")
#MapKey(name="id" )
private Map<Long, Comment> commentList;
and the many-to-one side should be:
#ManyToOne(targetEntity = "Member.class")
private Person commentOwner;