Spring: Method Injection Lookup How to use it? - spring

Can I use Method Injection Lookup -- with a entity class?.I use Spring+JPA+Hibernate. This allow to inject a prototype bean into a singleton bean.Is this also possible with entity beans?A is prototype scoped bean.I want to put A(#Entity) into a class B (ex. DAO) with scope=singleton.Thanks
#Entity
public class A(){
private String name;
private String surname;
...//get and set
}//A
public interface DAO{
public void method();
}//DAO
public class DAOImpl implements DAO{
private A object_a;
public void method(){
//In this method I use everytime a new istance of A
}//method
}//DAOImpl

You can use #Embedded to include your sub bean, and use in your sql.
#Entity
public class User(){
private String name;
#Embedded
private Address address;
#Bean(scope=DefaultScopes.PROTOTYPE)
public User() {
}
...//get and set
}
#Entity
public class Address(){
private String name;
...//get and set
}
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "select u from users u where u.address.name = :addressName")
List<Blog> findUserByAddress(#Param("addressName") String addressName);
}

Related

How to do a Findby In Springboot Mongo repository for Nested Objects

Need your help here in a Spring Data CrudRepository on how to do a findby of nested fields.
My class is of following structure and I need to query using truckId which is of the nested objects
#Document(collection = "unt-truck")
public class TruckModelDTO {
private String type;
private TestDTO testDTO;
}
Class TestDTO.java
public class TestDTO{
private TruckDTO truckDTO;
Private String version;
}
Class TruckDTO.java
public class TruckDTO {
private String truckId;
private String legacySystem;
}
Class TruckRepository.java
#Repository
public interface TruckRepository extends MongoRepository<TruckModelDTO, String> {
// TruckModelDTO findByTruckId(String truckid);
}
So how should I use findby for truckId which is inside a nested class?
You can use with either Entity or DTO as response. but you have to mention the relation between two or three Entity based on you requirement.
I have created Entity. you have to create DTO with same based on entity then apply main DTO as return type in JPA Repository query.
1.Entity
#Entity
public class TruckModel {
private String type;
// mention the relation based on your requirement
private Test test;
}
Entity
#Entity
public class Test {
// here mention the relation based on you requirement
private Truck truck;
Private String version;
}
3.Entity
#Entity
public class Truck {
private String truckId;
private String legacySystem;
}
Repository
#Repository
public interface TruckModelRepository extends MongoRepository<TruckModel, String> {
TruckModelDTO findByTestTruckTruckId(String truckid);
}

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 !!

Modifying spring data repository methods (mongo)

