hibernate query not producing results - java

I am trying to list all records form a user table.
each time I send the request I get this log
Hibernate:
select
u1_0.id,
u1_0.creation_date,
u1_0.email,
u1_0.full_name,
u1_0.password,
u1_0.updated_date,
u1_0.username
from
user u1_0
but this query is not returning any results
this is the result I get from postman http request
[
{},
{},
{},
{},
{}
]
I have a user entity like this:
#Table(name = "user")
#Entity
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
public class User {
#Id
#GeneratedValue
private Long id;
private String fullName;
private String username;
private String password;
private String email;
private Date creationDate;
private Date updatedDate;
}
a repository like this:
public interface UserRepository extends JpaRepository<User, Long> {
}
a controller like this:
#RestController
#RequestMapping("/api/user")
public class UserController {
#Autowired
private UserRepository userRepository;
#RequestMapping("/list")
public List<User> listAll(){
return userRepository.findAll();
}
}
and this is my table

Related

How to map relationship while testing spring data jpa

Issue
I'm writing test code for a simple service layer using jpa data entity, but entity's relationship doesn't seem to work properly.
I googled but couldn't find an answer. I'm not sure what's wrong.
Please check the code below
Codes
(0) test property
spring.datasource.url=jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false;MODE=MySQL
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.MariaDBDialect
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
(1) entities
#Entity
#Getter
#Setter
#Table(name = "users")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long id;
private String username;
private String password;
#OneToMany(mappedBy = "user")
private List<Authority> authList;
public Set<String> getAuthName() {
if (this.authList == null || this.authList.isEmpty()) return null;
Set<String> authNameSet = new HashSet<>();
authList.forEach(e -> authNameSet.add(e.getStringName()));
return authNameSet;
}
}
//----------
#Entity
#Getter
#Setter
#Table(name = "authorities")
public class Authority implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long id;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#Enumerated(EnumType.STRING)
#Column(length = 10)
private AuthorityName name;
}
(2) repositories
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
}
//----------
#Repository
public interface AuthorityRepository extends CrudRepository<Authority, Long> {
List<Authority> findByUser(User user);
}
(3) service layer to test
#Service
public class AuthorityService {
// this is the method i want to test
public boolean isUserHaveAuthorityOf(User user, AuthorityName authOf) {
if (user == null || authOf == null) throw new InternalError("msg");
if (user.getAuthName() == null) return false;
return user.getAuthName().contains(authOf.name());
}
}
(4) test code
import static org.junit.jupiter.api.Assertions.*;
#TestPropertySource("/application-test.properties")
#SpringBootTest
#Transactional
class AuthorityServiceTest {
#Autowired private UserRepository userRepository;
#Autowired private AuthorityRepository authorityRepository;
#Autowired private AuthorityService authorityService;
private User sampleUser;
#BeforeEach
void setupDB() {
User user = new User();
user.setId(1);
user.setUsername("name");
user.setPassword("passwd");
user.setEmail("email#dot.com");
user.setBirth("20000101");
user.setAddress("addr");
user.setAddressDetail("addrDetail");
user.setZipCode("12345");
user.setDeleted(false);
user.setDisabled(false);
user.setBlock(false);
userRepository.save(user);
sampleUser = user;
}
#Test
void testIsUserHaveAuthorityOfNormalCase() {
assertFalse(authorityService.isUserHaveAuthorityOf(sampleUser, AuthorityName.USER));
assertFalse(authorityService.isUserHaveAuthorityOf(sampleUser, AuthorityName.ADMIN));
Authority auth = new Authority();
auth.setUser(sampleUser);
auth.setName(AuthorityName.USER);
authorityRepository.save(auth);
assertNotNull(sampleUser.getAuthName()); // it is null!
// I thought it was because of a caching, so I get a new user from the db.
User flushedUser = userRepository.findById(sampleUser.getId()).get();
assertNotNull(flushedUser.getAuthName()); // but still null
}
#AfterEach
void cleanDB() {
authorityRepository.deleteAll();
userRepository.deleteAll();
}
}
Thank you
You have a bidirectional relationship between User and Authority so you should keep the relationship in sync. As well as setting the User in an Authority you should also add the Authority to the the User
public void addAuthority(Authority authority) {
if (authList == null) {
authList = new ArrayList<>();
}
authList.add(authority);
authority.setUser(this);
}
It would also be helpful to see how you are persisting the sampleUser

Transactional Service Method that updates 2 repositories

