Spring Boot entity not being recognized during build - spring-boot

I'm running into this error when I mvn clean install my Spring Boot application:
Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.fitzgerald.floorplanmanager.data.Users
I've tried adding #EntityScan to my Application class, with and without a defined pathname, but to no avail.
I also have two other Entities aside from Users. I'm not sure if they are being recognized or if Users was just the first entity that the compiler encountered (my gut says the latter), but I'm not seeing them in the stacktrace.
Here is what my Application class looks like:
#EntityScan
#SpringBootApplication
public class FloorplanmanagerApplication {
public static void main(String[] args) {
SpringApplication.run(FloorplanmanagerApplication.class, args);
}
}
This is my UsersRepository:
#Transactional
public interface UsersRepository extends CrudRepository<Users, Long> {
}
UsersService:
#Service
public class UsersServiceImpl implements UsersService {
#Autowired
private UsersRepository usersRepository;
#Override
public Users saveUsers(Users users) {
return usersRepository.save(users);
}
}
and finally Users:
#Entity
#Data
#Table(name = "users")
#NoArgsConstructor
public class Users {
#Id
#Column
private long id;
#Column
private String userName;
#Column
private String password;
}
My file structure looks like this
Also, my data.sql file in com.fitzgerald.floorplanmanager.resources looks like this:
DROP TABLE IF EXISTS users;
CREATE TABLE users (
id INT PRIMARY KEY,
USER_NAME VARCHAR(250) NOT NULL,
PASSWORD VARCHAR(250) NOT NULL
);
// two more tables are created...
I've tried using the folder name entity instead of data, adding #EntityScan("com.fitzgerald.floorplanmanager.data") to the Application class, adding #EnableJpaRepositories, #ComponentScan, and messing with the file structure but I just can't get it to work.
Thanks!

Related

How to configure integration test for the new Spring for GrapQL

