How to save an element with WebFlux and ReactiveMongoRepository? - spring

I want to write the first program webFlux and ReactiveMongoRepository.
i have repository:
#Repository
public interface personRepository extends ReactiveMongoRepository<Person,String> {
Mono<Person> save(Person person);
}
my service:
#AllArgsConstructor
#Service
public class personServiceImpl implements personService{
personRepository repository;
#Override
public Flux<Person> findAll() {
return repository.findAll();
}
#Override
public Mono<Person> saveOrUpdate(Person person) {
CompletableFuture<Person> future = CompletableFuture.supplyAsync(() -> {
repository.save(person);
return person;
});
return Mono.fromFuture(future);
}
}
and the rest service itself:
#RestController
#AllArgsConstructor
public class personController {
personServiceImpl personService;
#GetMapping("/all")
Flux<Person> getAllPerson(){
return personService.findAll();
}
#PostMapping("/save")
public Mono<Person> post(#RequestBody Person user) {
System.out.println("inside***************");
return personService.saveOrUpdate(user);
}
}
Now when I want to test the service and save or find everyone via postman, then I get an error:
"path": "/all",
"status": 405,
"error": "Method Not Allowed",
That is, as I understand it, the request does not even reach the function, but an error is immediately thrown, where can there be an error here?

The issue seems to be in saveOrUpdate() method. You don't actually need the CompletableFuture (why would you in this case?) and the following should work:
#AllArgsConstructor
#Service
public class personServiceImpl implements personService{
personRepository repository;
#Override
public Flux<Person> findAll() {
return repository.findAll();
}
#Override
public Mono<Person> saveOrUpdate(Person person) {
return repository.save(person);
}
}

Related

Spring JPA : REQUIRES_NEW propagation not working

I have the following scenario where I have one controller containing two functions (saveAudit and saveProduct). Each one persists an object,I would like to separate transactions between those functions.
throwed exception on saveProduct function should not rollback transaction on saveAudit function :
My repositories/ DAO :
public interface AuditRepository extends JpaRepository<Audit, String> {
}
public interface ProductRepository extends JpaRepository<Product, String> {
}
My controller:
#RestController
#Transactional
public class ProductController {
private final ProductreRepository productRepository;
private final Auditrepository auditRepository;
#Transactional(propagation=Propagation.REQUIRES_NEW)
void saveAudit()
{
auditRepository.saveAudit(Audit.builder().action("action1").build());
}
#PostMapping(ApiPaths.PRODUCTS)
#ResponseStatus(HttpStatus.CREATED)
public ProductDTO addNewProduct() {
ProductDTO res = productRepository.saveProduct(Product.builder().label("product1").build());
saveAudit();
int h=1/0; // => throw exception to rollback product creation
return res;
}
}
Logs:
Participating in existing transaction
its same class proxy will not work.
move below method to #Service class and inject in your controller or annotate #Transactional(propagation=Propagation.REQUIRES_NEW) in auditRepository.saveAudit
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void saveAudit()
{
auditRepository.saveAudit(Audit.builder().action("action1").build());
}

Mocked method always returns empty Optional