I have the following classes: MyEntity, MyEntityRepository, MyEntityCustomRepository, MyEntityCustomRepositoryImpl.
MyEntity:
#Document
class MyEntity {
#Id
private ObjectId id;
private final String name;
#JsonIgnore
private Boolean isDeleted = false;
#JsonIgnore
private Instant deletedAt;
}
MyEntityRepository:
#Repository
interface MyEntityRepository extends MongoRepository<MyEntity, ObjectId>, MyEntityCustomRepository {}
MyEntityCustomRepository:
public interface MyEntityCustomRepository {
List <MyEntity> someCustomMethod(Set<ObjectId> ids);
}
MyEntityCustomRepositoryImpl
class MyEntityCustomRepositoryImpl implements MyEntityCustomRepository {
private final MongoTemplate template;
MyEntityCustomRepositoryImpl(MongoTemplate template) {
this.template = template;
}
#Override
public List <MyEntity> someCustomMethod(Set<ObjectId> ids) {
Query query = new Query()
...
return template.find(query, MyEntity.class);
}
}
Now I want to modify all find/get/count etc methods in the MyEntityRepository by adding param Criteria.where("isDeleted).is(false) to all queries.
It's easy to add this query param to my custom method, but what will be the best way to override methods from the CrudRepository extended by the MyEntityRepository?

Spring Data JPA: using property in #Query as parameter

I have several application-x.properties files which are used for different profiles and each file contains a property with a specific value for each profile. I want to use this property in queries to database as a parameter.
Is it possible to add it using SpEL or something else?
For instance application.properties:
query.parameters.role: ADMIN
possible usage:
#Query(value = "select u from User u where u.role = :#{query.parameters.role}")
Set<User> getAllUsers();
You might do it by following way:
1.- Find all users by role using Repository Query Keywords
#Repository
public interface UserRepository extends JpaRepository<User, UUID> {
Set<User> findByRole(String role);
}
2.- Create a method called getAllUsers in UserService and get role value by using #Value:
#Service
public class UserService {
#Autowired
private UserRepository repository;
#Value("${query.parameters.role}")
private String role;
public Set<User> getAllUsers() {
return repository.findByRole(role);
}
}
Other way to answer to this question is implement a custom SpEL that is supported by #Query you can take a look this SpEL support in Spring Data JPA
Then you should follow these steps for your case:
1.- Create a ConfigProperties class so that you can read and get the application.properties.
#Configuration
#PropertySource("classpath:application.properties")
#ConfigurationProperties(prefix = "query")
public class ConfigProperties {
private Parameters parameters;
// standard getters and setters
}
public class Parameters {
private String role;
// standard getters and setters
}
2.- Implement a custom EvaluationContextExtensionSupport and reference to ConfigProperties
public class PropertyEvaluationContextExtension extends EvaluationContextExtensionSupport {
private final ConfigProperties configProperties;
public PropertyEvaluationContextExtension(final ConfigProperties configProperties) {
this.configProperties= configProperties;
}
#Override
public String getExtensionId() {
return "properties";
}
#Override
public ConfigProperties getRootObject() {
return this.configProperties;
}
}
3.- Create a bean in order to be called your custom PropertyEvaluationContextExtension
#Configuration
public class CustomConfig {
private final ConfigProperties configProperties;
public CustomConfig(final ConfigProperties configProperties) {
this.configProperties= configProperties;
}
#Bean
EvaluationContextExtensionSupport propertyExtension() {
return new PropertyEvaluationContextExtension(configProperties);
}
}
4.- Call the query.parameters.role by following format: ?#{query.parameters.role}
#Query(value = "SELECT u FROM User u WHERE u.role = ?#{query.parameters.role}")
Set<User> getAllUsers();

Generic DAO design-pattern with inheritance. is this a good design?

I just want to have a comment for what I've learned from dozens of samples about Generic DAO design-pattern. I added an inheritance hierarchy between POJO classes, DAO interfaces, and DAO implementations please see codes below
Legend:
DAOs (From Parent to children)
DAO implementations (From Parent to Children)
POJO classes (From Parent to Children)
The Data Acess Objects (Interfaces)
The GenericDAO interface
public interface GenericDAO<T> {
... some crud operations common to all objets
}
The PersonDAO interface
public interface PersonDAO<T extends Person> extends GenericDAO<T> {
... some operations unique to a person
}
The StudentDAO interface
public interface StudentDAO extends PersonDAO<Student> {
... some operations unique to a student
}
The Implementations
The GenericDAO Implementation
#Repository("genericDAO")
public class GenericDAOImpl<T extends Person> implements GenericDAO<T> {
private Class<T> type;
#SuppressWarnings("unchecked")
public GenericDAOImpl() {
this.type = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), GenericDAO.class);
System.out.println(type);
}
#Resource(name = "sessionFactory")
protected SessionFactory sessionFactory;
#Transactional
#Override
public Integer save(T entity) {
return (Integer) sessionFactory.getCurrentSession().save(entity);
}
#SuppressWarnings("unchecked")
#Transactional
#Override
public T get(Integer id) {
return (T) sessionFactory.getCurrentSession().get(type, id);
}
}
The PersonDAO implementation
#Repository ("personDAO")
public class PersonDAOImpl<T extends Person> extends GenericDAOImpl<T> implements PersonDAO<T> {
.. implemented methods for person
}
The StudentDAO implementation
#Repository("studentDAO")
public class StudentDAOImpl extends PersonDAOImpl<Student> implements StudentDAO {
.. implemented methods for student
}
The POJO Classes (Hibernate Annotated)
The Person Class (Parent Abstract Class)
#MappedSuperclass
public abstract class Person {
#Id
#GeneratedValue
#Column (name = "id")
private int id;
#Column (name = "name")
private String name;
#Column (name = "age")
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The concrete class (Student)
#Entity
#Table(name = "STUDENT")
public class Student extends Person {
#Column(name = "school")
private String school;
public Student() {
}
public Student(String school) {
this.school = school;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
I've been thinking about how am I going to construct a design-pattern between POJOs and DAO objects for days, Until I've come up with these design based on everything I've learned from different resources around the web. I've come up with the idea of DAO and DAO implementation inheritance based on the inheritance of the POJOs.
is this a good practice? reflecting the hierarchy of the POJOs and do it in DAOs?
am I doing something wrong about here with my design? because I have a complete program that
saves and retrieves my objects from the database without any problem
I'm open to any suggestion or corrections. Thank you in advance!!!
Not a comment on the design, but... have you consider using Spring Spring Data Jpa, which allows you to:
write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.

Resources