What does 'Propagation.NEVER Executes non-transactionally' mean in Spring? - spring

In the code below, the save operation in createDevice method inside DeviceService class will not be executed inside a transaction, what does it mean that this operation is not executed inside a transaction?
Is it possible to execute an operation on the database without a transaction?
package controller;
import model.Device;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import service.DeviceService;
#RestController
public class DeviceController {
#Autowired
private DeviceService deviceService;
#PostMapping("/devices")
#ResponseStatus(HttpStatus.CREATED)
public void createDevice(#RequestBody Device device) {
deviceService.createDevice(device);
}
}
--
package service;
import model.Device;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import repository.DeviceRepository;
#Service
public class DeviceService {
#Autowired
private DeviceRepository deviceRepository;
#Transactional(propagation = Propagation.NEVER)
public void createDevice(Device device) {
deviceRepository.save(device);
}
}
--
package repository;
import model.Device;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DeviceRepository extends JpaRepository<Device, Integer> {
}
--
package model;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Device {
#Id
private Integer id;
private String name;
}
Edit
I'm using MySQL database.
The Operation gets executed successfully.
Any details on how this gets executed without a transaction? What is being done behinde the scene?
What is the difference between executing an operation inside a transaction and without a transaction?

Related

Spring can't find repository bean

I'm using spring boot with spring data jdbc and I got trouble with run my app
I have StudentService class:
package ru.turnip.service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import ru.turnip.model.Student;
import ru.turnip.repository.StudentRepository;
import ru.turnip.utils.student.BusyStudents;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
#Service
public class StudentService {
private final BusyStudents busyStudents;
private final StudentRepository studentRepository;
public StudentService(BusyStudents busyStudents, StudentRepository studentRepository) {
this.busyStudents = busyStudents;
this.studentRepository = studentRepository;
}
...
}
And StudentRepository interface:
package ru.turnip.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import ru.turnip.model.Student;
import java.util.UUID;
#Repository
public interface StudentRepository extends CrudRepository<Student, UUID> { }
So, when I try to run app, I get an eror, and I can't figure out where the problem is.
That my config class:
package ru.turnip;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.relational.core.mapping.event.BeforeSaveEvent;
import org.springframework.scheduling.annotation.EnableScheduling;
import ru.turnip.model.Student;
import java.time.Clock;
import java.util.UUID;
#ComponentScan
#Configuration
#EnableScheduling
public class ApplicationConfig {
#Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
#Bean
public ApplicationListener<BeforeSaveEvent> idGenerator() {
return event -> {
var entity = event.getEntity();
if (entity instanceof Student) {
((Student) entity).setId(UUID.randomUUID());
}
};
}
}
And project structure:
I tried to explicitly set package to be scanned, and also moved the repository to the package with the config. Also I tried to annotate with #Autowired field and constructor in StudentService

Failed to create query for method public abstract