I am currently learning Spring for GraphQL and am working on an application to do some basic CRUD operations, using the GraphQL API using Spring-boot with JPA and an H2 in-memory database for testing. Now I am trying to write some integration tests using the GraphlQlTester interface. There is a possibility to test importing just the service layer, storing the data in a collection at this layer. Now I want to be able to access the repository layer too to temporarily store and manipulate the test data in the h2 database. I have been researching the documentation online, but unfortunately, I have not found any possible way to approach this particular issue. Perhaps you may have an idea?
Entity Class
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Table(name = "address")
public class Address {
#Id
#GeneratedValue(strategy = IDENTITY)
private long id;
private String street;
private String city;
private int postCode;
}
Controller Class (just the first method)
#Controller
#RequiredArgsConstructor
public class AddressController {
private final AddressService addressService;
private static final String ERROR_MESSAGE = "Address with id %d not found";
#QueryMapping
List<Address> findAllAddresses() {
return addressService.findAll();
}
Service Class (just the first method)
#Service
#RequiredArgsConstructor
public class AddressService {
private final String ERROR_MESSAGE = "Address with id %d not found";
private final AddressRepository addressRepository;
private final ContactInformationRepository contactInformationRepository;
public List<Address> findAll() {
return addressRepository.findAll();
}
Repository
public interface AddressRepository extends JpaRepository<Address, Long> {
}
Integration Test class
import com.soscarlos.dropit.entity.Address;
import com.soscarlos.dropit.repository.AddressRepository;
import com.soscarlos.dropit.service.AddressService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest;
import org.springframework.context.annotation.Import;
import org.springframework.graphql.test.tester.GraphQlTester;
#GraphQlTest(AddressController.class)
#Import({AddressService.class, AddressRepository.class})
class AddressControllerTest {
#Autowired
GraphQlTester tester;
#Autowired
AddressService addressService;
#Autowired
AddressRepository addressRepository;
#Test
void findAllAddresses() {
// language=GraphQL
String document = """
query {
findAllAddresses {
id
street
city
postCode
}
}
""";
tester.document(document)
.execute()
.path("findAllAddresses")
.entityList(Address.class)
.hasSize(1);
}
I cannot load the application context because of this error basically
"Error creating bean with name 'com.soscarlos.dropit.repository.AddressRepository': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.soscarlos.dropit.repository.AddressRepository]: Specified class is an interface"

CascadeType Merge is ignored when Persist is set

Hy all
I'm having a hard time solving the following spring jpa problem.
Let's say I have the following simple data model (two entities with a one direction relationship between the two)
#Accessors(chain = true) #Getter #Setter #NoArgsConstructor #AllArgsConstructor
#MappedSuperclass
public class AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Version
private Long version;
}
#Accessors(chain = true) #Getter #Setter #NoArgsConstructor #AllArgsConstructor
#Entity
public class Entity1 extends AbstractEntity {
private String name;
}
#Accessors(chain = true) #Getter #Setter #NoArgsConstructor #AllArgsConstructor
#Entity
public class Entity2 extends AbstractEntity {
private String name;
#ManyToOne(cascade={ALL})
private Entity1 entity1;
}
and the following plumbing to store them
public interface Entity1Dao extends JpaRepository< Entity1, Long >, JpaSpecificationExecutor< Entity1 > {
Entity1 findByName(String name);
}
public interface Entity2Dao extends JpaRepository< Entity2, Long >, JpaSpecificationExecutor< Entity2 > {
Entity2 findByName(String name);
}
#Service
public class StoreService {
#Autowired
Entity1Dao dao1;
#Autowired
Entity2Dao dao2;
#Transactional
public Entity1 saveEntity1(Entity1 e) {
return dao1.save(e);
}
#Transactional
public Entity2 saveEntity2(Entity2 e) {
return dao2.save(e);
}
public Entity1 loadEntity1ByName(String name) {
return dao1.findByName(name);
}
}
#SpringBootApplication
public class JpaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(JpaDemoApplication.class, args);
}
}
And the following test
#SpringBootTest
#TestMethodOrder(value = MethodOrderer.OrderAnnotation.class)
class JpaDemoApplicationTests {
#Autowired
StoreService store;
#Test
#Order(1)
void contextLoads() {
assertThat(store).isNotNull();
}
#Test
#Order(2)
void insertEntity1() {
store.saveEntity1(new Entity1("test entity1"));
Entity1 saved = store.loadEntity1ByName("test entity1");
assertThat(saved).isNotNull().hasNoNullFieldsOrProperties();
}
#Test
#Order(4)
void insertEntity2WithNewEntity1() {
store.saveEntity2(new Entity2("with new entity1", new Entity1("new entity1")));
}
#Test
#Order(5)
void insertEntity2WithExistingEntity1() {
store.saveEntity2(new Entity2("with saved entity1", store.loadEntity1ByName("test entity1")));
}
}
the last test (i.e. insertEntity2WithExistingEntity1) fails with the following exception
org.hibernate.PersistentObjectException: detached entity passed to
persist: com.example.jpaDemo.Entity1
If I change the CascadeType in Entity2 to MERGE, that test passes but the insertEntity2WithNewEntity1 fails with the following exception
org.hibernate.TransientPropertyValueException: object references an
unsaved transient instance - save the transient instance before
flushing : com.example.jpaDemo.Entity2.entity1 ->
com.example.jpaDemo.Entity1
I've tried multiple combination of cascading types bute it seems that as soon as PERSIST is used, the last test fails (and ALL includes PERSIST).
I would have expected that if MERGE and PERSIST are set, they would both be active but form the test it looks like MERGE is ignored when PERSIST is set.
Any clues, tips, hints at what I'm doing wrong so that both tests run???
EDIT
The tests are suppose to mimick the behaviour of a REST service endpoint reveiving and saving json reprensentation of an Entity1.
The json for the third test would be
{ name: "with new entity1", entity1: { name: "new entity1"}}
The json for the fourth would be
{ name: "with new entity1", entity1: { id: 1, version: 0, name: "test entity1"}}
JPA should persists the entity1 in the third test because it's id is null but should merge the one in the fourth test because it's id is not null.
I am however unable to do both, it's either one or the other.
EDIT 2
I've modified Entity1 slightly to have a reference to the list of Entity2 associated to it and annotated it with #OneToMany and the same cascading type as in Entity2 and it's the same behavior.
When I set the cascading type to MERGE and only Merge, I'm able to save a new entity that has a reference with an existing one but I can't save a new entity with a reference to a new one.
When I set the cascading type to PERSIST (i.e PERSIST on its own, PERSIST and MERGE or ALL), it's the oppposit; I can save a new entity with a reference to anther new entity but I can't save a new entity with a reference to an already existing one.
So it's seem that when PERSIST is set, it overrides the behavior of MERGE. That, to me, is a bug. Is it not?
I've uploaded the source to github in case you want to experiment or take a look at it yourself. https://github.com/willix71/persistVsMerge.git
You need to add #Transactional on your last test. The entity loaded is detached as there is no outer transaction, you can't persist it.
#Test
#Order(5)
#Transactional
void insertEntity2WithExistingEntity1() {
store.saveEntity2(new Entity2("with saved entity1", store.loadEntity1ByName("test entity1")));
}
I'm not sure if this is relevant anymore, but the code below works as I would expect. Removing "cascade = CascadeType.PERSIST" will fail the persist test with "object references an unsaved transient instance".
I also noticed in your github repo that you are attempting to do cascading both from parent to child and child to parent. I think this is the root cause of your issues.
Entities:
#Entity
#Table(name = "users")
#Getter
#Setter
#NoArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
UUID id;
#ManyToOne(cascade = CascadeType.PERSIST)
Address address;
}
#Entity
#Getter
#Setter
#NoArgsConstructor
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
#OneToMany(mappedBy = "address")
List<User> user;
}
Repositories:
public interface UserRepository extends JpaRepository<User, UUID> {
}
public interface AddressRepository extends JpaRepository<Address, UUID> {
}
Tests:
#DataJpaTest
#Import(DataSourceConfig.class)
class UserRepositoryTest {
#Autowired
private UserRepository userRepository;
#Autowired
private AddressRepository addressRepository;
#Test
void testMerge() {
var address = new Address();
addressRepository.save(address);
var user = new User();
user.setAddress(address);
userRepository.save(user);
assertThat(userRepository.findAll()).contains(user);
assertThat(addressRepository.findAll()).contains(address);
}
#Test
void testPersist() {
var address = new Address();
var user = new User();
user.setAddress(address);
userRepository.save(user);
assertThat(userRepository.findAll()).contains(user);
assertThat(addressRepository.findAll()).contains(address);
}
}