I want to test Transactional operation in my project. Basically, I want to roll back the userService.saveUser() operation, if an exception is thrown. I have simplified the classes, and you can find it below.
A user must live in an address. An address can have multiple users.
Address Entity
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Address {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "STREET")
#NotNull
private String street;
#ToString.Exclude
#OneToMany(mappedBy = "address")
private Set<User> users = new HashSet<>();
}
User Entity
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "USER")
public class User {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "FIRSTNAME", nullable = false)
#NotNull
private String firstName;
#ManyToOne(fetch = FetchType.LAZY)
private Address address;
}
Repositories
public interface AddressRepository extends CrudRepository<Address, Long> {
}
public interface UserRepository extends CrudRepository<User, Long> {
}
UserService Class
#Service
#Slf4j
#AllArgsConstructor
public class UserService {
#Autowired
AddressRepository addressRepository;
#Autowired
UserRepository userRepository;
#Transactional
public void saveUser(String firstName, String street) {
var address1 = Address.builder.street(street).build();
// to make sure that I have "id" of the address when I am saving it.
var addressSaved = addressRepository.save(address1);
if ("f1".equals(firstName))
throw new RuntimeException("some exception");
var user = User.builder()
.firstName(firstName)
.address(addressSaved)
.build();
// this operation can also throw DataIntegrityViolationException
userRepository.save(user);
}
}
This is my test class
#SpringBootTest
class UserServiceIT {
#Autowired
AddressRepository addressRepository;
#Autowired
UserRepository userRepository;
#Autowired
UserService userService;
#BeforeEach
void beforeEach() {
userRepository.deleteAll();
addressRepository.deleteAll();
}
#Test
void test_saveUser() {
assertThrows(RuntimeException.class,() -> userService.saveUser("f1", "s1"));
assertEquals(0, userRepository.count());
assertEquals(0, addressRepository.count());
}
#Test
void test_saveUser2() {
// column: nullable = false will throw the exception
assertThrows(DataIntegrityViolationException.class,() -> userService.saveUser(null, "s1"));
assertEquals(0, userRepository.count());
assertEquals(0, addressRepository.count());
}
}
Both of the tests give assertion error on address count (Address is saved and user is not saved). I expect address to be roll backed (and not to be saved) since there is an error after saving the address, and while saving the user (some condition is violated, therefore 2 saves must be roll backed). What am I doing wrong?
application.yml for test environment
spring:
devtools:
restart:
enabled: false
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=false
driverClassName: org.h2.Driver
username: sa
password: 123
h2:
console:
enabled: false
jpa:
database-platform: org.hibernate.dialect.H2Dialect
database: H2
show-sql: false
hibernate:
ddl-auto: create
You can reach the whole sample project from this link: https://wetransfer.com/downloads/7cb870266e2e20f610b44d3cc9f229c220220308071438/7b88a2700076a3e53771e389c796cfe420220308071438/c777ab
The code you posted here differs from what is actually exists in the original code you uploaded.
original code:
#Transactional
void saveUser(String firstName, String street) {
var address = Address.builder().street(street).build();
var addressSaved = addressRepository.save(address);
if ("f1".equals(firstName))
throw new RuntimeException("f1");
var user = Person.builder()
.firstName(firstName)
.address(addressSaved)
.build();
personRepository.save(user);
}
This method actually have default access modifier so CGLIB is not able to override it and creates the needed logic. change access modifier of this method to public

How to make a get all records using pageable in springboot

