1

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!

6
  • I see you defined @Id private String username; in Customer bean, but not in Employee. I think you should keep it consistent. (if I remember correctly, it should be defined only in the parent) Commented Mar 23, 2015 at 13:56
  • any change that you placed your Customer class in wrong package? Or in the test branch of the code? No jpa errors in the logs upon start? Commented Mar 23, 2015 at 14:03
  • Thanks for the quick responses! The @Id field in customer is something I added as an experiment after the problem started, I've removed it again and no change. Commented Mar 23, 2015 at 14:11
  • The package is definitely correct, and in the correct branch. Nothing that stands out in the logs, except the exceptions from the errors I already mentioned. Thanks again for help! Commented Mar 23, 2015 at 14:13
  • You haven't defined TYPE variable. Try to do that. Commented Mar 23, 2015 at 14:30

1 Answer 1

2

I found this eventually. https://bugs.eclipse.org/bugs/show_bug.cgi?id=429992 It turns out EclipseLink will silently ignore entities with lambda expressions! Very annoying for it to not be at least mentioned in logs!

Thanks to everyone who took the time!

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.