So I'm new to Unit Testing.
I'm trying to test the behavior of the method findAll() in IngredientServiceImplTest.
The problem that I'm facing has to do with the return value of the method mocked. It always return empty thus throwing the exception.
Can someone tell me what I'm missing?
Testing class.
#ExtendWith(MockitoExtension.class)
class IngredientServiceImplTest {
#Mock
private MenuItemIngredientRepository menuItemIngredientRepository;
#Mock
private IngredientRepository ingredientRepository;
#InjectMocks
private IngredientServiceImpl ingredientService;
#Mock
private JpaRepository<Ingredient, Long> jpaRepository;
#Mock
private BaseMapper<IngredientCreateDto, IngredientUpdateDto, IngredientResponseDto,
Ingredient> baseMapper;
#BeforeEach
void init() {
ingredientService.jpaRepository = jpaRepository;
ingredientService.baseMapper = baseMapper;
}
#Test
void When_FindById_ReturnIngredient() {
Ingredient ingredient = new Ingredient();
ingredient.setId(1L);
ingredient.setName("Name");
IngredientCreateDto ingredientCreateDto = new IngredientCreateDto();
ingredientCreateDto.setName("Name");
when(jpaRepository.findById(ingredient.getId())).thenReturn(Optional.of(ingredient));
when(baseMapper.createDtoToEntity(ingredientCreateDto)).thenReturn(ingredient);
assertEquals(ingredientService.findById(ingredient.getId()).getName(),
}
Base service class
#AllArgsConstructor
#NoArgsConstructor
public class BaseServiceImpl<CREATE_DTO, UPDATE_DTO, RESPONSE_DTO, ENTITY> implements BaseService<CREATE_DTO, UPDATE_DTO, RESPONSE_DTO, ENTITY> {
#Autowired
protected JpaRepository<ENTITY, Long> jpaRepository;
#Autowired
protected BaseMapper<CREATE_DTO, UPDATE_DTO, RESPONSE_DTO, ENTITY> baseMapper;
#Override
public List<RESPONSE_DTO> findAll() {
return jpaRepository.findAll()
.stream()
.map(baseMapper::entityToResponseDto)
.collect(Collectors.toList());
}
#Override
public RESPONSE_DTO findById(Long id) {
return jpaRepository.findById(id)
.map(baseMapper::entityToResponseDto)
.orElseThrow(() -> {
throw new RuntimeException("Entity with id: " + id + " does not exist!");
});
}
#Override
public RESPONSE_DTO save(CREATE_DTO entity) {
return baseMapper.entityToResponseDto(jpaRepository.save(baseMapper.createDtoToEntity(entity)));
}
}
Ingredient Service class
#Service
#AllArgsConstructor
#Validated
public class IngredientServiceImpl extends BaseServiceImpl<IngredientCreateDto, IngredientUpdateDto, IngredientResponseDto, Ingredient> implements IngredientService{
private final MenuItemIngredientRepository menuItemIngredientRepository;
private final IngredientRepository ingredientsRepository;
#Override
public IngredientResponseDto update(Long id, IngredientUpdateDto ingredient) {
super.findById(id);
Ingredient entityIngredient = baseMapper.updateDtoToEntity(ingredient);
entityIngredient.setId(id);
entityIngredient.setUpdatedAt(LocalDateTime.now());
return baseMapper.entityToResponseDto(jpaRepository.save(entityIngredient));
}
#Override
public List<IngredientResponseDto> findTopIngredients(Integer n) {
return menuItemIngredientRepository.findTopIngredients(n)
.stream()
.map(id -> baseMapper.entityToResponseDto(jpaRepository.getOne(id)))
.collect(Collectors.toList());
}
#Override
public List<IngredientResponseDto> findAllByFilter(IngredientFilter ingredientFilter) {
return ingredientsRepository.findAllByFilter(ingredientFilter)
.stream()
.map(ingredient -> baseMapper.entityToResponseDto(ingredient))
.collect(Collectors.toList());
}
}

How to autowire an Inteface which extends JpaRepository in an another class

#Repository
public interface Userrepo extends JpaRepository<Users, String> {
}
I want the above interface to be autowired in the below class
#Component
public class Userauth {
#Autowired
Userrepo urepo;
public boolean check(String name,String password) {
Application a=new Application();
Optional<Users> u=urepo.findById(name);
if(!u.isEmpty()) {
Users ud=u.get();
if(ud.getPassword().equals(password))
return true;
}
return false;
}
}
but its giving an error "urepo" is null
in the log getting this.
Ignored because not a concrete top-level class: file [C:\Users\Documents\workspace-spring-tool-suite-4-4.9.0.RELEASE\1Sampleproject\target\classes\com\example\demo\repos\Userrepo.class]

Creating custom functions in Spring Boot services

I am writing a simple Spring Boot Application.I'm creating a repository,then its service and then its implementation
The code works fine if I use inbuilt functions of the JPA repository.
However it throws error if I try to make a function in the service interface.
If I make that function in the repository it doesn't throw that error
Here is the code:
Repository:
#Transactional
public interface Local_Repository extends JpaRepository<LocalModel,Long> {
}
Service:
public interface Local_Service {
public List<LocalModel> findAll();
public LocalModel findById(Long id);
public LocalModel findBymo(String mo);//this is the function I added
}
Implementation:
#Service
public class Local_Impl implements Local_Service {
#Autowired
private Local_Repository repository;
#Override
public List<LocalModel> findAll() {
List<LocalModel> cities = (List<LocalModel>) repository.findAll();
return cities;
}
#Override
public LocalModel findById(Long id) {
LocalModel city = repository.findOne(id);
return city;
}
#Override //this throws error
public LocalModel findBymo(String mo) {
LocalModel city=repository.findBymo(mo);
return null;
}
}
In the service you are calling a function that doesn't exist in the repository layer. There is no method called findBymo in the repository. If LocalModel has a field called mo, you can just add a function in the repository interface like this
LocalModel findByMo(String mo);
and it will be implemented automatically.
If LocalModel doesn't have such field you should implement the query yourself in the repository like this
#Query("select ... query here")
LocalModel findByMo(String mo);

How to get entityName or interface name in SpEL for generic repositories in PreAuthorize

I'd like to create a generic security crud repository and annotate each method with preauthorize, however I cannot get how to retrieve entity class name
#NoRepositoryBean
public interface AbstractEntityRepository<T extends AbstractEntity> extends CrudRepository<T, String> {
#Override
#PreAuthorize("hasPermission(null, #entityName, 'find');
Iterable<T> findAll();
}
public interface UserRepository extends AbstractEntityRepository<User> {}
in this case, entityName is always null.
#Component
#Log
public class CustomPermissionEvaluator implements PermissionEvaluator {
#Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission)
log.fine("type " + targetType); // <- null
return true;
}
...
Any idea how to get either "User" or "UserRepository" ?
#Component
public class ClassTypeResolver {
public static String resolve(Object object) {
if (AopUtils.isJdkDynamicProxy(object)) {
try {
return ((SimpleJpaRepository) ((Advised)object).getTargetSource().getTarget()).getDomainClass().getCanonicalName();
} catch (Exception e) {
return null;
}
} else {
return ((SimpleJpaRepository) object).getDomainClass().getCanonicalName();
}
}
}

Resources