Working with abstract / generic class in spring boot rest - crud api - java

im really struggling with my problem right now. I'm trying to solve this issue for quit long and maybe I get help here.
I do have a simple Spring Boot CRUD Project connected with my MySQL Database (localhost:3306) and everything works fine. The moment I modify my classes to a more common oop structure I get several errors and nothing works anymore.
Simple sketch of my structure:
Employee (abstract) class
Clerk (Entity) class
Admin (Entity) class
The employee class contains only one field (employee id "emp_id") and I want to spare me the retyping of the jpaRepo functions like finall and so on.
These are my abstract class:
package dev.cherry.emp.Employee.Util;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#MappedSuperclass
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
public abstract class Employee {
#Id
#Column(name = "emp_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long empId;
}
This is my Repository for the abstract class:
package dev.cherry.emp.Repository;
import dev.cherry.emp.Employee.Util.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
#NoRepositoryBean
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
This is the Service Class for my Abstract class. Generics are included to reuse finall for clerk and admin class:
package dev.cherry.emp.Service;
import dev.cherry.emp.Repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class EmployeeService<T> {
private final EmployeeRepository employeeRepo;
#Autowired
public EmployeeService(EmployeeRepository employeeRepo) {
this.employeeRepo = employeeRepo;
}
public List<T> allEmps() {
return (List<T>) employeeRepo.findAll();
}
}
And this is my Controller Class for the abstract class Employee:
package dev.cherry.emp.Controller;
import dev.cherry.emp.Service.EmployeeService;
import org.apache.coyote.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class EmployeeController<T> {
private final EmployeeService employeeService;
#Autowired
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
public ResponseEntity<List<T>> allEmps() {
List<T> allEmps = employeeService.allEmps();
return new ResponseEntity<>(allEmps, HttpStatus.OK);
}
}
I'm sorry for this boilerplate looking code. Last but not least my folderstructure, root is src/main/java/dev.cherry.emp/
.
├── Controller
│   ├── AdminController.java
│   ├── ClerkController.java
│   └── EmployeeController.java
├── EmpApplication.java
├── Employee
│   └── Util
│   ├── Employee.java
│   └── Gender.java
├── Model
│   ├── Admin.java
│   └── Clerk.java
├── Repository
│   ├── AdminRepository.java
│   ├── ClerkRepository.java
│   └── EmployeeRepository.java
└── Service
├── AdminService.java
├── ClerkService.java
└── EmployeeService.java
And this is the error from spring boot on console:
APPLICATION FAILED TO START
Description:
Parameter 0 of constructor in dev.cherry.emp.Service.EmployeeService required a single bean, but 2 were found:
- adminRepository: defined in dev.cherry.emp.Repository.AdminRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration
- clerkRepository: defined in dev.cherry.emp.Repository.ClerkRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration
Action:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed

somehow I could figure out how to solve my issue. Long story short, I´ll diplaying all my classes. Short disclaimer. ChatGPT helped me to solve the issue.
My Class/Project structure:
Path: src/main/java/dev/cherry/emp
Tree from folder “emp”:
.
├── EmpApplication.java
└── Employee
├── Controller
│   └── EmployeeController.java
├── Model
│   ├── Admin.java
│   └── Clerk.java
├── Repository
│   ├── AdminRepository.java
│   ├── ClerkRepository.java
│   └── EmployeeRepository.java
├── Service
│   └── EmployeeService.java
└── Util
├── Employee.java (abstract)
└── Gender.java (Enum)
Here are the classes 1-by-1. Sorry for the wall of text:
Abstract Class Employee
package dev.cherry.emp.Employee.Util;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#MappedSuperclass
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
public abstract class Employee {
#Id
#Column(name = "emp_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long empId;
}
Class Admin and Clerk (Sub-/Childclasses)
package dev.cherry.emp.Employee.Model;
import dev.cherry.emp.Employee.Util.Employee;
import dev.cherry.emp.Employee.Util.Gender;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Date;
#Entity
#Table(name = "employee")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Clerk extends Employee implements Serializable{
// Attributes
}
package dev.cherry.emp.Employee.Model;
import dev.cherry.emp.Employee.Util.Employee;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Date;
#Entity
#Table(name = "admin")
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#Component
public class Admin extends Employee implements Serializable {
// Attributes
}
My Repository Classes
package dev.cherry.emp.Employee.Repository;
import dev.cherry.emp.Employee.Util.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
#NoRepositoryBean
public interface EmployeeRepository<T extends Employee> extends JpaRepository<T, Long> {
}
package dev.cherry.emp.Employee.Repository;
import dev.cherry.emp.Employee.Model.Clerk;
import org.springframework.stereotype.Repository;
#Repository
public interface ClerkRepository extends EmployeeRepository<Clerk>{
}
package dev.cherry.emp.Employee.Repository;
import dev.cherry.emp.Employee.Model.Admin;
import org.springframework.stereotype.Repository;
#Repository
public interface AdminRepository extends EmployeeRepository<Admin> {
}
My Service Class
package dev.cherry.emp.Employee.Service;
import dev.cherry.emp.Employee.Util.Employee;
import dev.cherry.emp.Employee.Model.Admin;
import dev.cherry.emp.Employee.Model.Clerk;
import dev.cherry.emp.Employee.Repository.AdminRepository;
import dev.cherry.emp.Employee.Repository.ClerkRepository;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class EmployeeService {
private final AdminRepository adminRepo;
private final ClerkRepository clerkRepo;
public List<? extends Employee> getAllEmps(#NotNull String type) {
if (type.equals("Clerk")) {
return (List<Clerk>) clerkRepo.findAll();
} else if (type.equals("Admin")) {
return (List<Admin>) adminRepo.findAll();
} else throw new IllegalArgumentException("Class: " + type + " not found in project");
}
public Employee createEmployee(Employee employee) {
if (employee instanceof Clerk) {
return clerkRepo.save((Clerk) employee);
} else if (employee instanceof Admin) {
return adminRepo.save((Admin) employee);
} else {
throw new IllegalArgumentException("Illegal Employee subclass: " + employee.getClass().getSimpleName());
}
}
}
My Controller Class
package dev.cherry.emp.Employee.Controller;
import dev.cherry.emp.Employee.Util.Employee;
import dev.cherry.emp.Employee.Service.EmployeeService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
#RequestMapping("/employees")
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class EmployeeController {
private final EmployeeService employeeService;
#GetMapping(value = "type/{type}")
public ResponseEntity<List<? extends Employee>> getAllEmps(#PathVariable String type) {
List<? extends Employee> employees = employeeService.getAllEmps(type);
return new ResponseEntity<>(employees, HttpStatus.OK);
}
#PostMapping("/new")
public ResponseEntity<Employee> createEmployee(#RequestBody Employee employee) {
Employee savedEmployee = employeeService.createEmployee(employee);
return new ResponseEntity<>(savedEmployee, HttpStatus.CREATED);
}
}
My Code works actually and on postman I could test my requests. Please feel free to show me a better way if you think it could be done smarter or with less lines of code.
Thank your very much for your support.

Related

