Unable to delete item from ReactiveCouchbaseRepository - java

Working on my first app using Spring data with Reactive Couchbase and having trouble with repository operations. I can create a User in my UserRepository and can retrieve it by id or name, but can't delete it. deleteAll() doesn't work either.
#N1qlPrimaryIndexed
#ViewIndexed(designDoc = "user")
interface UserRepository extends ReactiveCouchbaseRepository<User, String> {
Flux<User> findByName(String name)
}
#Service
class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository
Mono<User> save(User user) {
return userRepository.save(user)
}
Mono<Void> delete(User user) {
return userRepository.delete(user)
}
Mono<User> findById(String id) {
return userRepository.findById(id)
}
Flux<User> findByName(String name) {
return userRepository.findByName(name)
}
}
class UserServiceTest extends ApplicationTests {
#Autowired
private UserService userService
#Test
void testSave() {
User user = new User(null, 'name')
User savedUser = userService.save(user).block()
List<User> allUsers = userRepository.findAll().collectList().block()
assert allUsers.size() == 1
userService.delete(allUsers.first())
allUsers = userRepository.findAll().collectList().block()
assert allUsers.size() == 0 // fails here
}
}

You simply forgot to subscribe() (or block()) to the delete Mono<Void>

Related

Is there a way to extend a Spring Service in order to manage an inherited entity without duplicating code?

I'm playing with a Spring application with 2 controllers and 2 services that manages related entities and I would like to avoid duplicating code. I've got for example a Person class with his PersonRepository
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Person {
#Id
Long id;
String name;
String surname;
}
And his child User with his UserRepository
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class User extends Person {
String login;
String password;
}
I've a simple Person service whith business logic:
#Service
public class PersonService {
#Autowired
PersonRepository repo;
public Iterable<Person> getAll() {
// Busines Logic
return repo.findAll();
}
}
Is there a way to create a UserService extending or proxying PersonService and implementing some kind of repository "hiding"? Something like this:
#Service
public class UserService extends PersonService {
#Autowired
UserRepository repo;
}
that obviously gives this error:
Type mismatch: cannot convert from Iterable<Person> to Iterable<User> with a controller like this
#RestController
#RequestMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
public class DemoController {
#Autowired
UserService service;
#GetMapping
public void items() {
Iterable<User> persons = service.getAll();
return;
}
}
Try the following structure:
Common service and repository:
#NoRepositoryBean
public interface PersonRepository<T> extends JpaRepository<T, Long> {
}
public class PersonService<T extends Person> {
protected PersonRepository<T> repository;
public <R extends PersonRepository<T>> PersonService(R repository) {
this.repository = repository;
}
public Iterable<T> getAll() {
return repository.findAll();
}
}
For User entity:
public interface UserRepository extends PersonRepository<User> {
}
#Service
public class UserService extends PersonService<User> {
public UserService(UserRepository repository) {
super(repository);
}
public void additionalMethod() {
User user = repository.getOne(1L);
}
}
And I added Company entity by User entity example:
public interface CompanyRepository extends PersonRepository<Company> {
}
#Service
public class CompanyService extends PersonService<Company> {
public CompanyService(CompanyRepository repository) {
super(repository);
}
public void additionalMethod() {
Optional<Company> company = repository.findById(1L);
}
}

The given id must not be null!; nested exception is java.lang.IllegalArgumentException

