Dobry wieczór, postanowiłem że w ramach przypomnienia/poćwiczenia operacji asynchronicznych, przepisze sobie zwykłą metodę w serwisie na asynchroniczną. Jak ona wygląda i w czym jest problem:
public Activity addActivityToActivityList(AddActivityCommand addActivityCommand) {
// Wypisuje normalnie uzytkownika powiązanego z Listą Aktywności - więc lista jest normalnie znajdywana
System.out.println(activitiesListRepository
.findById(addActivityCommand.getActivitiesListId())
.get()
.getUser()
.getUsername());
// Optional wyrzuca mój wyjątek - nie może znaleźć listy, mimo tego, że u góry to samo działa
CompletableFuture<ActivitiesList> owningActivitiesList = CompletableFuture.supplyAsync(
() -> activitiesListRepository
.findById(addActivityCommand.getActivitiesListId())
.<ActivitiesListNotFound>orElseThrow(ActivitiesListNotFound::new)
// ^^ btw. bez jawnego zadeklarowania typu wyjątku w diamond operator javac nie chciało mi kompilować
);
// Raczej nieważne rzeczy, dalsze asynchroniczne działania
}
Co robi - persystuje obiekt Activity, mając parę danych i id *Listy Aktywności *, z którą ma być powiązany.
W czym problem - normalnie, bez żadnych asynchronicznych działań wszystko działa. Gdy wrzucę tą samą metodę do CompletableFuture, nagle obiekt nie może być znaleziony.
Test integracyjny w Junit5, wcześnie persystuje obiekty używając TestEntityManager:
@Test
void shouldAddNewActivityToActivitiesList() {
//given
activitiesServiceImpl.addNewActivitiesListToUser( new CreateNewActivitiesListCommand(user.getId()));
List<ActivitiesList> activitiesList = user.getActivitiesList();
// when
// Sprawdzalem czy testEntityManager znajduje obiekt - znajduje
System.out.println(testEntityManager.find(ActivitiesList.class, activitiesList.get(0).getId()));
activitiesServiceImpl.addActivityToActivityList( new AddActivityCommand(
activitiesList.get(0).getId(),
testActivityType.getId(),
0,
0
));
// then
assertEquals( 1, user.getActivitiesList().get(0).getActivities().size(),
"Activity weren't persisted" );
}
Repositorium to czyste repozytorium Spring Data -
public interface SpringDataActivitiesListRepository extends ActivitiesListRepository, JpaRepository<ActivitiesList, Long> {}
Serwis ma adnotacje:
@Service
@Transactional
Klasa testowa :
@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureTestEntityManager
@Transactional
Szczerze powiedziawszy to nie mam nawet pomysłu jaki może być problem - pewnie coś z JPA/Hibernatem, ale nie potrafię powiedzieć. Próbowałem robić * flush()* i clear() na testEntityManager, ale nie pomaga, dalej to samo.
TLDR: Ta sama metoda w wersji "po kolei" znajduje zapisany obiekt bez problemu. Po wprowadzeniu asynchroniczności, obiekt nie może zostać znaleziony. Jakim cudem obiekt w supplyAsync() nagle przestaje być persistent?