Hi i want to create DAO unit test in SPRING mvc for example for this type of code
package users;
public interface UserDAO {
public void setDataSource(DataSource ds);
public void create(int id, int personal, String password, String first_name, String last_name, String role,
String email, Date date, int id_team);
public User getUser(Integer user_id);
public List<User> listUsers();
void create1(int id, int personal, String password, String first_name, String last_name, String role, String email,
Date start_date);
}
...what is the best way to do it
For simpler DAO methods, which don't use proprietary sql functions you can use in memory relational database, like HSQLDB.
You configure it as a datasource for your tests.
You can start and populate it during test set up and the data will not be persisted anywhere after the test is done.
Seeing the methods you want to test, I suggest you take a look at Spring Data. All these methods are already implemented for you, all you have to do is configure and set up the interface
Related
I have an entity class User with 20 fields, some of them being confidential fields. I have a controller class, which has a method getUser to fetch all the user from DB and send the JSON respone. Below is the sample code for the same:
#GetMapping("/getUsers")
public UserDT getUsers( Model theModel) {
List<User> userList;
userList = userService.findAll();
return userList;
}
When I run the above code, it returns all the fields from User table/User Entity Class. Instead of sending all the fields, I would like to send selected fields say Field1 to Field5 only.
Ultimate goal is to have multiple views for the same Entity Class. For URL1 I would like to show only field1 to field5 of User table, But for URL2 I would like to show Field9 , Filed15, Field20.
Do I need to create multiple Entity Class for each URL? Please guide me with the best practice to be followed in such scenario.
Assuming you are using Spring Data JPA, use projections.
So create different projections for your different URLs write a method that returns the projection (or a dynamic one as in the documentation).
public interface NamesOnlyProjection {
String getFirstName();
String getLastName();
}
public interface UserinfoProjection {
String getUsername();
String getPassword();
String getDepartment();
}
Then in your repository do something like this
public interface PersonRepository extends JpaRepository<Person, Long> {
<T> List<T> findAll(Class<T> type);
}
Then you can do something like this in your controller/service
#RestController
public class PersonController {
private final PersonRepository persons;
#GetMapping("/people/names")
public List<NamesOnlyProjection> allNames() {
return persons.findAll(NamesOnlyProjection.class);
}
#GetMapping("/people/users")
public List<UserinfoProjection> allNames() {
return persons.findAll(UserinfoProjection.class);
}
}
I am able to get the property value in Spring classes like below:
#Value("${database.name}")
private String databaseName;
I have to execute a native query by joining different tables which are in different databases.
#Query(value="select t1.* FROM db1.table1 t1 INNER JOIN db2.table2 t2 ON t2.t1_id1 = t1.id1")
Instead of hard coding database names i.e., db1 and db2 here, I have to get them from properties file.
how to get the property value inside the #Query annotation in Spring Data JPA Repository ?
I don't know if it is possible, but if not, you can consider this approach:
Instead of using properties in Repository's #Query directly, you can use params in the query but when you call the actual method - you can provide values from .properties.
Imagine you have simple repository:
public interface UserRepository extends JpaRepository<User, Long> {
// query with param
#Query("select u from User u where u.lastname = :lastname")
User findByLastname(#Param("lastname") String lastname);
}
Then, let's say you have some Service or Controller where you need to use your Repository - you can inject properties there and pass them to your method:
#Service
public class UserService {
// this comes from .properties
#Value("${user.lastName}")
private String userLastName;
#Autowired
private UserRepository userRepository;
public User getUser() {
// you pass it as param to the repo method which
// injects it into query
return userRepository.findByLastname(userLastName);
}
}
This is just an example. But I believe it may be useful.
Happy hacking :)
I have Tenant table where only one tenant should be active at a time.
To activate a tenant i am using following code. Is there a better way to change particular column of all rows using spring data mongo.
tenantRepository.save(tenantRepository.findAll().stream().map(t -> {
t.setActive(false);
return t;
}).collect(Collectors.toList()));
tenant.setActive(true);
tenantRepository.save(tenant);
If you want to update specific column(s) in Spring data Mongo, simply define your custom repository interface and its implementation like:
Define Custom Interface
public interface TenantRepositoryCustom {
Integer updateStatus(List<String> id, TenantStatus status, Date date);
}
Implement your Custom Interface
#Repository
public class TenantRepositoryCustomImpl implements TenantRepositoryCustom{
#Autowired
MongoTemplate template;
#Override
Integer updateStatus(List<String> id, TenantStatus status, Date date) {
WriteResult result = template.updateMulti(new Query(Criteria.where("id").in(ids)),
new Update().set("status", status).set("sentTime", date), Tenant.class);
return result.getN();
}
Extends you Default Tenant Repository from Custom Repository:
public interface TenantRepository extends MongoRepository<Tenant, String>, TenantRepositoryCustom{
}
Use Custom repository in Service
#Service
public class TenantService{
#Autowired
TenantRepository repo;
public void updateList(){
//repo.updateStatus(...)
}
}
Note:
This is less error prone as compared to using #Query, as here you will have to just specify column's names and values instead of complete query.
I have a CrudRepository throug which I can access my entities. Let's say I have an entity called Report (all oversimplified and not compiling):
#Entity
public class Report{
#Id
private Long id;
private boolean classified;
private Date date;
private String reportdata;
}
And a CrudRepository:
#RepositoryRestResource(collectionResourceRel = "reports", path = "report")
public interface ReportRepository extends CrudRepository<Report, Long>
{
findByDate(Date date); // <---- I want this to return only reports which are not classified for users who do not have the appropriate role
}
The findByDate will return all reports, including all classified reports for all users making the request. I want to restrict the access to the data based on the currently authenticated user. Is this possible?
You need Spring Security 4. It now integrates with Spring Data.
http://docs.spring.io/spring-security/site/docs/4.0.2.RELEASE/reference/htmlsingle/#data
Something like:
#Repository
public interface ReportRepository extends CrudRepository<Report,Long> {
#Query("select r from Report r where r.date=?1 and r.owner.id = ?#{ principal?.id }")
Report findByDate(Date date);
}
REST is stateless. It means that the server stores NO runtime informations (session, role etc.) about client. So if you want to use REST you should generate an API key for you client. Use a simple path filter to check whether the API key valid or not.
But perhaps you mean AJAX ?
I am using spring-data-jpa version 1.5.1.RELEASE .
My domain is :
public class MyDomain{
....
....
private String prop1;
private String prop2;
......
......
}
My JPA Specification is:
public final class MyDomainSpecs {
public static Specification<MyDomain> search(final String prop1,final String prop2) {
return new Specification<MyDomain>() {
public Predicate toPredicate(Root<MyDomain> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
// Some tests if prop1 exist .....
Predicate predicate1 = cb.equal(root.get("prop1"), prop1);
Predicate predicate2 = cb.equal(root.get("prop2"), prop2);
return cb.and(predicate1, predicate2);
}
};
}
}
My Repository :
public interface MyDomainRepository extends JpaRepository<MyDomain, Long>, JpaSpecificationExecutor<MyDomain> {
List<MyDomain> findAll(Specification<MyDomain> spec);
}
All is Working .
But my need (For performance DB tunning) is to not return and select all fields of MyDomain from DB .
I need to select only for example tree properties (prop1, prop2, prop3) , idealy in a DTO Object .
I don't want to convert My List<MyDomain> to List<MyDto> because i am tunning DB request .
So , I don't find any way to do that with spring-data-Jpa and Specification .
Any Idea ?
Thanks
This is not possible as for now. There is a ticket for this but no idea if it will be ever implmented: https://jira.spring.io/browse/DATAJPA-51
Create a special version of MyDomain (e.g. MyDomainSummary or LightMyDomain) that only includes the fields you want to map.
Basic example
Borrowed from the excellent JPA WikiBook.
Assume a JPA entity (i.e. domain class) like so:
#Entity
#Table(name="EMPLOYEE")
public class BasicEmployee {
#Column(name="ID")
private long id;
#Column(name="F_NAME")
private String firstName;
#Column(name="L_NAME")
private String lastName;
// Any un-mapped field will be automatically mapped as basic and column name defaulted.
private BigDecimal salary;
}
The SQL query generated will be similar to
SELECT ID, F_NAME, L_NAME, SALARY FROM EMPLOYEE
if no conditions (where clause) are defined. So, to generalize the basic case one can say that the number of queried columns is equal to the number of mapped fields in your entity. Therefore, the fewer fields your entity, the fewer columns included in the SQL query.
You can have an Employee entity with e.g. 20 fields and a BasicEmployee as above with only 4 fields. Then you create different repositories or different repository methods for both.
Performance considerations
However, I seriously doubt you'll see noticeable performance improvements unless the fields you want to omit represent relationships to other entities. Before you start tweaking here log the SQL that is currently issued against the data base, then remove the columns you want to omit from that SQL, run it again and analyze what you gained.