Simple I want test my application to connect with database to insert
some record statically.
it properly work or not.but it throws this type of error that i
mentioned below;
I donot know where i make mistake,I define everything properly
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'turistRepo': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract com.main.ToursTravels.model.Turist com.main.ToursTravels.repo.TuristRepo.findByName(java.lang.String)! No property name found for type Turist!
turistrepo.java
package com.main.ToursTravels.repo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.main.ToursTravels.model.Turist;
#Repository
public interface TuristRepo extends CrudRepository<Turist, Long> {
Turist findByName(String turistname);
}
vechiletyperepo.java
package com.main.ToursTravels.repo;
import java.util.List;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.main.ToursTravels.model.Turist;
import com.main.ToursTravels.model.VechileType;
#Repository
public interface VechileTypeRepo extends CrudRepository<VechileType, Long> {
List<VechileType> findByTurist(Turist turist , Sort sort);
}
mainclasss.java
package com.main.ToursTravels;
import java.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.main.ToursTravels.model.Turist;
import com.main.ToursTravels.model.VechileKind;
import com.main.ToursTravels.model.VechileType;
import com.main.ToursTravels.repo.TuristRepo;
import com.main.ToursTravels.repo.VechileTypeRepo;
#SpringBootApplication
public class ToursTravelsApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ToursTravelsApplication.class, args);
}
#Autowired
TuristRepo trp;
#Autowired
VechileTypeRepo vtrp;
#Override
public void run(String... args) throws Exception {
// TODO Auto-generated method stub
Turist trs = new Turist();
trs.setTuristname("NewsWels");
trs.setTravelkm(100);
trs.setTraveldate(LocalDate.of(2020, 20, 11));
trs.setDrivername("prabhka5r");
VechileType vtp= new VechileType();
vtp.setVechilekind(VechileKind.SEDAN);
vtp.setRateperkm(6);
vtp.setMinprice(2530.00);
trs.setVechileno("GJ05K2619");
trs.setTotalamount(15186.00);
trs.setBookingstatus(true);
trs.setVechiletype(vtp);
vtp.setTurist(trs);
trp.save(trs);
}
}
turist.java
package com.main.ToursTravels.model;
import java.math.BigDecimal;
import java.time.LocalDate;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Data;
#Entity
#Table(name="turist")
#Data
public class Turist {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="truist_id")
private Long truistid;
#Column(name="turistname")
private String turistname;
#Column(name="travel_km")
private int travelkm;
#Column(name="travel_date")
private LocalDate traveldate;
#Column(name="drivername")
private String drivername;
#OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
#JoinColumn(name="booking_id")
private VechileType vechiletype;
#Column(name="vechileno")
private String vechileno;
#Column(name="total_amount")
private Double totalamount;
#Column(name="BOOKING_status")
private boolean bookingstatus;
public Turist(){}
public Turist(String turistname, int travelkm, LocalDate traveldate, String drivername, VechileType vechiletype,
String vechileno, Double totalamount, boolean bookingstatus) {
super();
this.turistname = turistname;
this.travelkm = travelkm;
this.traveldate = traveldate;
this.drivername = drivername;
this.vechiletype = vechiletype;
this.vechileno = vechileno;
this.totalamount = totalamount;
this.bookingstatus = bookingstatus;
}
}
VechileType.java
package com.main.ToursTravels.model;
import java.math.BigDecimal;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import lombok.Data;
#Entity
#Table(name="vechiletype")
#Data
public class VechileType {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="booking_id")
private Long bookingid;
#OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="vechiletype")
private Turist turist;
#Enumerated(EnumType.STRING)
#Column(name="vechilekind")
private VechileKind vechilekind;
#Column(name="rate_per_km")
private int rateperkm;
#Column(name="miniprice")
private Double minprice;
public VechileType(){}
public VechileType(Turist turist, VechileKind vechilekind, int rateperkm, Double minprice) {
this.turist = turist;
this.vechilekind = vechilekind;
this.rateperkm = rateperkm;
this.minprice = minprice;
}
}
Your Repository method references a name field for your Turist class, but none exists. You have turistname available to query.
So your method name should be this:
Turist findByTuristname(String turistname);

Field required a bean of type that could not be found.'

The structure has no problem. The spring-boot can scan UserMapper but can't scan UserService. I tried to give my UserService #Mapper component, then it could be scanned. But I don't know how to use other methods to let it be scanned. I tried #Service but it doesn't work.
package com.mywebprojet.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MywebprojectApplication {
public static void main(String[] args) {
SpringApplication.run(MywebprojectApplication.class, args);
}
}
package com.mywebprojet.springboot.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.mywebprojet.springboot.entity.User;
import com.mywebprojet.springboot.mapper.UserMapper;
import com.mywebprojet.springboot.service.UserService;
#RestController
#RequestMapping(value = "user")
public class UserController {
#Autowired
private UserMapper userMapper;
#Autowired
private UserService userService;
}
package com.mywebprojet.springboot.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.mywebprojet.springboot.entity.User;
#Service
public interface UserService{
void insert(User user);
}
You should write a UserService Implementation and have it annotated with #Service, not the interface. For example:
#Service
public class UserServiceImpl implements UserService {
#Override
public void insert(User user) {
// Implementation
}
}

ApplicationContext failed to load

I am new to testing. I have created a test case to perform a test on rest API using JUNIT Mockito. In my code I have created a test on method itemGetByid(), but when I run the test I get ApplocationContext error message. I don't know where I am going wrong.
Item Controller Test class
package com.example.demo.controller;
import com.example.demo.entities.Item;
import com.example.demo.entities.User;
import com.example.demo.service.ItemService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import java.util.*;
import static org.junit.Assert.*;
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(ItemController.class)
public class ItemControllerTest {
#Autowired
MockMvc mockmvc;
#Mock
ItemService itemService;
#InjectMocks
ItemController itemController;
#Test
public void itemGetById() {
Item item = new Item();
Mockito.when(itemController.getById(10L)).thenReturn(item);
Item i = itemController.getById(10L);
assertEquals(i, item);
}
}
Item entity class
package com.example.demo.entities;
import lombok.Data;
import javax.persistence.*;
#Data
#Entity
#Table(name = "Item")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long itemId;
private Long customerId;
private String itemName;
private int itemPrice;
}
Item controller
package com.example.demo.controller;
import com.example.demo.entities.Item;
import com.example.demo.entities.User;
import com.example.demo.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("item")
public class ItemController {
private ItemService itemService;
#Autowired
public ItemController(ItemService itemService) {
this.itemService = itemService;
}
#PostMapping("/post")
public Item post(#RequestBody Item item) {
return itemService.post(item);
}
#GetMapping
public Iterable<Item> getAll() {
return itemService.get();
}
#GetMapping("/get")
public Item getById(Long id) {
return itemService.getItem(id);
}
#DeleteMapping("/delete")
public void deleteAll() {
itemService.deleteAll();
}
}
Item Service
package com.example.demo.service;
import com.example.demo.entities.Item;
import com.example.demo.userepository.ItemRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
#Service
public class ItemService {
ItemRepository itemRepository;
#Autowired
public ItemService(ItemRepository itemRepository) {
this.itemRepository = itemRepository;
}
public Item post(#RequestBody Item item) {
return itemRepository.save(item);
}
public Iterable<Item> get() {
return itemRepository.findAll();
}
public void deleteAll() {
itemRepository.deleteAll();
}
public Item getItem(Long id) {
return itemRepository.findById(id).get();
}
}
Item Repository
package com.example.demo.userepository;
import com.example.demo.entities.Item;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface ItemRepository extends CrudRepository<Item, Long> {
}
For starters, you are using SpringJUnit4ClassRunner. Try the MockitoJunitRunner.
An ItemController instance is never created in the test, so that needs to be fixed as well.
The line below will fail because itemController is not a mock.
**Mockito.when(itemController.getById(10L)).thenReturn(item);**
If itemController is converted to a mock, with the when statement, the test method doesnt validate anything because the test tells Mockito to return the item in the when statement.
Assuming the intent is to validate the ItemController getById method, the Mockito.when statement needs to describe the call to the Mock ItemService.