Multiple JPA Repositories with multiple Entity Mapping conflict

I am creating a simple one to many relationship using JPA and Spring Data Rest. But i am getting this error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'designationRepository' defined in com.example.relational.BootRelations.repository.DesignationRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Cannot resolve reference to bean 'jpaMappingContext' while setting bean property 'mappingContext'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: com.example.relational.BootRelations.models.Designation
That is because I have #Entity classes like Designation and Employee, the code follows like:
#Entity
public class Designation {
private String Designation;
private float Salary;
#OneToMany(targetEntity=Employee.class, mappedBy="designation", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumn(name="Emp_Id")
private Set<Employee> employee;
// Getter & Setter and Constructors
}
Now Employee class:
#Entity
#Table(name="Employee")
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="Emp_Id")
private int Emp_Id;
#Column(name="Emp_Name")
private String Emp_Name;
#Column(name="Emp_Email")
private String Emp_Email;
#OneToOne(targetEntity=Designation.class, mappedBy="employee", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private Designation designation;
// // Getter & Setter and Constructors
}
The repositories are:
public interface DesignationRepository extends JpaRepository<Designation, Integer> {}
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {}
Services:
#Service
public class DesignationServiceImpl implements DesignationService {
private DesignationRepository designationRepository;
#Autowired
public DesignationServiceImpl(DesignationRepository designationRepository) {
this.designationRepository = designationRepository;
}
#Override
public List<Designation> findAllDesignation() {
return designationRepository.findAll();
}
}
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeRepository employeeRepository;
#Autowired
public EmployeeServiceImpl(#Qualifier("employeeJPAImpl") EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
}
#Service
public class DesignationServiceImpl implements DesignationService {
private DesignationRepository designationRepository;
#Autowired
public DesignationServiceImpl(#Qualifier("DesignationRepository") DesignationRepository designationRepository) {
this.designationRepository = designationRepository;
}
#Override
public List<Designation> findAllDesignation() {
return designationRepository.findAll();
}
}
As I had two entities I had two controllers:
#RestController
#RequestMapping("/api")
public class DesignationController {
private DesignationService designationService;
#Autowired
public DesignationController(DesignationService designationService) {
this.designationService = designationService;
}
#GetMapping("/designation")
public List<Designation> getAllDesignation(){
return designationService.findAllDesignation();
}
}
and
#RestController
#RequestMapping("/api")
public class EmployeeController {
private EmployeeService employeeService;
#Autowired
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
// Mappings
}
Can anyone help me solve this issue? Until I had one entity it was working fine; as soon as I added another one it failed to start, with the error. Please help me fix the issue.
In Employee class make this changes.
#Entity
#Table
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column
private Long empId;
#Column
private String Name;
#Column
private String Email;
#OneToMany(targetEntity=Designation.class, fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private Designation designation;
// // Getter & Setter and Constructors
}
In the Designation class, make this changes..
#Entity
public class Designation {
#Id
private Long id;
private String role;
private float salary;
#ManyToOne(targetEntity=Employee.class, fetch=FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumn
private Set<Employee> employee;
// Getter & Setter and Constructors
}
This will result in a table structure like this.
Employee
EMP_ID
NAME
EMAIL
Designation
ID
ROLE
SALARY
EMPLOYEE_ID
In OneToMany and ManyToOne association, we must keep a note that, which class is holding the Many side. That side is known as the owning side. As that class will contain the foreign key. Here, our designation class is containing the Many side. So, it will create a foreign key automatically.
If we give the #JoinColumn in the Employee class. Still we will get the Designation class as the Owning class.
You can refer this article, for more details.
Rather than this, let me tell you some of your major mistakes.
Do not give the variables name same as your class name.
By writing variables name as empId in java file, it will result EMP_ID in database.
If a column name or a table name is same your variable name, you can avoid re-mentioning it.
means, if my entity class name is Employee. And I want my database Table name should also be EMPLOYEE. I can avoid specifying #Table(name="EMPLOYEE").
I hope it would be helpful !!

