I'm trying to use JPA for the first time in a project. Most of my entities are working fine, but I am having trouble with one which is part of a Joined Inheritance Strategy.The entities are also being serialised by Jackson so they also have Json annotations.
The parent "User" class: (Edit: added "Type" field)
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include= JsonTypeInfo.As.WRAPPER_OBJECT) @JsonTypeName("user") @JsonSubTypes({ @JsonSubTypes.Type(name="customer", value=Customer.class), @JsonSubTypes.Type(name="employee", value=Employee.class)}) @Entity(name = "User") @Table(name="user") @Inheritance(strategy = InheritanceType.JOINED) @DiscriminatorColumn(name="type",discriminatorType = DiscriminatorType.INTEGER) @NamedQuery(name="User.all",query = "select u from User u") public abstract class User { @Id private String username; @Column(name = "type",nullable = false) private int type; public User(){ } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public abstract Set<Order> getOrders(); } A Child "Employee"
@JsonTypeName("employee") @Entity(name="Employee") @Table(name="employee") @PrimaryKeyJoinColumn(name = "username",referencedColumnName = "username") @DiscriminatorValue("1") @NamedQuery(name = "Employee.all",query = "select e from Employee e") public class Employee extends User implements Serializable{ private String username; private String firstName; private String lastName; private String email; @Convert(converter = LocalDatePersistenceConverter.class) private LocalDate dateStarted; @Convert(converter = LocalDatePersistenceConverter.class) private LocalDate dateEnded; @OneToMany(mappedBy = "employee",targetEntity = Order.class,fetch = FetchType.EAGER,cascade = CascadeType.PERSIST) @JsonIgnore private Set<Order> orders = new HashSet<>(); public Employee() { } @Override public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } public void addOrder(Order order){ orders.add(order); } public void setFirstName(String firstName) { this.firstName = firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public void setEmail(String email) { this.email = email; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getEmail() { return email; } public String getDateStarted() { if(dateStarted != null) return dateStarted.toString(); else return null; } public void setDateStarted(LocalDate dateStarted) { this.dateStarted = dateStarted; } public String getDateEnded() { if(dateEnded != null) return dateEnded.toString(); else return null; } public void setDateEnded(LocalDate dateEnded) { this.dateEnded = dateEnded; } @Override public String toString(){ return getUsername(); } } And a child "Customer": (Edit: removed @Id field)
@JsonTypeName("customer") @Entity(name="Customer") @Table(name="customer") @PrimaryKeyJoinColumn(name = "username",referencedColumnName = "username") @DiscriminatorValue("2") @NamedQueries({ @NamedQuery(name="Customer.all",query = "select c from Customer c") }) public class Customer extends User implements Serializable{ public enum VIP_TYPE {NORMAL,SILVER,GOLD,DIAMOND} @Transient private static final int SILVER_THRESHOLD = 1000; @Transient private static final int GOLD_THRESHOLD = 2000; @Transient private static final int DIAMOND_THRESHOLD = 3000; private String firstName; private String lastName; private String email; private String address; private String postcode; private String mobileNumber; private String homeNumber; @Convert(converter = VipTypeConverter.class) private VIP_TYPE vipGroup; private String discount; @OneToMany(mappedBy = "customer",targetEntity = Order.class,fetch=FetchType.EAGER,cascade = CascadeType.ALL) @JsonIgnore private Set<Order> orders = new HashSet<>(); public Customer() { } @Override public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } public void addOrder(final Order order){ orders.add(order); updateVipGroup(); } private void updateVipGroup() { int sum = orders.stream().map(Order::getPayment).distinct().mapToInt(p->p.getAmmount()).sum(); if(sum > DIAMOND_THRESHOLD){ vipGroup = VIP_TYPE.DIAMOND; return; } if(sum > GOLD_THRESHOLD){ vipGroup = VIP_TYPE.GOLD; return; } if(sum > SILVER_THRESHOLD){ vipGroup = VIP_TYPE.SILVER; return; } } public void setFirstName(String firstName) { this.firstName = firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public void setEmail(String email) { this.email = email; } public void setAddress(String address) { this.address = address; } public void setDiscount(String discount) { this.discount = discount; } public void setVipGroup(VIP_TYPE vipGroup) { this.vipGroup = vipGroup; } public void setHomeNumber(String homeNumber) { this.homeNumber = homeNumber; } public void setMobileNumber(String mobileNumber) { this.mobileNumber = mobileNumber; } public void setPostcode(String postcode) { this.postcode = postcode; } public String getDiscount() { return discount; } public VIP_TYPE getVipGroup() { return vipGroup; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getEmail() { return email; } public String getAddress() { return address; } public String getPostcode() { return postcode; } public String getMobileNumber() { return mobileNumber; } public String getHomeNumber() { return homeNumber; } } Persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="local" transaction-type="JTA"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>jdbc/cod</jta-data-source> <class>com.technicalpioneers.cod.user.Customer</class> <class>com.technicalpioneers.cod.user.Employee</class> <class>com.technicalpioneers.cod.user.User</class> <exclude-unlisted-classes>false</exclude-unlisted-classes> </persistence-unit> </persistence> Everything to do with "employee" works file, I can use the named query Employee.all to find all the employees in the database.
However, If I try to retrieve any customers I get errors. If I try to run the named query Customer.all I get:
java.lang.IllegalArgumentException: NamedQuery of name: Customer.all not found. If I try to use EntityManager's find() method to find a particular customer I get:
javax.servlet.ServletException: Exception [EclipseLink-43] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DescriptorException Exception Description: Missing class for indicator field value [2] of type [class java.lang.Integer]. Descriptor: RelationalDescriptor(com.technicalpioneers.cod.user.User --> [DatabaseTable(user)]) I don't understand why the Customer entity is not being found by JPA. I've checked the user table and the "type" column is there with correct numbers, and @DescriminatorValue is set correctly. It's almost like the annotations are being ignored?
Have done many clean rebuilds and redeploys too. Any help would be very much appreciated!