Testing connectiong with db, tests passes but no new instance in db created

What I wan to do: I want to test if my app is connecting correctly with db. In order to do so I was using these tutorials: http://www.baeldung.com/spring-boot-testing http://www.baeldung.com/spring-testing-separate-data-source So I'm creating new testUser, saving it and checking if user found by userName is equal to the one I've saved.
What is not working: even though the test passes, no new user appears in database. I don't know why. Any suggestions?
Test:
package com.shareabook.integration.user;
import com.shareabook.constants.initialNumberOfPoints;
import com.shareabook.model.Points;
import com.shareabook.model.User;
import com.shareabook.repository.PointsRepository;
import com.shareabook.repository.RoleRepository;
import com.shareabook.repository.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
#RunWith(SpringRunner.class)
#DataJpaTest
public class userTest {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
#Autowired
private PointsRepository pointsRepository;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#Test
public void whenFindByUserName_thenReturnUser() {
//given
User testUser = new User();
// Creates new points instance
Points points = new Points();
points.setAmountOfPoints(initialNumberOfPoints.INITIAL_NUMBER_OF_POINTS.getInitialNumberOfPoints());
pointsRepository.save(points);
int tempId = points.getId();
testUser.setUserName("userName");
testUser.setFirstName("firstName");
testUser.setLastName("lastName");
testUser.setPassword(passwordEncoder.encode("P#ssword123"));
testUser.setEmail("emal#email.com");
testUser.setIsBlocked(false);
testUser.setIdpoints(tempId);
testUser.setRoles(Arrays.asList(roleRepository.findByRole("USER")));
userRepository.save(testUser);
//when
User found = userRepository.findByUserName(testUser.getUserName());
//then
assertThat(found.getUserName()).isEqualTo(testUser.getUserName());
}
}
------EDIT---------
After helpful suggestions in comments I changed my test a bit and now it's working as expected.
package com.shareabook.integration.user;
import com.shareabook.constants.initialNumberOfPoints;
import com.shareabook.model.Points;
import com.shareabook.model.User;
import com.shareabook.repository.PointsRepository;
import com.shareabook.repository.RoleRepository;
import com.shareabook.repository.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
#RunWith(SpringRunner.class)
#SpringBootTest
public class userTest {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
#Autowired
private PointsRepository pointsRepository;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#Test
public void whenFindByUserName_thenReturnUser() {
//given
User testUser = new User();
// Creates new points instance
Points points = new Points();
points.setAmountOfPoints(initialNumberOfPoints.INITIAL_NUMBER_OF_POINTS.getInitialNumberOfPoints());
pointsRepository.save(points);
int tempId = points.getId();
testUser.setUserName("userName");
testUser.setFirstName("firstName");
testUser.setLastName("lastName");
testUser.setPassword(passwordEncoder.encode("P#ssword123"));
testUser.setEmail("emal#email.com");
testUser.setIsBlocked(false);
testUser.setIdpoints(tempId);
testUser.setRoles(Arrays.asList(roleRepository.findByRole("USER")));
userRepository.save(testUser);
//when
User found = userRepository.findByUserName(testUser.getUserName());
//then
assertNotNull(found);
assertEquals(testUser.getUserName(), found.getUserName());
}
}
#DataJpaTest will configure an in-memory embedded database, scan for #Entity classes and configure Spring Data JPA repositories.
It is transactional but will rollback at the end of each test!
That's why you don't have data in your database.

Resources