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.
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.
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 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.
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)