How can I access the data from a table in another schema

I have to get data from a table in another schema, which I do have grant permission.
Tried select query from my current database. I am able to acess the table in other schema(USERAUTH)
Entity had created with schema attribute
#Entity
#Table(name="PESRSON", schema=USERAUTH)
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="CODE")
private Long code;
#Column(name="TITLE")
private String title;
.....
.....
.....
}
Created Repository
#Repository
public interface PersonRepo extends JpaRepository<Person, Long> {
}
In service, to get the record.
#Autowired
private PersonRepo personRepo;
.....
.....
.....
Person per = personRepo.getOne(663L);
Exception on server start.
ERROR ORA-00942: table or view does not exist
How can I access the data from a table in another schema.
I was facing the same problem and after doing a bit of Google I find out below two options. You can use either way to achieve the same.
#Entity
#Table(name="PESRSON", schema="USERAUTH", catalog="USERAUTH")
public class Person implements Serializable { }
or
#Entity
#Table(name="USERAUTH.PESRSON")
public class Person implements Serializable { }

Spring Data Neo4J #Indexed(unique = true) not working

I'm new to Neo4J and I have, probably an easy question.
There're NodeEntitys in my application, a property (name) is annotated with #Indexed(unique = true) to achieve the uniqueness like I do in JPA with #Column(unique = true).
My problem is, that when I persist an entity with a name that already exists in my graph, it works fine anyway.
But I expected some kind of exception here...?!
Here' s an overview over basic my code:
#NodeEntity
public abstract class BaseEntity implements Identifiable
{
#GraphId
private Long entityId;
...
}
public class Role extends BaseEntity
{
#Indexed(unique = true)
private String name;
...
}
public interface RoleRepository extends GraphRepository<Role>
{
Role findByName(String name);
}
#Service
public class RoleServiceImpl extends BaseEntityServiceImpl<Role> implements
{
private RoleRepository repository;
#Override
#Transactional
public T save(final T entity) {
return getRepository().save(entity);
}
}
And this is my test:
#Test
public void testNameUniqueIndex() {
final List<Role> roles = Lists.newLinkedList(service.findAll());
final String existingName = roles.get(0).getName();
Role newRole = new Role.Builder(existingName).build();
newRole = service.save(newRole);
}
That's the point where I expect something to go wrong!
How can I ensure the uniqueness of a property, without checking it for myself??
P.S.: I'm using neo4j 1.8.M07, spring-data-neo4j 2.1.0.BUILD-SNAPSHOT and Spring 3.1.2.RELEASE.
I walked into the same trap... as long as you create new entities, you will not see the exception - the last save()-action wins the battle.
Unfortunately, the DataIntegrityViolationException will be raised only in case of update an existing entity!
A detailed description of that behaviour can be found here:
http://static.springsource.org/spring-data/data-graph/snapshot-site/reference/html/#d5e1035
If you are using SDN 3.2.0+ use the failOnDuplicate attribute:
public class Role extends BaseEntity
{
#Indexed(unique = true, failOnDuplicate = true)
private String name;
...
}

Resources