I am trying to get all records from a h2 database using pageable. I can pull the results using normal findAll(), but when I try using pageable, I am not able to
This is my controller
#GetMapping
Page<PostInfo> getPosts(Pageable pageable) {
return postService.getPosts(pageable);
}
this are my models
My Post model
#Data
#ToString
#Entity
#Table(name = "POST")
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
private String content;
}
My Postdetails class which extends postinfo
#Data
#ToString
public class PostDetails extends PostInfo {
private String content;
}
My Postinfo class
#Data
#ToString
#Entity
public class PostInfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
}
My PostService service class
public interface PostService {
PostDetails createPost(#Valid CreatePostRequest createPostRequest);
Page<PostInfo>getPosts(final Pageable pageable);
PostDetails getPostDetails(Long id);
void deletePost(Long id);
}
My Implementation class
#Override
public Page<PostInfo> getPosts(Pageable pageable) {
return postRepository.findAll(pageable);
}
I end up getting not getting pageable data. How can I use pageable to findAll() records stored. I have researched with no luck. Any help is appreciated. Thanks in advance.
Use PageRequest.of(pageNumber,pageSize) in your implementation, like:
#Override
public Page<PostInfo> getPosts(int pageNumber, int pageSize) {
return postRepository.findAll(PageRequest.of(pageNumber,pageSize));
}
and in your interface use:
Page<PostInfo> getPosts(int pageNumber, int pageSize);
instead of:
Page<PostInfo>getPosts(final Pageable pageable);

How to get User from database for login with Spring Boot and Spring Data Jpa

I want to make login form with data from my own database. I made Entity User class:
#Entity
#Table(name = "Auth_data")
public class User {
#Id
#GeneratedValue
#Getter #Setter
private Long id;
#Column(name= "username")
#Getter #Setter
private String username;
#Column(name="password")
#Getter #Setter
private String password;
#Enumerated(EnumType.ORDINAL)
#Column(name="role")
#Getter #Setter
private Role role;
#Column(name = "client_ID")
#Getter #Setter
private Long clientID;
#Column(name = "instructor_ID")
#Getter #Setter
private Long instructorID;
public User() {}
public User(String username, String password, Role role, Long clientID, Long instructorID) {
this.username = username;
this.password = password;
this.role = role;
this.clientID = clientID;
this.instructorID = instructorID;
}
}
Also I made UserDetailsServiceIml class which implements UserDetailsService:
#Service
public class UserDetailsServiceIml implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final User user = userRepository.findByUsername(username);
if(user == null) {
throw new UsernameNotFoundException(username);
}
Set<GrantedAuthority> grantedAuthorities = new HashSet< >();
grantedAuthorities.add(new SimpleGrantedAuthority(user.getRole().name()));
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
grantedAuthorities);
}
}
My User repository class:
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
I also tried make Query like this:
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
#Query("Select u from User u WHERE u.username=:username")
User findByUsername(#Param("username") String username);
}
But when I enter login and password into login form I get error, because User is Null after searching in database. How can I fix it?
UPD: SOLVED!
I don't know why and how. I found that hibernate created new table "auth_data", but not used my table "Auth_data". So, I renamed "Auth_data" to "auth_data" and now it's work! I also changed #Getter #Setter on #Data,changed in User repository on " User findByUsername(String username);" and changed type of field role from enum to String.
It is possible that you don't seed the database with the user you are trying to login. You can use an Application Runner class to seed it on every start if the user doesn't exist in the database. Also, you can apply the #Data annotation from Lombok on class level to generate getters and setters for all the fields.
package com.javahowtos.dataseeddemo.dataseed;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import com.javahowtos.dataseeddemo.model.User;
import com.javahowtos.dataseeddemo.repository.UserRepository;
#Component
public class UserDataLoader implements CommandLineRunner {
#Autowired
UserRepository userRepository;
#Override
public void run(String... args) throws Exception {
loadUserData();
}
private void loadUserData() {
if (userRepository.count() == 0) {
User user1 = new User("John", "Doe");
User user2 = new User("John", "Cook");
userRepository.save(user1);
userRepository.save(user2);
}
System.out.println(userRepository.count());
}
}
Source: https://javahowtos.com/guides/107-spring/376-how-to-seed-the-database-in-spring-boot-project.html
You have to be sure that you have a user with the appropriate username in the database (case sensitive), if you do not have a user you can insert some test users (with the migration tool, with custom component, or manually)
You probably need to add a unique index for username
If you extend JpaRepository and add method findByUsername spring will generate implementation and you do not need #Query, if you have multiple items you can use findFirstByUsername

Choosing which attributes to publish in RESTful web service

Given a User entity with the following attributes mapped:
#Entity
#Table(name = "user")
public class User {
//...
#Id
#GeneratedValue
#Column(name = "user_id")
private Long id;
#Column(name = "user_email")
private String email;
#Column(name = "user_password")
private String password;
#Column(name = "user_type")
#Enumerated(EnumType.STRING)
private UserType type;
#Column(name = "user_registered_date")
private Timestamp registeredDate;
#Column(name = "user_dob")
#Temporal(TemporalType.DATE)
private Date dateOfBirth;
//...getters and setters
}
I have created a controller method that returns a user by ID.
#RestController
public class UserController {
//...
#RequestMapping(
value = "/api/users/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> getUser(#PathVariable("id") Long id) {
User user = userService.findOne(id);
if (user != null) {
return new ResponseEntity<User>(user, HttpStatus.OK);
}
return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
}
//...
}
A service in my business logic layer.
public class UserServiceBean implements UserService {
//...
public User findOne(Long id) {
User user = userRepository.findOne(id);
return user;
}
//...
}
And a repository in my data layer.
public interface UserRepository extends JpaRepository<User, Long> {
}
This works fine, it returns everything about the user, but I use this in several different parts of my application, and have cases when I only want specific fields of the user.
I am learning spring-boot to create web services, and was wondering: Given the current implementation, is there a way of picking the attributes I want to publish in a web service?
If not, what should I change in my implementation to be able to do this?
Thanks.
Firstly, I agree on using DTOs, but if it just a dummy PoC, you can use #JsonIgnore (jackson annotation) in User attributes to avoid serializing them, for example:
#Entity
#Table(name = "user")
public class User {
//...
#Column(name = "user_password")
#JsonIgnore
private String password;
But you can see there, since you are not using DTOs, you would be mixing JPA and Jackson annotations (awful!)
More info about jackson: https://github.com/FasterXML/jackson-annotations

Categories

Resources