Getting Error ( Field xyzRepository (that extends JPA Repository) in abcService class required a bean of xyzRepository that could not be found

sipRepository.java
import sip.sipDemo.model.mysql.SipEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Component
#Repository
public interface SipRepository extends JpaRepository<SipEntity,Integer>{
}
SipEntity.java
package sip.sipDemo.model.mysql;
import javax.persistence.*;
import java.sql.Date;
import java.sql.Timestamp;
#Entity
#Table(name = "sip_table")
public class SipEntity {
public SipEntity() {}
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "userid")
private int UserId;
#Column(name = "folioNo")
private String FolioNo;
#Column(name = "amount")
private double Amount;
#Column(name = "isin")
private String IsIn;
#Column(name = "schemename")
private String SchemeName;
#Column(name = "nextSipDate")
private Date NextSipDate;
#Column(name = "status")
private String status;
}
SipController.java
package sip.sipDemo.Controller;
import sip.sipDemo.Service.SipService;
import sip.sipDemo.model.mysql.SipEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.Optional;
#Controller
public class SipController {
#Autowired
private SipService sipservice;
#ResponseBody
#GetMapping(value="/")
public String home()
{
return "Hello";
}
#ResponseBody
#GetMapping(value = "/getAllEntities")
public List<SipEntity> getAllEntities()
{
List<SipEntity> newList = sipservice.getAllEntities();
return newList;
}
}
SipService.java
package sip.sipDemo.Service;
import sip.sipDemo.model.mysql.SipEntity;
import sip.sipDemo.repository.mysql.SipRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
#Service
public class SipService {
#Autowired
private SipRepository sipRepository;
public List<SipEntity> getAllEntities()
{
List<SipEntity> sipList = sipRepository.findAll();
return sipList;
}
}
sipDemoApplication.java (main file)
package sip.sipDemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#EnableAutoConfiguration
#ComponentScan(basePackages = {"sip.sipDemo"})
#SpringBootApplication
public class SipDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SipDemoApplication.class, args);
}
}
The Error Message looks like
: APPLICATION FAILED TO START
***************************
Description:
Field sipRepository in sip.sipDemo.Service.SipService required a bean of type 'sip.sipDemo.repository.mysql.SipRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'sip.sipDemo.repository.mysql.SipRepository' in your configuration.
> Task :SipDemoApplication.main() FAILED
application.properties
spring.datasource.url= jdbc:mysql://localhost:3306/sys?autoReconnect=true&zeroDateTimeBehavior=convertToNull
spring.datasource.username=root
spring.datasource.password=******** (actual password)
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.org.hibernate.envers.audit_table_suffix=_AUDIT_LOG
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
I have used mysql database.
The main class is in the outer most layer and the packages are well structured.
│   │   └── sipDemo
│   │   ├── Controller
│   │   │   └── SipController.java
│   │   ├── model
│   │   │   └── mysql
│   │   │   └── SipEntity.java
│   │   ├── repository
│   │   │   └── mysql
│   │   │   └── SipRepository.java
│   │   ├── Service
│   │   │   └── SipService.java
│   │   └── SipDemoApplication.java
│   └── resources
│   ├── application.properties
│   ├── static
│   └── templates
If I remove #Autowire for the sipRepository object in sipService, the controller endpoints for sipRepository do not work but the rest is working fine.
Please provide the possible source of error.

Junit Testing #getmappings with h2 in memory database