i'm creating a simple crud with spring boot. All function well but I have a little problem with the method findOne(Long id)
in postman when i put this url : http://localhost:8080/api/user/id/?id=13 , i get this exception :
"error": "Internal Server Error",
"exception": "org.springframework.dao.InvalidDataAccessApiUsageException",
"message": "The given id must not be null!; nested exception is java.lang.IllegalArgumentException: The given id must not be null!",
here is my code :
Repository
#SuppressWarnings("unused")
#Repository
public interface UserRepository extends JpaRepository<Utilisateur, Long> {
}
Service
public interface UserService {
Utilisateur save(Utilisateur utilisateur);
List<Utilisateur> findAll();
Utilisateur findOne(Long id);
}
ServiceImpl
#Service
public class UserServiceImpl implements UserService{
#Autowired
UserRepository userRepository;
public UserServiceImpl() {
}
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public Utilisateur save(Utilisateur utilisateur) {
return userRepository.save(utilisateur);
}
#Override
public List<Utilisateur> findAll() {
return userRepository.findAll();
}
public Utilisateur findOne(Long id) {
return userRepository.findOne(id);
}
}
Controller
#RestController
#RequestMapping("/api")
#CrossOrigin(origins="http://localhost:4200",allowedHeaders="*")
public class UserController {
#Autowired
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
public UserController() {
super();
// TODO Auto-generated constructor stub
}
#GetMapping("/users")
public List<Utilisateur> getUsers() {
return userService.findAll();
}
#GetMapping("/user/id/{id}")
public ResponseEntity<Utilisateur> getUser(#PathVariable Long id) {
Utilisateur utilisateur = userService.findOne(id);
return ResponseEntity.ok().body(utilisateur);
}
/*
#DeleteMapping("/user/{id}")
public Boolean deleteUser(#PathVariable Long id) {
userRepository.delete(id);
return true;
} */
#PostMapping("/user")
public ResponseEntity<Utilisateur> saveUser(#RequestBody Utilisateur utilisateur) throws URISyntaxException {
Utilisateur result = userService.save(utilisateur);
return ResponseEntity.created(new URI("/api/user/" + result.getId()))
.body(result);
}
#PutMapping("/user")
public ResponseEntity<Utilisateur> updateUser(#RequestBody Utilisateur utilisateur) throws URISyntaxException {
Utilisateur result = userService.save(utilisateur);
return ResponseEntity.ok().body(result);
}
}
You have your mapping set as a URL path variable
#GetMapping("/user/id/{id}")
but the URL you tried has a query parameter: ?id=13
Try using: http://localhost:8080/api/user/id/13
Here is a good comparison of the two on stackoverflow
The URL is incorrect. You have set it up as a path variable in your code. In which case, instead of hitting localhost:8080/api/user/id/?id=13 in postman, you should hit localhost:8080/api/user/id/3 instead,
But if you were following REST standards, a better URL would look like this (no need to have the "id" in the URL). localhost:8080/api/user/3

User account is locked while signing in

I'm starting to learn Spring Security now and I got with trouble. I wrote configuration classes, getting data from DB and so on, but in my webpage I see the message "User account is locked" and error parameter in url after signing in.
MessengerApplication.java
#SpringBootApplication
public class MessengerApplication {
public static void main(String[] args) {
SpringApplication.run(MessengerApplication.class, args);
}
}
MainPageController.java
#RestController
public class MainPageController {
#RequestMapping("/")
public ModelAndView greeting() {
Map<String, Object> model = new HashMap<>();
model.put("data", "world");
return new ModelAndView("main_page", model);
}
}
SecurityConfig.java
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserServiceImpl userService;
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider
= new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
}
UserServiceImpl.java
#Service
public class UserServiceImpl implements UserDetailsService {
#Autowired
UserRepository userRepository;
#Override
public MyUserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userRepository.findUserByName(s);
if (user == null)
throw new UsernameNotFoundException(s);
return new MyUserDetails(user);
}
}
UserRepositoryImpl.java
#Repository
public class UserRepositoryImpl implements UserRepository {
#Autowired
JdbcTemplate template;
#Override
public User findUserByName(String name) {
return template.queryForObject("select * from users where name = ?", rowMapper, name);
}
private RowMapper<User> rowMapper = new RowMapper<User>() {
#Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User();
user.setPassword(resultSet.getString("password"));
user.setName(resultSet.getString("name"));
user.setId(resultSet.getLong("id"));
return user;
}
};
}
UserRepository.java
public interface UserRepository {
User findUserByName(String name);
}
User.java
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable = false, unique = true)
private String name;
private String password;
// get(), set()
}
MyUserDetails.java
public class MyUserDetails implements UserDetails {
private User user;
public MyUserDetails(User user) {
this.user = user;
}
// ...
}
The method is isAccountNonLocked, emphasis on non. You need to return true from this method in order to have an 'unlocked' account. Same thing with the method that pertains to 'expired', etc. In this case true means allow it, false means reject it.

