I've just read about CRUD system of PlayFramework and decided to write simple example, just two classes Group and User and decided that a lot of users can be in one group but one user can be just in one group. So, I've used for it ManyToOne and OneToMany anotations, please take a look to the code below:
package models;
import play.db.jpa.Model;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
/**
* #author sergiizagriichuk
*/
#Entity
public class User extends Model {
public String firstName;
public String lastName;
#ManyToOne
public Group group;
#Override
public String toString() {
return firstName;
}
}
and
package models;
import play.db.jpa.Model;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import java.util.List;
/**
* #author sergiizagriichuk
*/
#Entity
public class Group extends Model {
public String groupName;
public String groupDescription;
#OneToMany
#OrderBy("firstName desc")
public List<User> users;
}
For sorting I've tried to use OrderBy annotation, and as result nothing :(, I have list of users in additional sorting mode, but I wanna order by firstName, Could someone explain me how to sort list using controller for friendly using in CRUD mode ?
Thanks.
did you try adding the mappedBy attribute in your users list?
#OneToMany(mappedBy="group")
Related
I have created a pretty small and simple Spring Boot app using the Oracle database and some JPA queries.
This is the code snippet which is not returning data, which is actually exists in database.
letterRecipientNonOas = letterRecipientNonOasRepository
.findById(Long.valueOf(letterRecipientDTO.getNonOas().getId()))
.orElseThrow(() -> new EntityNotFoundException(LetterRecipientNonOas.class,
Constant.MESSAGE_ENTITY_NOT_FOUND));
here findById is returning empty result set.
this is my repository
package com.care.document.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.care.document.model.LetterRecipientNonOas;
/**
* The Interface LetterRecipientNonOasRepository.
*/
#Repository
public interface LetterRecipientNonOasRepository extends PagingAndSortingRepository<LetterRecipientNonOas, Long> {
Optional<LetterRecipientNonOas> findByLetterId(Long id);
Optional<LetterRecipientNonOas> findByTitleIgnoreCase(String title);
List<LetterRecipientNonOas> findByTitleContainingIgnoreCase(String title);
List<LetterRecipientNonOas> findAllByTitleIgnoreCaseAndIdNot(String title, Long recipientId);
List<LetterRecipientNonOas> findAllByIdAndLetterId(long id, long letterId);
}
and this is my model class:
package com.care.document.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import org.springframework.lang.Nullable;
import com.care.admin.model.BaseEntity;
import com.care.admin.util.CommonUtil;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#FieldDefaults(level = AccessLevel.PRIVATE)
#Entity
#Table(name = "letter_recipient_non_oas")
public class LetterRecipientNonOas extends BaseEntity implements Serializable {
#Id
Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "letter_id")
Letter letter;
Integer recipientType; // Action/Info
//byte recipientSubType; // Internal/External/NonOAS
byte recipientCategory; //Internal/External
int orderNo;
String title;
#Nullable
String remarks;
String address;
#PrePersist
private void prePersist() {
this.id = CommonUtil.generateID(this.atRegion);
}
}
I tested, tried different ways but of no use.
There are a couple of scenarios how one might get this impression:
You are looking at the wrong database.
The data isn't there yet when you try to load it, but is when you check.
JPAs caches are known to create such scenarios rather efficiently.
The data looks a little different than you think. This could be caused by invisible or easy to miss content like spaces or even control characters.
You check the database within the transaction that created the data or with a session that allows dirty reads and the insert that created the data wasn't committed yet.
I'm continuing the development of a system that uses the React JavaScript library (and related stuff) on the front end and Spring Data REST, Hibernate, PostgreSQL and related stuff on the back end.
This system will be used by people who may own one or more companies and their clients. This means that most/all model objects will have a reference to the Company(ies) that they belong to. Also, company owners will have a few Employees that will have higher level access on this system (or these will be the owners themselves).
I need to implement a functionality where, when a company is inserted in the database, an employee is inserted as well. Also, if one fails, both must fail. Because of how the model was set up, I'm sending an Employee object to be saved, and, within it, the new Company, like this (using Axios):
employee: {
// ...,
company: {
// ....
}
}
Problem is, when the save method is called in the back end, the Company member of the Employee object is null. I've tried a few things, like messing with the relationship, adding an Employee list to the Company object, passing the Company object separately, but nothing worked.
What else could I try? Here are some classes:
Record.java
package xxx.model.common;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotNull;
import lombok.Data;
#Data
#MappedSuperclass
public abstract class Record {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
#NotNull
#Column(name = "deleted")
protected Boolean isDeleted = false;
#NotNull
#Column(name = "enabled")
protected Boolean isEnabled = true;
}
Company.java
package xxx.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import xxx.common.Record;
// ...
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#Entity
#Table(name="company")
#AttributeOverrides( { #AttributeOverride(name = "id", column = #Column(name = "id_company")) } )
public class Company extends Record {
/*
* ...
*/
// Necessary for Hibernate
protected Company() {}
public Company(/* ... */) {
/*
* ...
*/
}
}
Registry.java
package xxx.model.common;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#MappedSuperclass
public abstract class Registry extends Record {
#NotBlank
#Column(name = "code", length = 15)
protected String code;
#NotBlank
#Column(name = "name", length = 40)
protected String name;
}
RegistrySingleCompany.java
package xxx.model.common;
import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import com.fasterxml.jackson.annotation.JsonBackReference;
import xxx.model.Company;
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#MappedSuperclass
public class RegistrySingleCompany extends Registry {
#ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE }, optional= false)
#JoinColumn(name="id_company")
protected Company company;
}
Employee.java
package xxx.model;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import xxx.model.common.RegistrySingleCompany;
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#Entity
#Table(name="employee")
#AttributeOverrides( { #AttributeOverride(name = "id", column = #Column(name = "id_employee")) } )
public class Employee extends RegistrySingleCompany {
/*
* ...
*/
// Necessary for Hibernate
protected Employee() {}
}
EmployeeRepositoryCustom.java
package xxx.repository.custom;
import org.springframework.data.repository.query.Param;
import xxx.model.Employee;
public interface EmployeeRepositoryCustom {
<S extends Employee> S save(S entity);
}
EmployeeRepositoryCustomImpl.java
package xxx.repository.custom;
import javax.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestBody;
import xxx.model.Employee;
public class EmployeeRepositoryCustomImpl implements EmployeeRepositoryCustom {
#Override
#Transactional
public <S extends Employee> S save(#RequestBody S entity) {
/*
* ...
*/
return entity;
}
}
EmployeeProjection.java
package xxx.model.projection;
import org.springframework.data.rest.core.config.Projection;
import xxx.model.Employee;
#Projection(name = "employeeProjection", types = { Employee.class })
public interface EmployeeProjection {
Boolean getIsDeleted();
Boolean getIsEnabled();
String getCode();
String getName();
/*
* ...
*/
}
EmployeeRepository.java
package xxx.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import xxx.model.Employee;
import xxx.model.projection.EmployeeProjection;
import xxx.repository.custom.EmployeeRepositoryCustom;
#RepositoryRestResource(collectionResourceRel = "employee", path = "employees", excerptProjection = EmployeeProjection.class)
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>, EmployeeRepositoryCustom {}
Thanks in advance.
Edit: added missing classes.
As mentioned before, one of the things I tried was to add an Employee list inside the Company object, which implies using Company's repository instead of the Employee's one to save both objects, but the other object was also arriving null. However, my colleague found out that, by using exported = false inside #RepositoryRestResource(), the value would be received correctly.
That would screw other things up, so we found the following temporary solution:
Create an exported = false repository (EmployeeWrapper) for the sole purpose of delivering the necessary Employee data to construct a new one inside save.
Instead of adding an Employee list inside Company, add an EmployeeWrapper list.
EmployeeWrapper also references Company.
We're still working on a more correct approach.
Update: a more correct approach:
My colleague also found out that, by adding a #Transient Employee list to Company, it's possible to receive the correctly filled out Employee object to save it. I don't know if it works at the repository since, due to other constraints, we moved to use a #RepositoryRestController and are receiving the Company as #RequestBody org.springframework.hateoas.Resource<Company> resource.
We still want to find a better solution, because an Employee list inside Company wasn't planned in our model and, worse yet, we're needing to use list of other things for other methods.
Update: an even better approach:
Experimenting a little more, we created a POJO containing the entities that we needed and received that in the controller, same way as before. Works well.
We're still not satisfied, though. Ideally, we want to receive the Employee to be saved, with the Company to be saved inside it, and save them both at once.
What I want to do is to get the total count in each month. So I have come up
with these queries. I followed the documentation on Spring Boot JPA
repository using #Query. But when I run my app, it goes Application
Startup Failed. I dont know if my query is right.
Here is my #Query
#Query("SELECT MONTH(date_completed) FROM shipment WHERE YEAR(date_created)=?1 GROUP BY MONTH(date_completed)=?1")
public List<Shipment> findByDate_completed(String date);
#Query("SELECT COUNT(*) FROM shipment WHERE YEAR(date_created)=?1 GROUP BY MONTH(date_completed)=?1")
public List<Shipment> countByDate_completed(String date);
Shipment.java
package com.pahrsek.smartfleet.model;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* Delivery of goods
* #author JRDomingo
*
*/
#Entity
#Table(name="shipment")
public class Shipment {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long id;
#Column(name="booking_number",unique=true)
public String bookingNumber;
#Column(name="wb_number")
public String wbNumber;
#ManyToOne
#JoinColumn(name="vehicle_id", referencedColumnName="id")
public Vehicle vehicle;
#ManyToOne
#JoinColumn(name="customer_id", referencedColumnName="id")
public Customer customer;
public String origin;
public String depot;
#ManyToOne
#JoinColumn(name="vendor_id", referencedColumnName="id")
public Vendor vendor;
public String type;
#Column(name="commodity_type")
public String commodityType;
#Column(name="truck_type")
public String truckType;
#Enumerated(EnumType.STRING)
public Status status;
#Column(name="delivery_date")
public Date deliveryDate;
#Column(name="fuel_po")
public String fuelPo;
#Column(name="client_ref_no")
public String clientReferenceNumber;
public String remarks;
#ManyToOne
#JoinColumn(name="driver_id",referencedColumnName="id")
public Personnel driver;
#ManyToOne
#JoinColumn(name="helper1_id",referencedColumnName="id")
public Personnel helper1;
#ManyToOne
#JoinColumn(name="helper2_id",referencedColumnName="id")
public Personnel helper2;
public enum Status{
New, Dispatched, Delivered, Completed, Cancelled
}
/******
* ACTUAL DATES IMPLEMENTED
******/
#Column(name="date_created")
public Date dateCreated;
#Column(name="date_dispatched")
public Date dateDispatched;
#Column(name="date_completed")
public Date dateCompleted;
#Column(name="date_cancelled")
public Date dateCancelled;
#Column(name="date_received")
public Date dateReceived;
#Column(name="farthest_destination")
public String farthestDestination;
#Column(name="client_rate")
public Double clientRate;
#Column(name="is_sub_con")
public boolean isSubCon;
#Column(name="sub_con_rate")
public Double subConRate;
#Column(name="fuel")
public Double fuel;
#Column(name="fuel_amount")
public Double fuelAmount;
#Column(name="route_code")
public String routeCode;
#ManyToOne
#JsonIgnore
#JoinColumn(name="dispatched_odometer_id",referencedColumnName="id")
public RegularOdometerUsage dispatchedOdometer;
#ManyToOne
#JsonIgnore
#JoinColumn(name="delivered_odometer_id",referencedColumnName="id")
public RegularOdometerUsage deliveredOdometer;
#ManyToOne
#JsonIgnore
#JoinColumn(name="completed_odometer_id",referencedColumnName="id")
public RegularOdometerUsage completedOdometer;
/**
* index 0 = Driver , index 1 = Helper1, index 2 = Helper2
*/
#JsonIgnore
#OneToMany(mappedBy="shipment",targetEntity=PersonnelRate.class)
public List<PersonnelRate> personnelRates = new ArrayList<PersonnelRate>();
#JsonIgnore
#ManyToOne
#JoinColumn(name="company_id", referencedColumnName="id")
public Company company;
#JsonIgnore
#ManyToOne
#JoinColumn(name="prepared_user_id", referencedColumnName="id")
public User preparedBy;
#JsonIgnore
#ManyToOne
#JoinColumn(name="customer_invoice", referencedColumnName="id")
public CustomerInvoice customerInvoice;
#JsonIgnore
#ManyToOne
#JoinColumn(name="trucker_settlement", referencedColumnName="id")
public TruckerSettlement truckerSettlement;
}
What I want to achieve is to get the count of shipments with the status 'Completed' in each month based on the current year.
If you need to get a custom info from your db, for example, a month number and count of related records you cannot return a whole entity from the query method. You have to use a projection. For example:
public interface MonthAndCount {
Integer getMonth();
Long getCount();
}
#Query("select month(s.dateCompleted) as month, count(s.id) as count from Shipment s where year(s.dateCompleted) = ?1 group by month(s.dateCompleted)")
List<MonthAndCount> getMonthAndCount(int year);
Note: it's important to use aliases (as month or as count) here to make the framework know how to fill you projection.
Test:
#Test
public void getMonthAndCount() {
List<MonthAndCount> monthAndCount = repo.getMonthAndCount(2017);
assertThat(monthAndCount).hasSize(4);
monthAndCount.forEach(System.out::println);
}
Result:
{month=1, count=1}
{month=2, count=1}
{month=3, count=1}
{month=12, count=2}
If you do a select * operation in your hql query in that case hibernate can map your table data to your entity class but if you select custom fields by performing some operation those fields you need to create projection classes to map that data.
But if you do not want to create any class just to fetch data from query in that case you can use an Object[] instead of your entity class.
So your methods will simply look this
#Query("SELECT MONTH(date_completed), COUNT(*) FROM shipment WHERE YEAR(date_created)=?1 GROUP BY MONTH(date_completed)=?1")
public List<Object[]> findByDate_completed(String date);
First let's say we have two tables. One table is an Employee table with the following columns:
EMPLOYEE:
------------------------
emp_id (int, primary key)
emp_name (varchar(125))
emp_dept (foreign key)
emp_intro (text)
The other table is a Department table with the following columns:
DEPARTMENT:
-----------
dept_id (int, primary key)
dept_label (varchar(25))
Here is a sample of the table's values
DEPARTMENT:
------------------------
dept_id | dept_label
------------------------
1 | Sales
------------------------
2 | Technology
------------------------
3 | Finance
In order to return the employee's info with a status label, we need to either perform a JOIN:
SELECT e, d.dept_label FROM employees JOIN department d ON d.dept_id = e.emp_dept
or a multi-table select:
SELECT e.emp_id, e.emp_name, d.dept_label, e.emp_intro FROM employees e, department d WHERE e.emp_dept = d.dept_id
However, when using JPA/Hibernate, we need to create two classes:
Employee.java
package com.example.entities;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "employees")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "emp_id")
private long emp_id;
#Column(name = "emp_name")
private String emp_name;
#Column(name = "emp_dept")
private Integer emp_dept;
#Column(name = "emp_intro")
private String emp_intro;
public long getEmp_id() {
return emp_id;
}
public void setEmp_id(long emp_id) {
this.emp_id = emp_id;
}
public String getEmp_name() {
return emp_name;
}
public void setEmp_name(String emp_name) {
this.emp_name = emp_name;
}
public Integer getEmp_dept() {
return emp_dept;
}
public void setEmp_dept(Integer emp_dept) {
this.emp_dept = emp_dept;
}
public String getEmp_intro() {
return emp_intro;
}
public void setEmp_intro(String emp_intro) {
this.emp_intro = emp_intro;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
Department.java
package com.example.entities;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "departments")
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "dept_id")
private long dept_id;
#Column(name = "dept_label")
private String dept_label;
public long getDept_id() {
return dept_id;
}
public void setDept_id(long dept_id) {
this.dept_id = dept_id;
}
public String getDept_label() {
return dept_label;
}
public void setDept_label(String dept_label) {
this.dept_label = dept_label;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
Then, there is the repository (DAO):
EmployeeRepository
package com.example.repository;
import.java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.example.entities.Employee;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
#Query("select e, d.dept_label FROM Employee e JOIN Department d ON "
+ "d.dept_id = e.emp_id")
public List<Employee> return getEmployees();
}
and lastly, the Java controller that binds the classed query to an endpoint of the application:
EmployeeController.java
package com.example.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.entities.Department;
import com.example.entities.Employee;
import com.example.repository.EmployeeRepository;
#Controller
public class EmployeeController {
#Autowired
EmployeeRepository er;
#RequestMapping(value = "/getEmployees")
public #ResponseBody List<Employee> getEmployees() {
return er.getEmployees();
}
}
I have already tested this entire structure with only retrieving rows inside of the Employee table (i.e. #Query("SELECT e FROM Employee e") ) and everything returns as is.
MY MAIN ISSUE is how does one return a JOIN QUERY while the query is inside of a specific class (table), being Employee, if I require contents inside of Department?
I've already tried #JoinColumn annotations and that didn't work as well (perhaps I did it wrong).
Any ideas? Thanks.
You dont have to use raw joins to do that, just use proper relation mapping. Relation between Employee and Departament sounds like #ManyToOne or #ManyToMany.
You will be able to eg employee.getDepartament() or query by employee.departament.name=:name
http://www.objectdb.com/api/java/jpa/ManyToMany
You can even map bidirectional relations so you will be able to get deparament from employee, as well as all employees from given deparaments
PS. #JoinColumn is used to delare DB columnt used for joins it it is different then created by selected named strategies (usualy entityname_id). Actual relation mapping is done by declaring #OneToOne #OneToMany #ManyToMany and those can but doesn't have to be used with #JoinColumn. It is strict JPA question.
Here you have complete documentation of JPA 2.1 specification
It describes in details how to declare relations as well as #MappedSuperclass, inheritance strategies and all other usefull stuff.
My Class heirarchy is as follows
School - contains list of Employees - which contains list of qualifications
Employees is an Embedded list in School. I can persist a School with it's employees no problem. Now when I add the list of qualifications to an employee as an embedded field I get the following error
You cannot nest multiple #Embedded arrays or collections
The objectify documentation seems to indicate I should be able to do this provided the objects are serializable which they are. Am I missing something? If this is the way it works is there a way around it?
Update:
School Class
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Embedded;
import javax.persistence.Id;
import com.googlecode.objectify.annotation.Entity;
#Entity
#SuppressWarnings("serial")
public class School implements Serializable
{
#Id
private String title;
#Embedded
private List<Employee> employees = new ArrayList<Employee>();
public School ()
{
}
public School (String title)
{
this.title = title;
}
public void addEmployee( Employee employee )
{
this.employees.add(employee);
}
}
Employee Class
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Embedded;
import javax.persistence.Id;
import com.googlecode.objectify.annotation.Entity;
#Entity
#SuppressWarnings("serial")
public class Employee implements Serializable
{
#Id
private String title;
#Embedded
private List<String> qualifications = new ArrayList<String>();
public Employee ()
{
}
public Employee (String title)
{
this.title = title;
}
public void addQualification( String qualification )
{
this.qualifications.add(qualification);
}
}
Caused by: java.lang.IllegalStateException: You cannot nest multiple #Embedded arrays or collections. A second was found at private java.util.List com.app.nquizitive.shared.Employee.qualifications
at com.googlecode.objectify.impl.save.EmbeddedMultivalueFieldSaver.<init>(EmbeddedMultivalueFieldSaver.java:36)
at com.googlecode.objectify.impl.save.EmbeddedCollectionFieldSaver.<init>(EmbeddedCollectionFieldSaver.java:21)
at com.googlecode.objectify.impl.save.ClassSaver.<init>(ClassSaver.java:64)
at com.googlecode.objectify.impl.save.EmbeddedMultivalueFieldSaver.<init>(EmbeddedMultivalueFieldSaver.java:43)
at com.googlecode.objectify.impl.save.EmbeddedCollectionFieldSaver.<init>(EmbeddedCollectionFieldSaver.java:21)
at com.googlecode.objectify.impl.save.ClassSaver.<init>(ClassSaver.java:64)
at com.googlecode.objectify.impl.save.ClassSaver.<init>(ClassSaver.java:29)
at com.googlecode.objectify.impl.Transmog.<init>(Transmog.java:322)
at com.googlecode.objectify.impl.ConcreteEntityMetadata.<init>(ConcreteEntityMetadata.java:75)
at com.googlecode.objectify.impl.Registrar.register(Registrar.java:69)
at com.googlecode.objectify.ObjectifyFactory.register(ObjectifyFactory.java:209)
at com.googlecode.objectify.ObjectifyService.register(ObjectifyService.java:38)
at com.app.nquizitive.server.dao.SchoolDao.<clinit>(SchoolDao.java:12)
There are two different annotations:
#Embed (#Embedded in ofy3)
#Serialize (#Serialized in ofy3)
If you want something to serialize, use the second. If you want something embedded, use the first. You can't nest #Embed(ded) lists, but you can put a #Serialize(d) list inside an embedded list.
Which of the classes above are annotated with #Entity? It sounds like School is a datastore entity, while Employees are not (i.e. they are just serialized into School) and qualifications are not (i.e. they are just serialized into Employees).
The Objectify annotation of #Embedded isn't needed/relevant/allowed, in a non-Entity class.