I'm having issues unit testing the DbRequest controller. I have one unit test working, but I'm unable to achieve a unit test for the DBRequest controller GET mappings which does a database lookup using hibernate. I' have an H2 in memory database created for the junit tests.
I've tried a variety of different setups, and nothing seems to work correctly.
Edited the below, I'm getting a NullPointer,
java.lang.NullPointerException
at com.lmig.informaticaservice.api.DBcontroltest.saveTest(DBcontroltest.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Here is the edited test.
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class DBcontroltest {
#Autowired
DbRequest dbRequest;
#Autowired
ConnectionRequestRepository connectionRequestRepository;
private MockMvc mockMvc;
// #Autowired
//private TestEntityManager entityManager;
#Test
public void saveTest() throws Exception {
ConnectionRequest connectionRequest = new ConnectionRequest((long) 1, "test");
connectionRequestRepository.save(connectionRequest);
System.out.println(connectionRequestRepository.findAll().toString());
mockMvc.perform(get("/api/selectDB/{connectionId}" ,1))
.andExpect(status().isOk());
}
}
Typical JPA repository
package com.test.models;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ConnectionRequestRepository extends JpaRepository<ConnectionRequest, Long> {
}
Here is my controller.
package com.test.api;
import com.models.ConnectionRequest;
import com.test.models.ConnectionRequestRepository;
import java.util.List;
import javax.validation.Valid;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#Data
#RestController
#RequestMapping("/api/")
public class DbRequest {
#Autowired
private ConnectionRequestRepository connectionRequestRepository;
private ConnectionRequest connectionRequest;
#GetMapping("/selectDB")
public List<ConnectionRequest> getAllRequests() {
return connectionRequestRepository.findAll();
}
#GetMapping("/selectDB/{connectionId}")
public ResponseEntity<ConnectionRequest> getRequestById(#PathVariable("connectionId") Long connectionId) throws Exception {
ConnectionRequest connectionRequest = connectionRequestRepository.findById(connectionId)
.orElseThrow(() -> new Exception("Connection Request " + connectionId + " not found"));
return ResponseEntity.ok().body(connectionRequest);
}
}
Here is the model for the database.
package com.testing.models;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
#Data
#Entity
#Table(name = "connrequest", schema = "testschema")
#AllArgsConstructor
#NoArgsConstructor
#EntityListeners(AuditingEntityListener.class)
public class ConnectionRequest {
#Id
#Column(name = "connection_id", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long connectionId;
#Column(name = "requestor", nullable = false)
private String requestor;
}
It looks like the on of the annotations on the PK of ConnectionRequest is the problem.
The annotation #GeneratedValue tells JPA that it needs to determine the value, so any provided value for the ID will be actively discarded. From the docs
Indicates that the persistence provider must assign primary keys for the entity using a database identity column.
To fix this try either removing that annotation, so then you must always provide an ID, or alternatively, after saving the entity in your test, get the ID that is assigned and call connectionRequestRepository.getOne() with that ID.

Spring Data REST call to `save` receiving object with null variable

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.

Greendao can't generate join dao import (ToMany relation)

Greendao not generating import of ToMany joiner dao. How can I do this?
I'm creating Book and BookStore, trying save list of books in book store by Custom joiner. After build trying generated Joiner JoinBookStoreWithBookDao not importing in BookStoreDao but exists.
Sources
Book.java
package com.example.valery.stackoverflowsample.dao;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Generated;
#Entity
public class Book {
#Id
private long id;
public Book() {
}
}
BookStore.java
package com.example.valery.stackoverflowsample.dao;
import com.example.valery.stackoverflowsample.dao.joiner.DaoSession;
import com.example.valery.stackoverflowsample.dao.joiner.JoinBookStoreWithBook;
import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.JoinEntity;
import org.greenrobot.greendao.annotation.ToMany;
import java.util.ArrayList;
import java.util.List;
#Entity
public class BookStore {
#Id
private long id;
#ToMany
#JoinEntity(
entity = JoinBookStoreWithBook.class,
sourceProperty = "bookStoreId",
targetProperty = "bookId"
)
private List<Book> mBooks;
}
JoinBookStoreWithBook.java
package com.example.valery.stackoverflowsample.dao.joiner;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Generated;
#Entity
public class JoinBookStoreWithBook {
#Id
private long id;
private long bookId;
private long bookStoreId;
}
I found reason. Joiner should be inside of package for "parent", he can't be in another package.

JAXB Annotated Child Class Using Super Classes XMLRootElement Name Value

I'm using JAXB 2.1 and I'm confused by the XML output I'm seeing. Below I have two child classes that extend the same parent. When marshalled and viewed as XML in a browser using REST, Child class 1 (GeoLocationDecodedPayload) always has a root element of geoLocationDecodedPayload as expected. For some reason child class 2 (AltitudeDecodedPayload) doesn't have altitudeDecodedPayload as its root element which is unexpected as its specified in its #XMLRootElement annotation. The XML output shows the super class (GeoPayload) #XMLRootElement of geoPayload. Any ideas why these two class act differently?
child class 1:
package com.api.model.vo.decoder;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import com.api.util.decoder.DecoderConstants;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "geoLocationDecodedPayload")
public class GeoLocationDecodedPayload extends GeoPayload implements Serializable {
public GeoLocationDecodedPayload() {}
}
child class 2:
package com.api.model.vo.decoder;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import com.api.util.decoder.DecoderConstants;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "altitudeDecodedPayload")
public class AltitudeDecodedPayload extends GeoPayload implements Serializable {
public AltitudeDecodedPayload() {}
}
parent class:
package com.api.model.vo.decoder;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "geoPayload")
public class GeoPayload {
public GeoPayload() {}
}
I had forgot to include AltitudeDecodedPayload.class in the below. This fixed my issue.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="payloadResponse")
public class PayloadResponse extends AbstractResponse{
#XmlElementWrapper(name="decodedPayloads")
#XmlElementRefs({
#XmlElementRef(type=GeoPayload.class),
#XmlElementRef(type=GeoLocationDecodedPayload .class),
#XmlElementRef(type=AltitudeDecodedPayload .class)

Categories