Why can't I save my #Entity User with it's UserRepository in Spring Boot

Problem
Invoking repository.save(user); where repository is an instance of UserRepository and user.toString is User[id=0, userName='asd', password='asd'], my controller gives the following error:
nested exception is java.lang.IllegalArgumentException: Invoked method public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object) is no accessor method!] with root cause
java.lang.IllegalArgumentException: Invoked method public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object) is no accessor method!
Details
I know repository.save(new User("user1", "pass1")); works because I tested my repository using:
public CommandLineRunner demo(UserRepository repository) {
return (args) -> {
// save a couple of users
repository.save(new User("user1", "pass1"));
repository.save(new User("user2", "pass2"));
}
}
Here's the full Request mapping of the page:
RequestMapping(value = "/register", method = RequestMethod.GET)
public String showRegistrationForm(WebRequest request, Model model) {
User user = new User();
model.addAttribute("user", user);
return "registrations/register";
}
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerUserAccount(WebRequest request,
#ModelAttribute("user") #Valid User user,
BindingResult result,
UserRepository repository) {
if (!result.hasErrors()) {
System.out.println(user);
repository.save(user);
}
return "redirect:/";
}
And here's the UserRepository:
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByUserName(String UserName);
}
And here's the User #Entity:
#Entity
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String userName;
private String password;
protected User() {}
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
// standard getters and setters
#Override
public String toString() {
return String.format(
"User[id=%d, userName='%s', password='%s']",
id, userName, password);
}
}
It seems the UserRepository repository in code of Controller should not be used as parameter:
...
public String registerUserAccount(WebRequest request,
#ModelAttribute("user") #Valid User user,
BindingResult result,
UserRepository repository)
...
Can you just use #Autowired it like:
#Autowired
private UserRepository repository;
And then try again?!
Hope this help.

Mock objects returns null

I have below Test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SpringTestConfig.class)
public class UserServiceTest {
#Inject
private UserRepository userRepository;
#Inject
private UserService userService;
#Test
public void testProcessInvoice() throws SQLException {
User user = new User();
user.setFirstName("abc");
when(userRepository.save(any(User.class))).thenReturn(user);
Assert.assertNotNull(userService);
User savedUser = userService.save(user);
Assert.assertEquals("abc", savedUser.getFirstName());
}
}
I have below SpringTestConfig.java
#Configuration
public class SpringTestConfig {
#Bean
public UserService userService() {
return Mockito.mock(UserService.class);
}
#Bean
public UserRepository userRepository() {
return Mockito.mock(UserRepository.class);
}
}
call to User savedUser = userService.save(user); returns null user object. I am not able to figure it out why it is returning null.
EDIT:
UserRepository is JpaRepository, if this is a problem
public interface UserRepository extends JpaRepository<User, Long> {
}
Your UserService is a mock object, and has no defined behavior for dealing with the #save(User) method.
Mocking the object under test is probably not what you are after here. I would recommend your objects under test are instantiated in the test, and injected with the mocks or stubs of the objects that they utilize.
Your configuration needs to return a real UserService:
#Configuration
public class SpringTestConfig {
#Bean
public UserService userService() {
return new UserServiceImpl(); // or whatever your implementation is
}
#Bean
public UserRepository userRepository() {
return Mockito.mock(UserRepository.class);
}
}
Mocks are for collaborators, not for the thing you're testing.

Categories