From b9c3e310cbe7d81fe12e9b3c6a7b88fd744a82bc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:26:08 +0000 Subject: [PATCH 01/12] Initial plan From 97d4a1ecb7f07339f8f296deb18ef112e71e0254 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:46:12 +0000 Subject: [PATCH 02/12] Refactor MediaModel: fix equals bug, List->Set, remove SUBSELECT, add BatchMapping Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com> --- .../geek/batch/MovieItemWriter.java | 4 +- .../espacogeek/geek/batch/MovieProcessor.java | 2 +- .../geek/batch/SerieItemWriter.java | 4 +- .../espacogeek/geek/batch/SerieProcessor.java | 2 +- .../geek/controllers/MediaController.java | 130 ++++++++++++++++++ .../data/api/impl/GamesAndVNsApiImpl.java | 10 +- .../geek/data/api/impl/MovieAPIImpl.java | 6 +- .../geek/data/api/impl/TvSeriesApiImpl.java | 8 +- .../impl/GenericMediaDataControllerImpl.java | 40 +++--- .../geek/data/impl/MovieControllerImpl.java | 4 +- .../geek/data/impl/SerieControllerImpl.java | 4 +- .../espacogeek/geek/models/MediaModel.java | 26 ++-- .../AlternativeTitlesRepository.java | 10 +- .../ExternalReferenceRepository.java | 6 +- .../geek/repositories/MediaRepository.java | 32 +++++ .../geek/repositories/SeasonRepository.java | 6 + .../geek/services/impl/MediaServiceImpl.java | 5 +- .../resources/graphql/entity/Company.graphqls | 4 + .../resources/graphql/entity/Media.graphqls | 4 + .../resources/graphql/entity/People.graphqls | 5 + .../geek/cors/BrowserCorsRequestTest.java | 17 +++ .../geek/query/media/AnimeQueryTest.java | 17 +++ .../geek/query/media/GameQueryTest.java | 17 +++ .../geek/query/media/MediaQueryTest.java | 17 +++ .../geek/query/media/MovieQueryTest.java | 17 +++ .../geek/query/media/TvSerieQueryTest.java | 17 +++ .../query/media/VisualNovelQueryTest.java | 17 +++ .../geek/services/MediaServiceImplTest.java | 14 +- 28 files changed, 376 insertions(+), 69 deletions(-) create mode 100644 src/main/resources/graphql/entity/Company.graphqls create mode 100644 src/main/resources/graphql/entity/People.graphqls diff --git a/src/main/java/com/espacogeek/geek/batch/MovieItemWriter.java b/src/main/java/com/espacogeek/geek/batch/MovieItemWriter.java index 68bcbe03..d42374d0 100644 --- a/src/main/java/com/espacogeek/geek/batch/MovieItemWriter.java +++ b/src/main/java/com/espacogeek/geek/batch/MovieItemWriter.java @@ -75,13 +75,13 @@ public void write(List items) { // fetch and persist alternative titles using the external API id (if present) try { - String externalId = original.getExternalReference().get(0).getReference(); + String externalId = original.getExternalReference().iterator().next().getReference(); if (externalId != null) { var alts = movieApi.getAlternativeTitles(Integer.valueOf(externalId)); if (alts != null && !alts.isEmpty()) { alts.forEach(a -> a.setMedia(persisted)); alternativeTitlesService.saveAll(alts); - persisted.setAlternativeTitles(alts); + persisted.setAlternativeTitles(new java.util.LinkedHashSet<>(alts)); } } } catch (Exception e) { diff --git a/src/main/java/com/espacogeek/geek/batch/MovieProcessor.java b/src/main/java/com/espacogeek/geek/batch/MovieProcessor.java index 66ec159e..2282d4b1 100644 --- a/src/main/java/com/espacogeek/geek/batch/MovieProcessor.java +++ b/src/main/java/com/espacogeek/geek/batch/MovieProcessor.java @@ -87,7 +87,7 @@ public MediaModel process(JSONObject json) { externalReference.setTypeReference(typeReference); externalReference.setReference(idStr); - List refs = new ArrayList<>(); + java.util.LinkedHashSet refs = new java.util.LinkedHashSet<>(); refs.add(externalReference); media.setExternalReference(refs); diff --git a/src/main/java/com/espacogeek/geek/batch/SerieItemWriter.java b/src/main/java/com/espacogeek/geek/batch/SerieItemWriter.java index 243d74bc..8c828fc6 100644 --- a/src/main/java/com/espacogeek/geek/batch/SerieItemWriter.java +++ b/src/main/java/com/espacogeek/geek/batch/SerieItemWriter.java @@ -75,7 +75,7 @@ public void write(List items) { } try { - String externalId = original.getExternalReference().get(0).getReference(); + String externalId = original.getExternalReference().iterator().next().getReference(); if (externalId != null) { List alts = tvSeriesApi.getAlternativeTitles(Integer.valueOf(externalId)); if (alts != null && !alts.isEmpty()) { @@ -83,7 +83,7 @@ public void write(List items) { alternativeTitleModel.setMedia(persisted); } alternativeTitlesService.saveAll(alts); - persisted.setAlternativeTitles(alts); + persisted.setAlternativeTitles(new java.util.LinkedHashSet<>(alts)); } } } catch (Exception e) { diff --git a/src/main/java/com/espacogeek/geek/batch/SerieProcessor.java b/src/main/java/com/espacogeek/geek/batch/SerieProcessor.java index 10fb3887..6baf27ca 100644 --- a/src/main/java/com/espacogeek/geek/batch/SerieProcessor.java +++ b/src/main/java/com/espacogeek/geek/batch/SerieProcessor.java @@ -87,7 +87,7 @@ public MediaModel process(JSONObject json) { externalReference.setTypeReference(typeReference); externalReference.setReference(idStr); - List refs = new ArrayList<>(); + java.util.LinkedHashSet refs = new java.util.LinkedHashSet<>(); refs.add(externalReference); media.setExternalReference(refs); diff --git a/src/main/java/com/espacogeek/geek/controllers/MediaController.java b/src/main/java/com/espacogeek/geek/controllers/MediaController.java index e4ce6265..2ae22572 100644 --- a/src/main/java/com/espacogeek/geek/controllers/MediaController.java +++ b/src/main/java/com/espacogeek/geek/controllers/MediaController.java @@ -2,10 +2,21 @@ import lombok.RequiredArgsConstructor; import org.springframework.graphql.data.method.annotation.Argument; +import org.springframework.graphql.data.method.annotation.BatchMapping; import org.springframework.graphql.data.method.annotation.QueryMapping; import org.springframework.stereotype.Controller; +import com.espacogeek.geek.models.AlternativeTitleModel; +import com.espacogeek.geek.models.CompanyModel; +import com.espacogeek.geek.models.ExternalReferenceModel; +import com.espacogeek.geek.models.GenreModel; import com.espacogeek.geek.models.MediaModel; +import com.espacogeek.geek.models.PeopleModel; +import com.espacogeek.geek.models.SeasonModel; +import com.espacogeek.geek.repositories.AlternativeTitlesRepository; +import com.espacogeek.geek.repositories.ExternalReferenceRepository; +import com.espacogeek.geek.repositories.MediaRepository; +import com.espacogeek.geek.repositories.SeasonRepository; import com.espacogeek.geek.services.MediaService; import com.espacogeek.geek.types.MediaPage; import com.espacogeek.geek.utils.MediaUtils; @@ -13,10 +24,20 @@ import graphql.schema.DataFetchingEnvironment; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; @Controller @RequiredArgsConstructor public class MediaController { private final MediaService mediaService; + private final SeasonRepository seasonRepository; + private final AlternativeTitlesRepository alternativeTitlesRepository; + @SuppressWarnings("rawtypes") + private final ExternalReferenceRepository externalReferenceRepository; + private final MediaRepository mediaRepository; /** * Finds a MediaModel object by its ID. @@ -125,4 +146,113 @@ public MediaPage getAnime(@Argument(name = "id") Integer id, @Argument(name = "n return this.mediaService.findAnimeByIdOrName(id, name, MediaUtils.getPageable(dataFetchingEnvironment)); } + + /** + * Batch-loads seasons for a list of MediaModel sources, resolving the N+1 problem. + */ + @BatchMapping + public Map> season(List medias) { + Map sourceById = medias.stream() + .collect(Collectors.toMap(MediaModel::getId, m -> m)); + Map> result = medias.stream() + .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + for (SeasonModel season : seasonRepository.findByMediaIn(medias)) { + MediaModel source = sourceById.get(season.getMedia().getId()); + if (source != null) { + result.get(source).add(season); + } + } + return result; + } + + /** + * Batch-loads genres for a list of MediaModel sources, resolving the N+1 problem. + */ + @BatchMapping + public Map> genre(List medias) { + Map sourceById = medias.stream() + .collect(Collectors.toMap(MediaModel::getId, m -> m)); + Map> result = medias.stream() + .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + for (MediaModel loaded : mediaRepository.findAllWithGenreByMediaIn(medias)) { + MediaModel source = sourceById.get(loaded.getId()); + if (source != null && loaded.getGenre() != null) { + result.put(source, loaded.getGenre()); + } + } + return result; + } + + /** + * Batch-loads companies for a list of MediaModel sources, resolving the N+1 problem. + */ + @BatchMapping + public Map> company(List medias) { + Map sourceById = medias.stream() + .collect(Collectors.toMap(MediaModel::getId, m -> m)); + Map> result = medias.stream() + .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + for (MediaModel loaded : mediaRepository.findAllWithCompanyByMediaIn(medias)) { + MediaModel source = sourceById.get(loaded.getId()); + if (source != null && loaded.getCompany() != null) { + result.put(source, loaded.getCompany()); + } + } + return result; + } + + /** + * Batch-loads people for a list of MediaModel sources, resolving the N+1 problem. + */ + @BatchMapping + public Map> people(List medias) { + Map sourceById = medias.stream() + .collect(Collectors.toMap(MediaModel::getId, m -> m)); + Map> result = medias.stream() + .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + for (MediaModel loaded : mediaRepository.findAllWithPeopleByMediaIn(medias)) { + MediaModel source = sourceById.get(loaded.getId()); + if (source != null && loaded.getPeople() != null) { + result.put(source, loaded.getPeople()); + } + } + return result; + } + + /** + * Batch-loads external references for a list of MediaModel sources, resolving the N+1 problem. + */ + @BatchMapping + @SuppressWarnings("unchecked") + public Map> externalReference(List medias) { + Map sourceById = medias.stream() + .collect(Collectors.toMap(MediaModel::getId, m -> m)); + Map> result = medias.stream() + .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + for (ExternalReferenceModel ref : (List) externalReferenceRepository.findAllByMediaIn(medias)) { + MediaModel source = sourceById.get(ref.getMedia().getId()); + if (source != null) { + result.get(source).add(ref); + } + } + return result; + } + + /** + * Batch-loads alternative titles for a list of MediaModel sources, resolving the N+1 problem. + */ + @BatchMapping + public Map> alternativeTitles(List medias) { + Map sourceById = medias.stream() + .collect(Collectors.toMap(MediaModel::getId, m -> m)); + Map> result = medias.stream() + .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + for (AlternativeTitleModel alt : alternativeTitlesRepository.findByMediaIn(medias)) { + MediaModel source = sourceById.get(alt.getMedia().getId()); + if (source != null) { + result.get(source).add(alt); + } + } + return result; + } } diff --git a/src/main/java/com/espacogeek/geek/data/api/impl/GamesAndVNsApiImpl.java b/src/main/java/com/espacogeek/geek/data/api/impl/GamesAndVNsApiImpl.java index f8e3a9d5..0d7c7491 100644 --- a/src/main/java/com/espacogeek/geek/data/api/impl/GamesAndVNsApiImpl.java +++ b/src/main/java/com/espacogeek/geek/data/api/impl/GamesAndVNsApiImpl.java @@ -95,7 +95,7 @@ public MediaModel getDetails(Integer id) { genresName.add(genre.getName()); }); - media.setGenre(genreService.findAllByNames(genresName)); + media.setGenre(new java.util.LinkedHashSet<>(genreService.findAllByNames(genresName))); media.setAbout(result.getSummary()); media.setName(result.getName()); @@ -112,8 +112,8 @@ public MediaModel getDetails(Integer id) { for (proto.AlternativeName title : result.getAlternativeNamesList()) { if (!title.getName().isEmpty()) alternativeTitles.add(new AlternativeTitleModel(null, title.getName(), media)); } - media.setAlternativeTitles(alternativeTitles); - media.setExternalReference(new ArrayList<>(List.of(reference))); + media.setAlternativeTitles(new java.util.LinkedHashSet<>(alternativeTitles)); + media.setExternalReference(new java.util.LinkedHashSet<>(List.of(reference))); media.setMediaCategory(category); } } @@ -154,8 +154,8 @@ public List doSearch(String search, MediaCategoryModel mediaCategory for (proto.AlternativeName title : result.getGame().getAlternativeNamesList()) { if (!title.getName().isEmpty()) alternativeTitles.add(new AlternativeTitleModel(null, title.getName(), media)); } - media.setAlternativeTitles(alternativeTitles); - media.setExternalReference(new ArrayList<>(List.of(reference))); + media.setAlternativeTitles(new java.util.LinkedHashSet<>(alternativeTitles)); + media.setExternalReference(new java.util.LinkedHashSet<>(List.of(reference))); media.setMediaCategory(category); diff --git a/src/main/java/com/espacogeek/geek/data/api/impl/MovieAPIImpl.java b/src/main/java/com/espacogeek/geek/data/api/impl/MovieAPIImpl.java index 1e682b01..43b679f2 100644 --- a/src/main/java/com/espacogeek/geek/data/api/impl/MovieAPIImpl.java +++ b/src/main/java/com/espacogeek/geek/data/api/impl/MovieAPIImpl.java @@ -99,12 +99,12 @@ public MediaModel getDetails(Integer id) { movieDb.getPosterPath() == null ? null : ExternalCDN.TMDB.getUrl() + movieDb.getPosterPath(), movieDb.getBackdropPath() == null ? null : ExternalCDN.TMDB.getUrl() + movieDb.getBackdropPath(), mediaCategoryService.findById(MediaDataController.MediaType.MOVIE.getId()).get(), - externalReferences, + new java.util.LinkedHashSet<>(externalReferences), null, null, - formatGenre(movieDb.getGenres()), + new java.util.LinkedHashSet<>(formatGenre(movieDb.getGenres())), null, - formatAlternativeTitles(movieDb.getAlternativeTitles().getTitles()), + new java.util.LinkedHashSet<>(formatAlternativeTitles(movieDb.getAlternativeTitles().getTitles())), null); return serie; diff --git a/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java b/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java index 0627e860..9f123965 100644 --- a/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java +++ b/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java @@ -105,13 +105,13 @@ public MediaModel getDetails(Integer id) { rawSerieDetails.getPosterPath() == null ? null : ExternalCDN.TMDB.getUrl() + rawSerieDetails.getPosterPath(), rawSerieDetails.getBackdropPath() == null ? null : ExternalCDN.TMDB.getUrl() + rawSerieDetails.getBackdropPath(), mediaCategoryService.findById(MediaDataController.MediaType.SERIE.getId()).get(), - externalReferences, + new java.util.LinkedHashSet<>(externalReferences), null, null, - formatGenre(rawSerieDetails.getGenres()), + new java.util.LinkedHashSet<>(formatGenre(rawSerieDetails.getGenres())), null, - formatAlternativeTitles(rawSerieDetails.getAlternativeTitles().getResults()), - season); + new java.util.LinkedHashSet<>(formatAlternativeTitles(rawSerieDetails.getAlternativeTitles().getResults())), + new java.util.LinkedHashSet<>(season)); return serie; } diff --git a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java index 5ade23b2..4917aaf5 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java @@ -1,7 +1,9 @@ package com.espacogeek.geek.data.impl; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.LinkedHashSet; import java.lang.reflect.Field; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -102,7 +104,7 @@ public MediaModel updateArtworks(MediaModel media, MediaModel result, TypeRefere MediaModel rawArtwork = new MediaModel(); if (result == null) { - List externalReferences = media.getExternalReference(); + Collection externalReferences = media.getExternalReference(); if (externalReferences == null || !Hibernate.isInitialized(externalReferences)) { externalReferences = externalReferenceService.findAll(media); } @@ -148,20 +150,20 @@ public List updateAlternativeTitles(MediaModel media, Med } } } else { - allAlternativeTitles = result.getAlternativeTitles(); + allAlternativeTitles = result.getAlternativeTitles() != null ? new ArrayList<>(result.getAlternativeTitles()) : new ArrayList<>(); } - if (CollectionUtils.isEmpty(allAlternativeTitles)) return media.getAlternativeTitles(); + if (CollectionUtils.isEmpty(allAlternativeTitles)) return media.getAlternativeTitles() != null ? new ArrayList<>(media.getAlternativeTitles()) : new ArrayList<>(); - if (media.getAlternativeTitles() == null) media.setAlternativeTitles(new ArrayList<>()); + if (media.getAlternativeTitles() == null) media.setAlternativeTitles(new LinkedHashSet<>()); for (AlternativeTitleModel title : allAlternativeTitles) { if (media.getAlternativeTitles().stream().noneMatch((alternativeTitle) -> alternativeTitle.getName().equals(title.getName()))) { media.getAlternativeTitles().add(new AlternativeTitleModel(null, title.getName(), media)); } } - alternativeTitlesService.saveAll(media.getAlternativeTitles()); - return media.getAlternativeTitles(); + alternativeTitlesService.saveAll(new ArrayList<>(media.getAlternativeTitles())); + return new ArrayList<>(media.getAlternativeTitles()); } @Override @@ -179,12 +181,12 @@ public List updateExternalReferences(MediaModel media, M } } } else { - rawExternalReferences = result.getExternalReference(); + rawExternalReferences = result.getExternalReference() != null ? new ArrayList<>(result.getExternalReference()) : new ArrayList<>(); } - if (CollectionUtils.isEmpty(rawExternalReferences)) return media.getExternalReference(); + if (CollectionUtils.isEmpty(rawExternalReferences)) return media.getExternalReference() != null ? new ArrayList<>(media.getExternalReference()) : new ArrayList<>(); - if (media.getExternalReference() == null) media.setExternalReference(new ArrayList<>()); + if (media.getExternalReference() == null) media.setExternalReference(new LinkedHashSet<>()); for (ExternalReferenceModel reference : rawExternalReferences) { if (CollectionUtils.isEmpty(media.getExternalReference()) || media.getExternalReference().stream().noneMatch((eReference) -> eReference.getReference().equals(reference.getReference()))) { reference.setMedia(media); @@ -192,9 +194,9 @@ public List updateExternalReferences(MediaModel media, M } } - externalReferenceService.saveAll(media.getExternalReference()); + externalReferenceService.saveAll(new ArrayList<>(media.getExternalReference())); - return media.getExternalReference(); + return new ArrayList<>(media.getExternalReference()); } @Override @@ -212,10 +214,10 @@ public List updateGenres(MediaModel media, MediaModel result, TypeRe } } } else { - rawGenres = result.getGenre(); + rawGenres = result.getGenre() != null ? new ArrayList<>(result.getGenre()) : new ArrayList<>(); } - if (CollectionUtils.isEmpty(rawGenres)) return media.getGenre(); + if (CollectionUtils.isEmpty(rawGenres)) return media.getGenre() != null ? new ArrayList<>(media.getGenre()) : new ArrayList<>(); rawGenres.forEach((rawGenre) -> { if (media.getGenre().stream().noneMatch((genre) -> genre.getId().equals(rawGenre.getId()))) { @@ -224,8 +226,8 @@ public List updateGenres(MediaModel media, MediaModel result, TypeRe } }); - genreService.saveAll(media.getGenre()); - return media.getGenre(); + genreService.saveAll(new ArrayList<>(media.getGenre())); + return new ArrayList<>(media.getGenre()); } @Override @@ -240,10 +242,10 @@ public List updateSeason(MediaModel media, MediaModel result, TypeR } } } else { - rawSeasons = result.getSeason(); + rawSeasons = result.getSeason() != null ? new ArrayList<>(result.getSeason()) : new ArrayList<>(); } - if (CollectionUtils.isEmpty(rawSeasons)) return media.getSeason(); + if (CollectionUtils.isEmpty(rawSeasons)) return media.getSeason() != null ? new ArrayList<>(media.getSeason()) : new ArrayList<>(); rawSeasons.forEach((rawSeason) -> { if (media.getSeason().stream().noneMatch((season) -> season.getName().equals(rawSeason.getName()))) { @@ -252,7 +254,7 @@ public List updateSeason(MediaModel media, MediaModel result, TypeR }); var savedSeasons = seasonService.saveAll(seasons); - List newSeasons = media.getSeason() == null ? new ArrayList<>() : media.getSeason(); + List newSeasons = media.getSeason() == null ? new ArrayList<>() : new ArrayList<>(media.getSeason()); newSeasons.addAll(savedSeasons == null ? new ArrayList<>() : savedSeasons); return newSeasons; @@ -283,7 +285,7 @@ public List searchMedia(String search, MediaApi mediaApi, TypeRefere result.add(media); } catch (MediaAlreadyExist e) { - media = mediaService.findByReferenceAndTypeReference(mediaSearch.getExternalReference().getFirst(), typeReference).orElseThrow(); + media = mediaService.findByReferenceAndTypeReference(mediaSearch.getExternalReference().iterator().next(), typeReference).orElseThrow(); result.add(media); } diff --git a/src/main/java/com/espacogeek/geek/data/impl/MovieControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/MovieControllerImpl.java index 5bb3de3d..b9efa314 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/MovieControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/MovieControllerImpl.java @@ -133,11 +133,11 @@ else if (isUndefined) externalReference.setMedia(mediaSaved); var referenceSaved = externalReferenceService.save(externalReference); - List referenceListSaved = new ArrayList<>(); + java.util.LinkedHashSet referenceListSaved = new java.util.LinkedHashSet<>(); referenceListSaved.add(referenceSaved); mediaSaved.setExternalReference(referenceListSaved); - media.setAlternativeTitles(updateAlternativeTitles(mediaSaved, null, typeReference, movieAPI)); + media.setAlternativeTitles(new java.util.LinkedHashSet<>(updateAlternativeTitles(mediaSaved, null, typeReference, movieAPI))); } } catch (Exception e) { var json = (JSONObject) jsonArrayDailyExport.get(index); diff --git a/src/main/java/com/espacogeek/geek/data/impl/SerieControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/SerieControllerImpl.java index 9a38936e..19422dc6 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/SerieControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/SerieControllerImpl.java @@ -102,11 +102,11 @@ private void updateTvSeries() { externalReference.setMedia(mediaSaved); var referenceSaved = externalReferenceService.save(externalReference); - List referenceListSaved = new ArrayList<>(); + java.util.LinkedHashSet referenceListSaved = new java.util.LinkedHashSet<>(); referenceListSaved.add(referenceSaved); mediaSaved.setExternalReference(referenceListSaved); - media.setAlternativeTitles(updateAlternativeTitles(mediaSaved, null, typeReference, tvSeriesApi)); + media.setAlternativeTitles(new java.util.LinkedHashSet<>(updateAlternativeTitles(mediaSaved, null, typeReference, tvSeriesApi))); } } catch (Exception e) { var json = (JSONObject) jsonArrayDailyExport.get(index); diff --git a/src/main/java/com/espacogeek/geek/models/MediaModel.java b/src/main/java/com/espacogeek/geek/models/MediaModel.java index 95c75d18..8083536a 100644 --- a/src/main/java/com/espacogeek/geek/models/MediaModel.java +++ b/src/main/java/com/espacogeek/geek/models/MediaModel.java @@ -2,11 +2,9 @@ import java.io.Serializable; import java.util.Date; -import java.util.List; import java.util.Objects; +import java.util.Set; -import org.hibernate.annotations.Fetch; -import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.UpdateTimestamp; import jakarta.persistence.*; @@ -56,32 +54,28 @@ public class MediaModel implements Serializable { private MediaCategoryModel mediaCategory; @OneToMany(mappedBy = "media", fetch = FetchType.LAZY) - @Fetch(FetchMode.SUBSELECT) - private List externalReference; + private Set externalReference; @ManyToMany(fetch = FetchType.LAZY) @JoinTable( name = "medias_has_companies", joinColumns = @JoinColumn(name = "medias_id_media"), inverseJoinColumns = @JoinColumn(name = "companies_id_company")) - @Fetch(FetchMode.SUBSELECT) - private List company; + private Set company; @ManyToMany(fetch = FetchType.LAZY) @JoinTable( name = "medias_has_people", joinColumns = @JoinColumn(name = "medias_id_media"), inverseJoinColumns = @JoinColumn(name = "people_id_person")) - @Fetch(FetchMode.SUBSELECT) - private List people; + private Set people; @ManyToMany(fetch = FetchType.LAZY) @JoinTable( name = "medias_has_genres", joinColumns = @JoinColumn(name = "medias_id_media"), inverseJoinColumns = @JoinColumn(name = "genres_id_genre")) - @Fetch(FetchMode.SUBSELECT) - private List genre; + private Set genre; @Column(name = "update_at") @UpdateTimestamp @@ -89,12 +83,10 @@ public class MediaModel implements Serializable { private Date updateAt; @OneToMany(mappedBy = "media", fetch = FetchType.LAZY) - @Fetch(FetchMode.SUBSELECT) - private List alternativeTitles; + private Set alternativeTitles; - @OneToMany(mappedBy = "media") - @Fetch(FetchMode.SUBSELECT) - private List season; + @OneToMany(mappedBy = "media", fetch = FetchType.LAZY) + private Set season; @Override public final boolean equals(Object o) { @@ -103,7 +95,7 @@ public final boolean equals(Object o) { Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); if (thisEffectiveClass != oEffectiveClass) return false; - ExternalReferenceModel that = (ExternalReferenceModel) o; + MediaModel that = (MediaModel) o; return getId() != null && Objects.equals(getId(), that.getId()); } diff --git a/src/main/java/com/espacogeek/geek/repositories/AlternativeTitlesRepository.java b/src/main/java/com/espacogeek/geek/repositories/AlternativeTitlesRepository.java index 601f2069..2d6f9752 100644 --- a/src/main/java/com/espacogeek/geek/repositories/AlternativeTitlesRepository.java +++ b/src/main/java/com/espacogeek/geek/repositories/AlternativeTitlesRepository.java @@ -1,11 +1,17 @@ package com.espacogeek.geek.repositories; +import java.util.Collection; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import com.espacogeek.geek.models.AlternativeTitleModel; +import com.espacogeek.geek.models.MediaModel; @Repository -public interface AlternativeTitlesRepository extends JpaRepository { - +public interface AlternativeTitlesRepository extends JpaRepository { + + List findByMediaIn(Collection medias); + } diff --git a/src/main/java/com/espacogeek/geek/repositories/ExternalReferenceRepository.java b/src/main/java/com/espacogeek/geek/repositories/ExternalReferenceRepository.java index 37d90128..d91ed395 100644 --- a/src/main/java/com/espacogeek/geek/repositories/ExternalReferenceRepository.java +++ b/src/main/java/com/espacogeek/geek/repositories/ExternalReferenceRepository.java @@ -1,5 +1,7 @@ package com.espacogeek.geek.repositories; +import java.util.Collection; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; @@ -15,7 +17,9 @@ public interface ExternalReferenceRepository extends JpaRepository findByMedia(MediaModel media); - java.util.List findAllByMedia(MediaModel media); + List findAllByMedia(MediaModel media); + + List findAllByMediaIn(Collection medias); boolean existsByMediaId(Integer id); } diff --git a/src/main/java/com/espacogeek/geek/repositories/MediaRepository.java b/src/main/java/com/espacogeek/geek/repositories/MediaRepository.java index b48e6b4d..81b84f0a 100644 --- a/src/main/java/com/espacogeek/geek/repositories/MediaRepository.java +++ b/src/main/java/com/espacogeek/geek/repositories/MediaRepository.java @@ -1,5 +1,7 @@ package com.espacogeek.geek.repositories; +import java.util.Collection; +import java.util.List; import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -59,4 +61,34 @@ Page findMediaByNameOrAlternativeTitleAndMediaCategory( @Query("SELECT m FROM MediaModel m JOIN ExternalReferenceModel e ON e MEMBER OF m.externalReference WHERE e.reference = :reference AND e.typeReference = :typeReference") public Optional findOneMediaByExternalReferenceAndTypeReference(@Param("reference") String reference, @Param("typeReference") TypeReferenceModel typeReference); + + /** + * Batch-loads the genre association for a collection of MediaModel entities. + * Used by @BatchMapping to resolve the N+1 problem for genres. + * + * @param medias the collection of MediaModel entities to load genres for. + * @return a list of MediaModel entities with their genre collections initialized. + */ + @Query("SELECT DISTINCT m FROM MediaModel m LEFT JOIN FETCH m.genre WHERE m IN :medias") + List findAllWithGenreByMediaIn(@Param("medias") Collection medias); + + /** + * Batch-loads the company association for a collection of MediaModel entities. + * Used by @BatchMapping to resolve the N+1 problem for companies. + * + * @param medias the collection of MediaModel entities to load companies for. + * @return a list of MediaModel entities with their company collections initialized. + */ + @Query("SELECT DISTINCT m FROM MediaModel m LEFT JOIN FETCH m.company WHERE m IN :medias") + List findAllWithCompanyByMediaIn(@Param("medias") Collection medias); + + /** + * Batch-loads the people association for a collection of MediaModel entities. + * Used by @BatchMapping to resolve the N+1 problem for people. + * + * @param medias the collection of MediaModel entities to load people for. + * @return a list of MediaModel entities with their people collections initialized. + */ + @Query("SELECT DISTINCT m FROM MediaModel m LEFT JOIN FETCH m.people WHERE m IN :medias") + List findAllWithPeopleByMediaIn(@Param("medias") Collection medias); } diff --git a/src/main/java/com/espacogeek/geek/repositories/SeasonRepository.java b/src/main/java/com/espacogeek/geek/repositories/SeasonRepository.java index 8981b5e5..5b533809 100644 --- a/src/main/java/com/espacogeek/geek/repositories/SeasonRepository.java +++ b/src/main/java/com/espacogeek/geek/repositories/SeasonRepository.java @@ -1,11 +1,17 @@ package com.espacogeek.geek.repositories; +import java.util.Collection; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import com.espacogeek.geek.models.MediaModel; import com.espacogeek.geek.models.SeasonModel; @Repository public interface SeasonRepository extends JpaRepository { + List findByMediaIn(Collection medias); + } diff --git a/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java b/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java index de9c49a0..f3b78c10 100644 --- a/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java +++ b/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java @@ -4,6 +4,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; @@ -228,8 +229,8 @@ public Optional findByIdEager(Integer id) { String getterName = "get" + capitalize(field.getName()); Method getter = media.getClass().getMethod(getterName); var fieldValue = getter.invoke(media); - if (fieldValue instanceof List) { - ((List) fieldValue).size(); // This will initialize the collection + if (fieldValue instanceof Collection) { + ((Collection) fieldValue).size(); // This will initialize the collection } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { log.error("Failed to initialize field {} for media id={}: {}", field.getName(), media.getId(), e.getMessage()); diff --git a/src/main/resources/graphql/entity/Company.graphqls b/src/main/resources/graphql/entity/Company.graphqls new file mode 100644 index 00000000..ed18195f --- /dev/null +++ b/src/main/resources/graphql/entity/Company.graphqls @@ -0,0 +1,4 @@ +type Company { + id: ID + name: String +} diff --git a/src/main/resources/graphql/entity/Media.graphqls b/src/main/resources/graphql/entity/Media.graphqls index 68d6bae1..8525211c 100644 --- a/src/main/resources/graphql/entity/Media.graphqls +++ b/src/main/resources/graphql/entity/Media.graphqls @@ -20,6 +20,10 @@ type Media { mediaCategory: MediaCategory "List of genres" genre: [Genre] + "Companies involved in production" + company: [Company] + "People involved (cast, crew, etc.)" + people: [People] "External references (IMDB, IGDB, VNDB, etc.)" externalReference: [ExternalReference] "Alternative titles in different languages" diff --git a/src/main/resources/graphql/entity/People.graphqls b/src/main/resources/graphql/entity/People.graphqls new file mode 100644 index 00000000..c431df85 --- /dev/null +++ b/src/main/resources/graphql/entity/People.graphqls @@ -0,0 +1,5 @@ +type People { + id: ID + name: String + typePerson: TypePerson +} diff --git a/src/test/java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java b/src/test/java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java index 859ca7a9..a4eb350f 100644 --- a/src/test/java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java +++ b/src/test/java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java @@ -19,6 +19,10 @@ import com.espacogeek.geek.controllers.DailyQuoteArtworkController; import com.espacogeek.geek.controllers.MediaController; import com.espacogeek.geek.models.DailyQuoteArtworkModel; +import com.espacogeek.geek.repositories.AlternativeTitlesRepository; +import com.espacogeek.geek.repositories.ExternalReferenceRepository; +import com.espacogeek.geek.repositories.MediaRepository; +import com.espacogeek.geek.repositories.SeasonRepository; import com.espacogeek.geek.services.DailyQuoteArtworkService; import com.espacogeek.geek.services.MediaService; import com.espacogeek.geek.services.impl.UserDetailsServiceImpl; @@ -88,6 +92,19 @@ RuntimeWiringConfigurer dateScalarConfigurer() { @MockitoBean private MediaService mediaService; + @MockitoBean + private SeasonRepository seasonRepository; + + @MockitoBean + private AlternativeTitlesRepository alternativeTitlesRepository; + + @SuppressWarnings("rawtypes") + @MockitoBean + private ExternalReferenceRepository externalReferenceRepository; + + @MockitoBean + private MediaRepository mediaRepository; + @MockitoBean private UserDetailsServiceImpl userDetailsService; diff --git a/src/test/java/com/espacogeek/geek/query/media/AnimeQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/AnimeQueryTest.java index 2cfc2067..8b4b389a 100644 --- a/src/test/java/com/espacogeek/geek/query/media/AnimeQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/AnimeQueryTest.java @@ -20,6 +20,10 @@ import com.espacogeek.geek.controllers.MediaController; import com.espacogeek.geek.data.MediaDataController; import com.espacogeek.geek.models.MediaModel; +import com.espacogeek.geek.repositories.AlternativeTitlesRepository; +import com.espacogeek.geek.repositories.ExternalReferenceRepository; +import com.espacogeek.geek.repositories.MediaRepository; +import com.espacogeek.geek.repositories.SeasonRepository; import com.espacogeek.geek.services.MediaCategoryService; import com.espacogeek.geek.services.MediaService; import com.espacogeek.geek.services.TypeReferenceService; @@ -48,6 +52,19 @@ public class AnimeQueryTest { @MockitoBean private MediaCategoryService mediaCategoryService; + @MockitoBean + private SeasonRepository seasonRepository; + + @MockitoBean + private AlternativeTitlesRepository alternativeTitlesRepository; + + @SuppressWarnings("rawtypes") + @MockitoBean + private ExternalReferenceRepository externalReferenceRepository; + + @MockitoBean + private MediaRepository mediaRepository; + @Test void anime_NoParameters_ShouldReturnEmptyPage() { // When & Then diff --git a/src/test/java/com/espacogeek/geek/query/media/GameQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/GameQueryTest.java index 1ed142ef..70ef11fa 100644 --- a/src/test/java/com/espacogeek/geek/query/media/GameQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/GameQueryTest.java @@ -21,6 +21,10 @@ import com.espacogeek.geek.models.MediaCategoryModel; import com.espacogeek.geek.models.MediaModel; import com.espacogeek.geek.models.TypeReferenceModel; +import com.espacogeek.geek.repositories.AlternativeTitlesRepository; +import com.espacogeek.geek.repositories.ExternalReferenceRepository; +import com.espacogeek.geek.repositories.MediaRepository; +import com.espacogeek.geek.repositories.SeasonRepository; import com.espacogeek.geek.services.MediaCategoryService; import com.espacogeek.geek.services.MediaService; import com.espacogeek.geek.services.TypeReferenceService; @@ -51,6 +55,19 @@ class GameQueryTest { @MockitoBean private MediaCategoryService mediaCategoryService; + @MockitoBean + private SeasonRepository seasonRepository; + + @MockitoBean + private AlternativeTitlesRepository alternativeTitlesRepository; + + @SuppressWarnings("rawtypes") + @MockitoBean + private ExternalReferenceRepository externalReferenceRepository; + + @MockitoBean + private MediaRepository mediaRepository; + @Test void game_NoParameters_ShouldReturnEmptyPage() { // When & Then diff --git a/src/test/java/com/espacogeek/geek/query/media/MediaQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/MediaQueryTest.java index 60afed3f..c5ab6854 100644 --- a/src/test/java/com/espacogeek/geek/query/media/MediaQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/MediaQueryTest.java @@ -18,6 +18,10 @@ import com.espacogeek.geek.data.api.MediaApi; import com.espacogeek.geek.models.MediaCategoryModel; import com.espacogeek.geek.models.MediaModel; +import com.espacogeek.geek.repositories.AlternativeTitlesRepository; +import com.espacogeek.geek.repositories.ExternalReferenceRepository; +import com.espacogeek.geek.repositories.MediaRepository; +import com.espacogeek.geek.repositories.SeasonRepository; import com.espacogeek.geek.services.MediaCategoryService; import com.espacogeek.geek.services.MediaService; import com.espacogeek.geek.services.TypeReferenceService; @@ -47,6 +51,19 @@ class MediaQueryTest { @MockitoBean private MediaCategoryService mediaCategoryService; + @MockitoBean + private SeasonRepository seasonRepository; + + @MockitoBean + private AlternativeTitlesRepository alternativeTitlesRepository; + + @SuppressWarnings("rawtypes") + @MockitoBean + private ExternalReferenceRepository externalReferenceRepository; + + @MockitoBean + private MediaRepository mediaRepository; + @Test void media_NotFound_ShouldReturnError() { // Given diff --git a/src/test/java/com/espacogeek/geek/query/media/MovieQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/MovieQueryTest.java index 75c499de..e433ad22 100644 --- a/src/test/java/com/espacogeek/geek/query/media/MovieQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/MovieQueryTest.java @@ -21,6 +21,10 @@ import com.espacogeek.geek.data.MediaDataController; import com.espacogeek.geek.data.api.MediaApi; import com.espacogeek.geek.models.MediaModel; +import com.espacogeek.geek.repositories.AlternativeTitlesRepository; +import com.espacogeek.geek.repositories.ExternalReferenceRepository; +import com.espacogeek.geek.repositories.MediaRepository; +import com.espacogeek.geek.repositories.SeasonRepository; import com.espacogeek.geek.services.MediaCategoryService; import com.espacogeek.geek.services.MediaService; import com.espacogeek.geek.services.TypeReferenceService; @@ -48,6 +52,19 @@ public class MovieQueryTest { @MockitoBean private MediaCategoryService mediaCategoryService; + @MockitoBean + private SeasonRepository seasonRepository; + + @MockitoBean + private AlternativeTitlesRepository alternativeTitlesRepository; + + @SuppressWarnings("rawtypes") + @MockitoBean + private ExternalReferenceRepository externalReferenceRepository; + + @MockitoBean + private MediaRepository mediaRepository; + @Test void movie_NoParameters_ShouldReturnEmptyPage() { // When & Then diff --git a/src/test/java/com/espacogeek/geek/query/media/TvSerieQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/TvSerieQueryTest.java index cbba1765..9a6c205c 100644 --- a/src/test/java/com/espacogeek/geek/query/media/TvSerieQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/TvSerieQueryTest.java @@ -18,6 +18,10 @@ import com.espacogeek.geek.controllers.MediaController; import com.espacogeek.geek.data.MediaDataController; +import com.espacogeek.geek.repositories.AlternativeTitlesRepository; +import com.espacogeek.geek.repositories.ExternalReferenceRepository; +import com.espacogeek.geek.repositories.MediaRepository; +import com.espacogeek.geek.repositories.SeasonRepository; import com.espacogeek.geek.services.MediaCategoryService; import com.espacogeek.geek.services.MediaService; import com.espacogeek.geek.services.TypeReferenceService; @@ -46,6 +50,19 @@ class TvSerieQueryTest { @MockitoBean private MediaCategoryService mediaCategoryService; + @MockitoBean + private SeasonRepository seasonRepository; + + @MockitoBean + private AlternativeTitlesRepository alternativeTitlesRepository; + + @SuppressWarnings("rawtypes") + @MockitoBean + private ExternalReferenceRepository externalReferenceRepository; + + @MockitoBean + private MediaRepository mediaRepository; + private MediaPage stubMediaPage() { MediaSimplefied item = new MediaSimplefied(); item.setId(1); diff --git a/src/test/java/com/espacogeek/geek/query/media/VisualNovelQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/VisualNovelQueryTest.java index 082a952d..cacac139 100644 --- a/src/test/java/com/espacogeek/geek/query/media/VisualNovelQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/VisualNovelQueryTest.java @@ -21,6 +21,10 @@ import com.espacogeek.geek.models.MediaCategoryModel; import com.espacogeek.geek.models.MediaModel; import com.espacogeek.geek.models.TypeReferenceModel; +import com.espacogeek.geek.repositories.AlternativeTitlesRepository; +import com.espacogeek.geek.repositories.ExternalReferenceRepository; +import com.espacogeek.geek.repositories.MediaRepository; +import com.espacogeek.geek.repositories.SeasonRepository; import com.espacogeek.geek.services.MediaCategoryService; import com.espacogeek.geek.services.MediaService; import com.espacogeek.geek.services.TypeReferenceService; @@ -51,6 +55,19 @@ class VisualNovelQueryTest { @MockitoBean private MediaCategoryService mediaCategoryService; + @MockitoBean + private SeasonRepository seasonRepository; + + @MockitoBean + private AlternativeTitlesRepository alternativeTitlesRepository; + + @SuppressWarnings("rawtypes") + @MockitoBean + private ExternalReferenceRepository externalReferenceRepository; + + @MockitoBean + private MediaRepository mediaRepository; + @Test void vn_NoParameters_ShouldReturnEmptyPage() { // When & Then diff --git a/src/test/java/com/espacogeek/geek/services/MediaServiceImplTest.java b/src/test/java/com/espacogeek/geek/services/MediaServiceImplTest.java index 303ef0ac..597ce04d 100644 --- a/src/test/java/com/espacogeek/geek/services/MediaServiceImplTest.java +++ b/src/test/java/com/espacogeek/geek/services/MediaServiceImplTest.java @@ -9,7 +9,9 @@ import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import jakarta.validation.ValidationException; import org.junit.jupiter.api.Test; @@ -63,7 +65,7 @@ void save_WithInMemoryExternalReference_ShouldPersist() { MediaModel media = new MediaModel(); media.setName("Inception"); ExternalReferenceModel ref = new ExternalReferenceModel(); - media.setExternalReference(List.of(ref)); + media.setExternalReference(new HashSet<>(List.of(ref))); when(mediaRepository.save(media)).thenReturn(media); // When @@ -94,7 +96,7 @@ void save_WithEmptyExternalReferenceListAndNoId_ShouldThrowValidationException() // Given MediaModel media = new MediaModel(); media.setName("Unknown"); - media.setExternalReference(new ArrayList<>()); + media.setExternalReference(new HashSet<>()); // When & Then assertThatThrownBy(() -> mediaService.save(media)) @@ -146,11 +148,11 @@ void saveAll_AllWithExternalReferences_ShouldSaveAll() { // Given MediaModel media1 = new MediaModel(); media1.setName("Movie A"); - media1.setExternalReference(List.of(new ExternalReferenceModel())); + media1.setExternalReference(new HashSet<>(List.of(new ExternalReferenceModel()))); MediaModel media2 = new MediaModel(); media2.setName("Movie B"); - media2.setExternalReference(List.of(new ExternalReferenceModel())); + media2.setExternalReference(new HashSet<>(List.of(new ExternalReferenceModel()))); List input = List.of(media1, media2); when(mediaRepository.saveAll(input)).thenReturn(input); @@ -168,7 +170,7 @@ void saveAll_SomeWithoutExternalReferences_ShouldSkipInvalidAndSaveValid() { // Given MediaModel valid = new MediaModel(); valid.setName("Valid Movie"); - valid.setExternalReference(List.of(new ExternalReferenceModel())); + valid.setExternalReference(new HashSet<>(List.of(new ExternalReferenceModel()))); MediaModel invalid = new MediaModel(); invalid.setName("No Ref Movie"); @@ -194,7 +196,7 @@ void saveAll_AllWithoutExternalReferences_ShouldReturnEmptyListWithoutCallingRep MediaModel media2 = new MediaModel(); media2.setName("No Ref B"); - media2.setExternalReference(new ArrayList<>()); + media2.setExternalReference(new HashSet<>()); // When List result = mediaService.saveAll(List.of(media1, media2)); From 4480edfbbfacc1a3b48d924744d781cb61fbde38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:50:25 +0000 Subject: [PATCH 03/12] Address code review: descriptive exception message, remove unnecessary cast Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com> --- .../com/espacogeek/geek/controllers/MediaController.java | 6 +++--- .../geek/data/impl/GenericMediaDataControllerImpl.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/espacogeek/geek/controllers/MediaController.java b/src/main/java/com/espacogeek/geek/controllers/MediaController.java index 2ae22572..01df6b49 100644 --- a/src/main/java/com/espacogeek/geek/controllers/MediaController.java +++ b/src/main/java/com/espacogeek/geek/controllers/MediaController.java @@ -36,8 +36,7 @@ public class MediaController { private final SeasonRepository seasonRepository; private final AlternativeTitlesRepository alternativeTitlesRepository; @SuppressWarnings("rawtypes") - private final ExternalReferenceRepository externalReferenceRepository; - private final MediaRepository mediaRepository; + private final ExternalReferenceRepository externalReferenceRepository; private final MediaRepository mediaRepository; /** * Finds a MediaModel object by its ID. @@ -229,7 +228,8 @@ public Map> externalReference(List m)); Map> result = medias.stream() .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); - for (ExternalReferenceModel ref : (List) externalReferenceRepository.findAllByMediaIn(medias)) { + List refs = externalReferenceRepository.findAllByMediaIn(medias); + for (ExternalReferenceModel ref : refs) { MediaModel source = sourceById.get(ref.getMedia().getId()); if (source != null) { result.get(source).add(ref); diff --git a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java index 4917aaf5..285aaef2 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java @@ -285,7 +285,7 @@ public List searchMedia(String search, MediaApi mediaApi, TypeRefere result.add(media); } catch (MediaAlreadyExist e) { - media = mediaService.findByReferenceAndTypeReference(mediaSearch.getExternalReference().iterator().next(), typeReference).orElseThrow(); + media = mediaService.findByReferenceAndTypeReference(mediaSearch.getExternalReference().iterator().next(), typeReference).orElseThrow(() -> new com.espacogeek.geek.exception.GenericException("Media not found for the given external reference")); result.add(media); } From 1b8643160a8a92b3f1e026cc7447249ecef75809 Mon Sep 17 00:00:00 2001 From: Vitor Hugo Date: Fri, 20 Mar 2026 09:07:53 -0300 Subject: [PATCH 04/12] Update src/main/java/com/espacogeek/geek/controllers/MediaController.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../java/com/espacogeek/geek/controllers/MediaController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/espacogeek/geek/controllers/MediaController.java b/src/main/java/com/espacogeek/geek/controllers/MediaController.java index 01df6b49..0a79002d 100644 --- a/src/main/java/com/espacogeek/geek/controllers/MediaController.java +++ b/src/main/java/com/espacogeek/geek/controllers/MediaController.java @@ -35,8 +35,8 @@ public class MediaController { private final MediaService mediaService; private final SeasonRepository seasonRepository; private final AlternativeTitlesRepository alternativeTitlesRepository; - @SuppressWarnings("rawtypes") - private final ExternalReferenceRepository externalReferenceRepository; private final MediaRepository mediaRepository; + private final ExternalReferenceRepository externalReferenceRepository; + private final MediaRepository mediaRepository; /** * Finds a MediaModel object by its ID. From 0920d8f98623628fbf15ab4b546d1beb7d07a499 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 12:11:44 +0000 Subject: [PATCH 05/12] Fix duplicate key crash in @BatchMapping methods by using loop-based map building Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com> --- .../geek/controllers/MediaController.java | 73 ++++++++++++------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/espacogeek/geek/controllers/MediaController.java b/src/main/java/com/espacogeek/geek/controllers/MediaController.java index 0a79002d..d23af338 100644 --- a/src/main/java/com/espacogeek/geek/controllers/MediaController.java +++ b/src/main/java/com/espacogeek/geek/controllers/MediaController.java @@ -28,7 +28,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; @Controller @RequiredArgsConstructor public class MediaController { @@ -151,10 +150,14 @@ public MediaPage getAnime(@Argument(name = "id") Integer id, @Argument(name = "n */ @BatchMapping public Map> season(List medias) { - Map sourceById = medias.stream() - .collect(Collectors.toMap(MediaModel::getId, m -> m)); - Map> result = medias.stream() - .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + Map sourceById = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + sourceById.putIfAbsent(m.getId(), m); + } + Map> result = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + result.putIfAbsent(m, new HashSet<>()); + } for (SeasonModel season : seasonRepository.findByMediaIn(medias)) { MediaModel source = sourceById.get(season.getMedia().getId()); if (source != null) { @@ -169,10 +172,14 @@ public Map> season(List medias) { */ @BatchMapping public Map> genre(List medias) { - Map sourceById = medias.stream() - .collect(Collectors.toMap(MediaModel::getId, m -> m)); - Map> result = medias.stream() - .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + Map sourceById = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + sourceById.putIfAbsent(m.getId(), m); + } + Map> result = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + result.putIfAbsent(m, new HashSet<>()); + } for (MediaModel loaded : mediaRepository.findAllWithGenreByMediaIn(medias)) { MediaModel source = sourceById.get(loaded.getId()); if (source != null && loaded.getGenre() != null) { @@ -187,10 +194,14 @@ public Map> genre(List medias) { */ @BatchMapping public Map> company(List medias) { - Map sourceById = medias.stream() - .collect(Collectors.toMap(MediaModel::getId, m -> m)); - Map> result = medias.stream() - .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + Map sourceById = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + sourceById.putIfAbsent(m.getId(), m); + } + Map> result = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + result.putIfAbsent(m, new HashSet<>()); + } for (MediaModel loaded : mediaRepository.findAllWithCompanyByMediaIn(medias)) { MediaModel source = sourceById.get(loaded.getId()); if (source != null && loaded.getCompany() != null) { @@ -205,10 +216,14 @@ public Map> company(List medias) { */ @BatchMapping public Map> people(List medias) { - Map sourceById = medias.stream() - .collect(Collectors.toMap(MediaModel::getId, m -> m)); - Map> result = medias.stream() - .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + Map sourceById = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + sourceById.putIfAbsent(m.getId(), m); + } + Map> result = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + result.putIfAbsent(m, new HashSet<>()); + } for (MediaModel loaded : mediaRepository.findAllWithPeopleByMediaIn(medias)) { MediaModel source = sourceById.get(loaded.getId()); if (source != null && loaded.getPeople() != null) { @@ -224,10 +239,14 @@ public Map> people(List medias) { @BatchMapping @SuppressWarnings("unchecked") public Map> externalReference(List medias) { - Map sourceById = medias.stream() - .collect(Collectors.toMap(MediaModel::getId, m -> m)); - Map> result = medias.stream() - .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + Map sourceById = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + sourceById.putIfAbsent(m.getId(), m); + } + Map> result = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + result.putIfAbsent(m, new HashSet<>()); + } List refs = externalReferenceRepository.findAllByMediaIn(medias); for (ExternalReferenceModel ref : refs) { MediaModel source = sourceById.get(ref.getMedia().getId()); @@ -243,10 +262,14 @@ public Map> externalReference(List> alternativeTitles(List medias) { - Map sourceById = medias.stream() - .collect(Collectors.toMap(MediaModel::getId, m -> m)); - Map> result = medias.stream() - .collect(Collectors.toMap(m -> m, m -> new HashSet<>())); + Map sourceById = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + sourceById.putIfAbsent(m.getId(), m); + } + Map> result = new java.util.LinkedHashMap<>(); + for (MediaModel m : medias) { + result.putIfAbsent(m, new HashSet<>()); + } for (AlternativeTitleModel alt : alternativeTitlesRepository.findByMediaIn(medias)) { MediaModel source = sourceById.get(alt.getMedia().getId()); if (source != null) { From b146d2a8d48d6ed7ad5159c58e60fe50279cbae4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 12:16:57 +0000 Subject: [PATCH 06/12] Fix NPE in updateGenres/updateSeason; remove unused generic from ExternalReferenceRepository Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com> --- .../com/espacogeek/geek/controllers/MediaController.java | 3 +-- .../geek/data/impl/GenericMediaDataControllerImpl.java | 8 ++++++++ .../geek/repositories/ExternalReferenceRepository.java | 2 +- .../geek/services/impl/ExternalReferenceServiceImpl.java | 8 +------- .../espacogeek/geek/services/impl/MediaServiceImpl.java | 2 -- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/espacogeek/geek/controllers/MediaController.java b/src/main/java/com/espacogeek/geek/controllers/MediaController.java index d23af338..97ef93a1 100644 --- a/src/main/java/com/espacogeek/geek/controllers/MediaController.java +++ b/src/main/java/com/espacogeek/geek/controllers/MediaController.java @@ -34,7 +34,7 @@ public class MediaController { private final MediaService mediaService; private final SeasonRepository seasonRepository; private final AlternativeTitlesRepository alternativeTitlesRepository; - private final ExternalReferenceRepository externalReferenceRepository; + private final ExternalReferenceRepository externalReferenceRepository; private final MediaRepository mediaRepository; /** @@ -237,7 +237,6 @@ public Map> people(List medias) { * Batch-loads external references for a list of MediaModel sources, resolving the N+1 problem. */ @BatchMapping - @SuppressWarnings("unchecked") public Map> externalReference(List medias) { Map sourceById = new java.util.LinkedHashMap<>(); for (MediaModel m : medias) { diff --git a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java index 285aaef2..eb001c01 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java @@ -219,6 +219,10 @@ public List updateGenres(MediaModel media, MediaModel result, TypeRe if (CollectionUtils.isEmpty(rawGenres)) return media.getGenre() != null ? new ArrayList<>(media.getGenre()) : new ArrayList<>(); + if (media.getGenre() == null) { + media.setGenre(new LinkedHashSet<>()); + } + rawGenres.forEach((rawGenre) -> { if (media.getGenre().stream().noneMatch((genre) -> genre.getId().equals(rawGenre.getId()))) { rawGenre.setMedias(new ArrayList<>(List.of(media))); @@ -247,6 +251,10 @@ public List updateSeason(MediaModel media, MediaModel result, TypeR if (CollectionUtils.isEmpty(rawSeasons)) return media.getSeason() != null ? new ArrayList<>(media.getSeason()) : new ArrayList<>(); + if (media.getSeason() == null) { + media.setSeason(new LinkedHashSet<>()); + } + rawSeasons.forEach((rawSeason) -> { if (media.getSeason().stream().noneMatch((season) -> season.getName().equals(rawSeason.getName()))) { seasons.add(new SeasonModel(null, rawSeason.getName(), rawSeason.getAirDate(), null, rawSeason.getAbout(), rawSeason.getCover(), rawSeason.getSeasonNumber(), rawSeason.getEpisodeCount(), media)); diff --git a/src/main/java/com/espacogeek/geek/repositories/ExternalReferenceRepository.java b/src/main/java/com/espacogeek/geek/repositories/ExternalReferenceRepository.java index d91ed395..dfc233c2 100644 --- a/src/main/java/com/espacogeek/geek/repositories/ExternalReferenceRepository.java +++ b/src/main/java/com/espacogeek/geek/repositories/ExternalReferenceRepository.java @@ -12,7 +12,7 @@ import com.espacogeek.geek.models.TypeReferenceModel; @Repository -public interface ExternalReferenceRepository extends JpaRepository { +public interface ExternalReferenceRepository extends JpaRepository { Optional findByReferenceAndTypeReference (String reference, TypeReferenceModel typeReference); Optional findByMedia(MediaModel media); diff --git a/src/main/java/com/espacogeek/geek/services/impl/ExternalReferenceServiceImpl.java b/src/main/java/com/espacogeek/geek/services/impl/ExternalReferenceServiceImpl.java index 18bf8c48..0148b298 100644 --- a/src/main/java/com/espacogeek/geek/services/impl/ExternalReferenceServiceImpl.java +++ b/src/main/java/com/espacogeek/geek/services/impl/ExternalReferenceServiceImpl.java @@ -18,14 +18,12 @@ @Service public class ExternalReferenceServiceImpl implements ExternalReferenceService { - @SuppressWarnings("rawtypes") @Autowired private ExternalReferenceRepository externalReferenceRepository; /** * @see ExternalReferenceService#findAll(MediaModel) */ - @SuppressWarnings("unchecked") @Override public List findAll(MediaModel media) { return this.externalReferenceRepository.findAllByMedia(media); @@ -34,7 +32,6 @@ public List findAll(MediaModel media) { /** * @see ExternalReferenceService#findById(Integer) */ - @SuppressWarnings("unchecked") @Override public Optional findById(Integer id) { return this.externalReferenceRepository.findById(id); @@ -43,16 +40,14 @@ public Optional findById(Integer id) { /** * @see ExternalReferenceService#save(ExternalReferenceModel) */ - @SuppressWarnings("unchecked") @Override public ExternalReferenceModel save(ExternalReferenceModel externalReference) { - return (ExternalReferenceModel) this.externalReferenceRepository.save(externalReference); + return this.externalReferenceRepository.save(externalReference); } /** * @see ExternalReferenceService#saveAll(List) */ - @SuppressWarnings("unchecked") @Override public List saveAll(List externalReferences) { return this.externalReferenceRepository.saveAll(externalReferences); @@ -61,7 +56,6 @@ public List saveAll(List externa /** * @see ExternalReferenceService#findByIdAndType(Integer, TypeReferenceModel) */ - @SuppressWarnings("unchecked") @Override public Optional findByReferenceAndType(String reference, TypeReferenceModel typeReference) { return this.externalReferenceRepository.findByReferenceAndTypeReference(reference, typeReference); diff --git a/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java b/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java index f3b78c10..e09d31bb 100644 --- a/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java +++ b/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java @@ -46,10 +46,8 @@ public class MediaServiceImpl implements MediaService { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MediaServiceImpl.class); - @SuppressWarnings("rawtypes") private final MediaRepository mediaRepository; - @SuppressWarnings("rawtypes") private final ExternalReferenceRepository externalsRepo; private final MediaCategoryService mediaCategoryService; From dddb4ff96954a7c4d139b7fb560d97ec53699f37 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 12:41:44 +0000 Subject: [PATCH 07/12] Fix all 43 Qodana static analysis warnings Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com> --- .../com/espacogeek/geek/config/JwtConfig.java | 3 +-- .../geek/controllers/MediaController.java | 13 ++++++------- .../geek/controllers/UserController.java | 10 +++++----- .../geek/data/api/impl/MovieAPIImpl.java | 18 +++++++----------- .../geek/data/api/impl/QuoteApiImpl.java | 14 +++----------- .../geek/data/api/impl/TvSeriesApiImpl.java | 18 +++++++----------- .../impl/GenericMediaDataControllerImpl.java | 5 +---- .../geek/data/impl/MovieControllerImpl.java | 5 ----- .../geek/data/impl/SerieControllerImpl.java | 5 ----- .../metrics/GraphQLMetricsInstrumentation.java | 2 +- .../geek/services/impl/ApiKeyServiceImpl.java | 2 +- .../geek/services/impl/MediaServiceImpl.java | 7 +++---- .../services/impl/UserDetailsServiceImpl.java | 3 +-- .../com/espacogeek/geek/utils/MediaUtils.java | 6 +++--- 14 files changed, 39 insertions(+), 72 deletions(-) diff --git a/src/main/java/com/espacogeek/geek/config/JwtConfig.java b/src/main/java/com/espacogeek/geek/config/JwtConfig.java index 2136db22..0fe5e335 100644 --- a/src/main/java/com/espacogeek/geek/config/JwtConfig.java +++ b/src/main/java/com/espacogeek/geek/config/JwtConfig.java @@ -79,8 +79,7 @@ private List buildRolesList(UserModel user) { if (raw != null && !raw.isBlank()) { String[] parts = raw.replaceAll("\\s", "").split(","); rolesList.addAll(Arrays.stream(parts) - .map(s -> s == null ? null : s.trim()) - .filter(s -> s != null && !s.isBlank()) + .filter(s -> !s.isBlank()) .map(s -> { if (s.startsWith("ROLE_") || s.startsWith("ID_")) return s; return "ROLE_" + s; diff --git a/src/main/java/com/espacogeek/geek/controllers/MediaController.java b/src/main/java/com/espacogeek/geek/controllers/MediaController.java index 97ef93a1..7241364b 100644 --- a/src/main/java/com/espacogeek/geek/controllers/MediaController.java +++ b/src/main/java/com/espacogeek/geek/controllers/MediaController.java @@ -62,7 +62,7 @@ public MediaModel getMediaById(@Argument(name = "id") Integer id) { public MediaPage getMovie(@Argument(name = "id") Integer id, @Argument(name = "name") String name, DataFetchingEnvironment dataFetchingEnvironment) { name = name == null ? null : name.trim(); - if (name == null && id == null || name == "" && id == null) { + if (id == null && (name == null || name.isEmpty())) { return new MediaPage(); } @@ -81,7 +81,7 @@ public MediaPage getMovie(@Argument(name = "id") Integer id, @Argument(name = "n public MediaPage getSerie(@Argument(name = "id") Integer id, @Argument(name = "name") String name, DataFetchingEnvironment dataFetchingEnvironment) { name = name == null ? null : name.trim(); - if (name == null && id == null || name == "" && id == null) { + if (id == null && (name == null || name.isEmpty())) { return new MediaPage(); } @@ -100,7 +100,7 @@ public MediaPage getSerie(@Argument(name = "id") Integer id, @Argument(name = "n public MediaPage getGame(@Argument(name = "id") Integer id, @Argument(name = "name") String name, DataFetchingEnvironment dataFetchingEnvironment) { name = name == null ? null : name.trim(); - if (name == null && id == null || name == "" && id == null) { + if (id == null && (name == null || name.isEmpty())) { return new MediaPage(); } @@ -117,11 +117,10 @@ public MediaPage getGame(@Argument(name = "id") Integer id, @Argument(name = "na */ @QueryMapping(name = "vn") public MediaPage getVisualNovel(@Argument(name = "id") Integer id, @Argument(name = "name") String name, DataFetchingEnvironment dataFetchingEnvironment) { - MediaPage response = new MediaPage(); name = name == null ? null : name.trim(); - if (name == null && id == null || name == "" && id == null) { - return response; + if (id == null && (name == null || name.isEmpty())) { + return new MediaPage(); } return this.mediaService.findVisualNovelByIdOrName(id, name, MediaUtils.getPageable(dataFetchingEnvironment)); @@ -138,7 +137,7 @@ public MediaPage getVisualNovel(@Argument(name = "id") Integer id, @Argument(nam public MediaPage getAnime(@Argument(name = "id") Integer id, @Argument(name = "name") String name, DataFetchingEnvironment dataFetchingEnvironment) { name = name == null ? null : name.trim(); - if (name == null && id == null || name == "" && id == null) { + if (id == null && (name == null || name.isEmpty())) { return new MediaPage(); } diff --git a/src/main/java/com/espacogeek/geek/controllers/UserController.java b/src/main/java/com/espacogeek/geek/controllers/UserController.java index 47846f18..69b0ff4c 100644 --- a/src/main/java/com/espacogeek/geek/controllers/UserController.java +++ b/src/main/java/com/espacogeek/geek/controllers/UserController.java @@ -183,7 +183,7 @@ public String editPasswordUserLogged(Authentication authentication, @Argument(na Integer userId = UserUtils.getUserID(authentication); - UserModel userLogged = userService.findById(Integer.valueOf(userId)).get(); + UserModel userLogged = userService.findById(userId).orElseThrow(() -> new GenericException(HttpStatus.NOT_FOUND.toString())); boolean resultPassword = BCrypt.verifyer().verify(actualPassword.toCharArray(), userLogged.getPassword()).verified; if (resultPassword) { @@ -205,11 +205,11 @@ public String deleteUserLogged(Authentication authentication, @Argument(name = " Integer userId = UserUtils.getUserID(authentication); - UserModel userLogged = userService.findById(userId).get(); + UserModel userLogged = userService.findById(userId).orElseThrow(() -> new GenericException(HttpStatus.NOT_FOUND.toString())); boolean resultPassword = BCrypt.verifyer().verify(password.toCharArray(), userLogged.getPassword()).verified; if (resultPassword) { - userService.deleteById(Integer.valueOf(userId)); + userService.deleteById(userId); return HttpStatus.OK.toString(); } @@ -222,7 +222,7 @@ public String editUsernameUserLogged(Authentication authentication, @Argument(na Integer userId = UserUtils.getUserID(authentication); - UserModel userLogged = userService.findById(userId).get(); + UserModel userLogged = userService.findById(userId).orElseThrow(() -> new GenericException(HttpStatus.NOT_FOUND.toString())); boolean resultPassword = BCrypt.verifyer().verify(password.toCharArray(), userLogged.getPassword()).verified; if (resultPassword) { @@ -240,7 +240,7 @@ public String editEmailUserLogged(Authentication authentication, @Argument(name Integer userId = UserUtils.getUserID(authentication); - UserModel userLogged = userService.findById(userId).get(); + UserModel userLogged = userService.findById(userId).orElseThrow(() -> new GenericException(HttpStatus.NOT_FOUND.toString())); boolean resultPassword = BCrypt.verifyer().verify(password.toCharArray(), userLogged.getPassword()).verified; if (resultPassword) { diff --git a/src/main/java/com/espacogeek/geek/data/api/impl/MovieAPIImpl.java b/src/main/java/com/espacogeek/geek/data/api/impl/MovieAPIImpl.java index 43b679f2..1e7c449c 100644 --- a/src/main/java/com/espacogeek/geek/data/api/impl/MovieAPIImpl.java +++ b/src/main/java/com/espacogeek/geek/data/api/impl/MovieAPIImpl.java @@ -77,7 +77,7 @@ public InputStream updateTitlesStream() { @Retryable(maxAttempts = 2, backoff = @Backoff(delay = 2000), retryFor = com.espacogeek.geek.exception.RequestException.class) @Override public MediaModel getDetails(Integer id) { - MovieDb movieDb = new MovieDb(); + MovieDb movieDb; try { movieDb = api.getDetails(id, "en-US", MovieAppendToResponse.EXTERNAL_IDS, MovieAppendToResponse.ALTERNATIVE_TITLES, MovieAppendToResponse.IMAGES, MovieAppendToResponse.VIDEOS); } catch (TmdbException e) { @@ -111,9 +111,7 @@ public MediaModel getDetails(Integer id) { } public ExternalReferenceModel getTrailer(MovieDb movieDb) { - ExternalReferenceModel trailers = null; - - trailers = movieDb.getVideos().getResults().stream().filter(video -> video.getType().equals("Trailer")) + ExternalReferenceModel trailers = movieDb.getVideos().getResults().stream().filter(video -> video.getType().equals("Trailer")) .findFirst().map(video -> new ExternalReferenceModel(null, video.getKey(), null, typeReferenceService.findById(MediaDataController.ExternalReferenceType.YT.getId()).get())) .orElse(null); @@ -125,7 +123,7 @@ public ExternalReferenceModel getTrailer(MovieDb movieDb) { */ @Override public MediaModel getArtwork(Integer id) { - Images rawArtwork = new Images(); + Images rawArtwork; try { rawArtwork = api.getImages(id, "en"); } catch (TmdbException e) { @@ -160,7 +158,7 @@ public List getKeyword(Integer id) { @Override @Retryable(maxAttempts = 2, backoff = @Backoff(delay = 2000), retryFor = com.espacogeek.geek.exception.RequestException.class) public List getAlternativeTitles(Integer id) { - List rawAlternativeTitles = new ArrayList<>(); + List rawAlternativeTitles; try { rawAlternativeTitles = api.getAlternativeTitles(id, "us").getTitles(); } catch (TmdbException e) { @@ -186,7 +184,7 @@ private List formatAlternativeTitles(List getExternalReference(Integer id) { - ExternalIds rawExternalReferences = new ExternalIds(); + ExternalIds rawExternalReferences; try { rawExternalReferences = api.getExternalIds(id); } catch (TmdbException e) { @@ -214,7 +212,7 @@ private List formatExternalReference(ExternalIds rawExte @Override @Retryable(maxAttempts = 2, backoff = @Backoff(delay = 2000), retryFor = com.espacogeek.geek.exception.RequestException.class) public List getGenre(Integer id) { - MovieDb movieDb = new MovieDb(); + MovieDb movieDb; try { movieDb = api.getDetails(id, "en-US"); } catch (TmdbException e) { @@ -237,9 +235,7 @@ private List formatGenre(List rawGenres) { var genre = rawStringGenres.get(i); if (genre.contains("&")) { for (String genreDivided : genre.split("&")) { - genreDivided.replace("&", ""); - genreDivided = genreDivided.strip(); - newRawGenres.add(genreDivided); + newRawGenres.add(genreDivided.strip()); } } } diff --git a/src/main/java/com/espacogeek/geek/data/api/impl/QuoteApiImpl.java b/src/main/java/com/espacogeek/geek/data/api/impl/QuoteApiImpl.java index c624affe..01dd1d3f 100644 --- a/src/main/java/com/espacogeek/geek/data/api/impl/QuoteApiImpl.java +++ b/src/main/java/com/espacogeek/geek/data/api/impl/QuoteApiImpl.java @@ -49,7 +49,7 @@ public void init() { @Override public QuoteModel getRandomQuote() { var client = new OkHttpClient().newBuilder().build(); - Request request = null; + Request request; try { request = new Request.Builder() .url(URL_QUOTE) @@ -62,21 +62,13 @@ public QuoteModel getRandomQuote() { throw new GenericException("Quote not found"); } - Response response = null; - try { - response = client.newCall(request).execute(); - } catch (IOException e) { - log.error("Error executing request for Quote API: {}", e.getMessage()); - throw new GenericException("Quote not found"); - } - var parser = new JSONParser(); var jsonArray = new JSONArray(); - try { + try (Response response = client.newCall(request).execute()) { assert response.body() != null; jsonArray = (JSONArray) parser.parse(response.body().string()); } catch (ParseException | IOException e) { - log.error("Error parsing response from Quote API: {}", e.getMessage()); + log.error("Error executing or parsing response from Quote API: {}", e.getMessage()); throw new GenericException("Quote not found"); } diff --git a/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java b/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java index 9f123965..99da071f 100644 --- a/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java +++ b/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java @@ -82,7 +82,7 @@ public InputStream updateTitlesStream() { @Retryable(maxAttempts = 2, backoff = @Backoff(delay = 2000), retryFor = com.espacogeek.geek.exception.RequestException.class) @Override public MediaModel getDetails(Integer id) { - TvSeriesDb rawSerieDetails = new TvSeriesDb(); + TvSeriesDb rawSerieDetails; try { rawSerieDetails = api.getDetails(id, "en-US", TvSeriesAppendToResponse.EXTERNAL_IDS, TvSeriesAppendToResponse.ALTERNATIVE_TITLES, TvSeriesAppendToResponse.IMAGES, TvSeriesAppendToResponse.VIDEOS); } catch (TmdbException e) { @@ -117,9 +117,7 @@ public MediaModel getDetails(Integer id) { } public ExternalReferenceModel getTrailer(TvSeriesDb rawSerieDetails) { - ExternalReferenceModel trailers = null; - - trailers = rawSerieDetails.getVideos().getResults().stream().filter(video -> video.getType().equals("Trailer")) + ExternalReferenceModel trailers = rawSerieDetails.getVideos().getResults().stream().filter(video -> video.getType().equals("Trailer")) .findFirst().map(video -> new ExternalReferenceModel(null, video.getKey(), null, typeReferenceService.findById(MediaDataController.ExternalReferenceType.YT.getId()).get())) .orElse(null); @@ -133,7 +131,7 @@ public ExternalReferenceModel getTrailer(TvSeriesDb rawSerieDetails) { @Override @Retryable(maxAttempts = 2, backoff = @Backoff(delay = 2000), retryFor = com.espacogeek.geek.exception.RequestException.class) public MediaModel getArtwork(Integer id) { - Images rawArtwork = new Images(); + Images rawArtwork; try { rawArtwork = api.getImages(id, ""); } catch (TmdbException e) { @@ -167,7 +165,7 @@ public List getKeyword(Integer id) { @Override @Retryable(maxAttempts = 2, backoff = @Backoff(delay = 2000), retryFor = com.espacogeek.geek.exception.RequestException.class) public List getAlternativeTitles(Integer id) { - List rawAlternativeTitles = new ArrayList<>(); + List rawAlternativeTitles; try { rawAlternativeTitles = api.getAlternativeTitles(id).getResults(); } catch (TmdbException e) { @@ -192,7 +190,7 @@ private List formatAlternativeTitles(List getExternalReference(Integer id) { - ExternalIds rawExternalReferences = new ExternalIds(); + ExternalIds rawExternalReferences; try { rawExternalReferences = api.getExternalIds(id); } catch (TmdbException e) { @@ -225,7 +223,7 @@ private List formatExternalReference(ExternalIds rawExte @Override @Retryable(maxAttempts = 2, backoff = @Backoff(delay = 2000), retryFor = com.espacogeek.geek.exception.RequestException.class) public List getGenre(Integer id) { - TvSeriesDb rawSerieDetails = new TvSeriesDb(); + TvSeriesDb rawSerieDetails; try { rawSerieDetails = api.getDetails(id, "en-US"); } catch (TmdbException e) { @@ -246,9 +244,7 @@ private List formatGenre(List rawGenres) { for (String genre : rawStringGenres) { if (genre.contains("&")) { for (String genreDivided : genre.split("&")) { - genreDivided = genreDivided.replace("&", ""); - genreDivided = genreDivided.strip(); - newRawGenres.add(genreDivided); + newRawGenres.add(genreDivided.strip()); } } } diff --git a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java index eb001c01..3c6ffc60 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java @@ -274,12 +274,9 @@ public List searchMedia(String search, MediaApi mediaApi, TypeRefere var result = new ArrayList(); for (MediaModel mediaSearch : rawMediaSearchList) { - var media = new MediaModel(); - media.setMediaCategory(mediaCategory); - + MediaModel media; try { media = createMediaIfNotExistAndIfExistReturnIt(mediaSearch, typeReference); - media = mediaSearch; if (media != null) { updateExternalReferences(media, mediaSearch, typeReference, mediaApi); diff --git a/src/main/java/com/espacogeek/geek/data/impl/MovieControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/MovieControllerImpl.java index b9efa314..36a1fbdc 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/MovieControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/MovieControllerImpl.java @@ -124,11 +124,6 @@ else if (isUndefined) media.setName(json.get("original_title").toString()); - if (externalReferenceExisted.isPresent()) { - media.setId(externalReferenceExisted.get().getMedia().getId()); - externalReference.setId(externalReferenceExisted.get().getId()); - } - var mediaSaved = mediaService.save(media); externalReference.setMedia(mediaSaved); diff --git a/src/main/java/com/espacogeek/geek/data/impl/SerieControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/SerieControllerImpl.java index 19422dc6..42154abd 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/SerieControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/SerieControllerImpl.java @@ -93,11 +93,6 @@ private void updateTvSeries() { media.setName(json.get("original_name").toString()); - if (externalReferenceExisted.isPresent()) { - media.setId(externalReferenceExisted.get().getMedia().getId()); - externalReference.setId(externalReferenceExisted.get().getId()); - } - var mediaSaved = mediaService.save(media); externalReference.setMedia(mediaSaved); diff --git a/src/main/java/com/espacogeek/geek/metrics/GraphQLMetricsInstrumentation.java b/src/main/java/com/espacogeek/geek/metrics/GraphQLMetricsInstrumentation.java index 774c8212..9f3283c3 100644 --- a/src/main/java/com/espacogeek/geek/metrics/GraphQLMetricsInstrumentation.java +++ b/src/main/java/com/espacogeek/geek/metrics/GraphQLMetricsInstrumentation.java @@ -28,7 +28,7 @@ public static String extractOperationName(String query) { } // Se não encontrou, tenta extrair a primeira palavra-chave GraphQL - pattern = java.util.regex.Pattern.compile("(\\w+)\\s*(?:\\(|\\{)"); + pattern = java.util.regex.Pattern.compile("(\\w+)\\s*[({]"); matcher = pattern.matcher(query); if (matcher.find()) { return matcher.group(1); diff --git a/src/main/java/com/espacogeek/geek/services/impl/ApiKeyServiceImpl.java b/src/main/java/com/espacogeek/geek/services/impl/ApiKeyServiceImpl.java index 2a78a35a..a7345a50 100644 --- a/src/main/java/com/espacogeek/geek/services/impl/ApiKeyServiceImpl.java +++ b/src/main/java/com/espacogeek/geek/services/impl/ApiKeyServiceImpl.java @@ -31,6 +31,6 @@ public Optional findById(Integer id) { */ @Override public Optional save(ApiKeyModel apiKeyModel) { - return Optional.ofNullable(apiKeyRepository.save(apiKeyModel)); + return Optional.of(apiKeyRepository.save(apiKeyModel)); } } diff --git a/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java b/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java index e09d31bb..d23ef4ac 100644 --- a/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java +++ b/src/main/java/com/espacogeek/geek/services/impl/MediaServiceImpl.java @@ -210,7 +210,7 @@ public Optional findByReferenceAndTypeReference(ExternalReferenceMod @Transactional public Optional findByIdEager(Integer id) { var fieldList = new ArrayList(); - MediaModel media = (MediaModel) mediaRepository.findById(id).orElseGet(null); + MediaModel media = (MediaModel) mediaRepository.findById(id).orElse(null); if (media == null) return Optional.empty(); @@ -271,8 +271,7 @@ public Optional randomArtwork() { if (categoryId == null) continue; - MediaModel updated = media; - updated = switch (categoryId) { + MediaModel updated = switch (categoryId) { case 2, 3 -> MediaUtils .updateGenericMedia( List.of(media), @@ -281,7 +280,7 @@ public Optional randomArtwork() { gamesAndVNsAPI) .getFirst(); case 1 -> MediaUtils.updateMedia(List.of(media), serieController).getFirst(); - default -> updated; + default -> media; }; if (updated != null && updated.getBanner() != null && !updated.getBanner().isEmpty()) { diff --git a/src/main/java/com/espacogeek/geek/services/impl/UserDetailsServiceImpl.java b/src/main/java/com/espacogeek/geek/services/impl/UserDetailsServiceImpl.java index 80d593a1..a37e1978 100644 --- a/src/main/java/com/espacogeek/geek/services/impl/UserDetailsServiceImpl.java +++ b/src/main/java/com/espacogeek/geek/services/impl/UserDetailsServiceImpl.java @@ -36,8 +36,7 @@ public UserDetails loadUserByUsername(String email) throws UsernameNotFoundExcep String[] parts = raw.replaceAll("\\s", "").split(","); // Normalize roles: if a role doesn't start with ROLE_ or ID_, prefix with ROLE_ rolesList.addAll(Arrays.stream(parts) - .map(s -> s == null ? null : s.trim()) - .filter(s -> s != null && !s.isBlank()) + .filter(s -> !s.isBlank()) .map(s -> { if (s.startsWith("ROLE_") || s.startsWith("ID_")) return s; return "ROLE_" + s; diff --git a/src/main/java/com/espacogeek/geek/utils/MediaUtils.java b/src/main/java/com/espacogeek/geek/utils/MediaUtils.java index cac3a29e..3717a9a0 100644 --- a/src/main/java/com/espacogeek/geek/utils/MediaUtils.java +++ b/src/main/java/com/espacogeek/geek/utils/MediaUtils.java @@ -40,7 +40,7 @@ public static Boolean updateMediaWhenLastTimeUpdateMoreThanOneDay(MediaModel med LocalDate mediaUpdateAt = media.getUpdateAt() == null ? null : LocalDate.ofInstant(media.getUpdateAt().toInstant(), ZoneId.systemDefault()); - if (mediaUpdateAt == null || ChronoUnit.DAYS.between(mediaUpdateAt, LocalDate.now()) > 1l) { + if (mediaUpdateAt == null || ChronoUnit.DAYS.between(mediaUpdateAt, LocalDate.now()) > 1L) { return true; } @@ -69,7 +69,7 @@ public static List updateGenericMedia(List medias, Media : media); } - return medias; + return updatedMedias; } /** @@ -89,7 +89,7 @@ public static List updateMedia(List medias, MediaDataCon : media); } - return medias; + return updatedMedias; } /** From 35f55312b63c556144055243e5e1ecd535994e97 Mon Sep 17 00:00:00 2001 From: Vitor Hugo Date: Fri, 20 Mar 2026 10:02:32 -0300 Subject: [PATCH 08/12] Update src/test/java/com/espacogeek/geek/query/media/AnimeQueryTest.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../java/com/espacogeek/geek/query/media/AnimeQueryTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/espacogeek/geek/query/media/AnimeQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/AnimeQueryTest.java index 8b4b389a..f8e0447c 100644 --- a/src/test/java/com/espacogeek/geek/query/media/AnimeQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/AnimeQueryTest.java @@ -58,7 +58,6 @@ public class AnimeQueryTest { @MockitoBean private AlternativeTitlesRepository alternativeTitlesRepository; - @SuppressWarnings("rawtypes") @MockitoBean private ExternalReferenceRepository externalReferenceRepository; From a7a1a898d1f90ef0588c12464f8b2daf5b9f0ed5 Mon Sep 17 00:00:00 2001 From: Vitor Hugo Date: Fri, 20 Mar 2026 10:03:59 -0300 Subject: [PATCH 09/12] Update src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../geek/data/impl/GenericMediaDataControllerImpl.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java index 3c6ffc60..bfd22880 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java @@ -290,8 +290,14 @@ public List searchMedia(String search, MediaApi mediaApi, TypeRefere result.add(media); } catch (MediaAlreadyExist e) { - media = mediaService.findByReferenceAndTypeReference(mediaSearch.getExternalReference().iterator().next(), typeReference).orElseThrow(() -> new com.espacogeek.geek.exception.GenericException("Media not found for the given external reference")); + Collection externalReferences = mediaSearch.getExternalReference(); + if (CollectionUtils.isEmpty(externalReferences)) { + throw new com.espacogeek.geek.exception.GenericException("MediaAlreadyExist thrown but no external references are available to lookup existing media"); + } + ExternalReferenceModel firstReference = externalReferences.iterator().next(); + media = mediaService.findByReferenceAndTypeReference(firstReference, typeReference) + .orElseThrow(() -> new com.espacogeek.geek.exception.GenericException("Media not found for the given external reference")); result.add(media); } } From a6551f8a49e738555f6644530b76b82860a7c257 Mon Sep 17 00:00:00 2001 From: Vitor Hugo Date: Fri, 20 Mar 2026 10:04:40 -0300 Subject: [PATCH 10/12] Update src/test/java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java b/src/test/java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java index a4eb350f..2265f926 100644 --- a/src/test/java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java +++ b/src/test/java/com/espacogeek/geek/cors/BrowserCorsRequestTest.java @@ -98,7 +98,6 @@ RuntimeWiringConfigurer dateScalarConfigurer() { @MockitoBean private AlternativeTitlesRepository alternativeTitlesRepository; - @SuppressWarnings("rawtypes") @MockitoBean private ExternalReferenceRepository externalReferenceRepository; From 0029e4c60726acbdf399a86f2dee90cbf6de7b11 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 13:05:34 +0000 Subject: [PATCH 11/12] Address PR review: fix assert in QuoteApiImpl, orElseGet(null) in TvSeriesApiImpl, searchMedia empty-collection guard, remove redundant @SuppressWarnings Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com> --- .../espacogeek/geek/data/api/impl/QuoteApiImpl.java | 12 ++++++++++-- .../geek/data/api/impl/TvSeriesApiImpl.java | 2 +- .../data/impl/GenericMediaDataControllerImpl.java | 2 -- .../espacogeek/geek/query/media/GameQueryTest.java | 1 - .../espacogeek/geek/query/media/MediaQueryTest.java | 1 - .../espacogeek/geek/query/media/MovieQueryTest.java | 1 - .../geek/query/media/TvSerieQueryTest.java | 1 - .../geek/query/media/VisualNovelQueryTest.java | 1 - .../geek/services/MediaServiceImplTest.java | 1 - 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/espacogeek/geek/data/api/impl/QuoteApiImpl.java b/src/main/java/com/espacogeek/geek/data/api/impl/QuoteApiImpl.java index 01dd1d3f..27346d92 100644 --- a/src/main/java/com/espacogeek/geek/data/api/impl/QuoteApiImpl.java +++ b/src/main/java/com/espacogeek/geek/data/api/impl/QuoteApiImpl.java @@ -65,8 +65,16 @@ public QuoteModel getRandomQuote() { var parser = new JSONParser(); var jsonArray = new JSONArray(); try (Response response = client.newCall(request).execute()) { - assert response.body() != null; - jsonArray = (JSONArray) parser.parse(response.body().string()); + if (!response.isSuccessful()) { + log.error("Quote API returned unsuccessful response: {}", response.code()); + throw new GenericException("Quote not found"); + } + okhttp3.ResponseBody body = response.body(); + if (body == null) { + log.error("Quote API returned empty body"); + throw new GenericException("Quote not found"); + } + jsonArray = (JSONArray) parser.parse(body.string()); } catch (ParseException | IOException e) { log.error("Error executing or parsing response from Quote API: {}", e.getMessage()); throw new GenericException("Quote not found"); diff --git a/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java b/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java index 99da071f..a4efa663 100644 --- a/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java +++ b/src/main/java/com/espacogeek/geek/data/api/impl/TvSeriesApiImpl.java @@ -99,7 +99,7 @@ public MediaModel getDetails(Integer id) { MediaModel serie = new MediaModel( null, rawSerieDetails.getName(), - Optional.ofNullable(rawSerieDetails.getNumberOfEpisodes()).orElse(season.stream().map(SeasonModel::getEpisodeCount).reduce(Integer::sum).orElseGet(null)), + Optional.ofNullable(rawSerieDetails.getNumberOfEpisodes()).orElse(season.stream().map(SeasonModel::getEpisodeCount).reduce(Integer::sum).orElse(null)), rawSerieDetails.getEpisodeRunTime() == null || rawSerieDetails.getEpisodeRunTime().isEmpty() ? null : rawSerieDetails.getEpisodeRunTime().getFirst(), rawSerieDetails.getOverview(), rawSerieDetails.getPosterPath() == null ? null : ExternalCDN.TMDB.getUrl() + rawSerieDetails.getPosterPath(), diff --git a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java index bfd22880..ba2aa69c 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java @@ -291,8 +291,6 @@ public List searchMedia(String search, MediaApi mediaApi, TypeRefere } catch (MediaAlreadyExist e) { Collection externalReferences = mediaSearch.getExternalReference(); - if (CollectionUtils.isEmpty(externalReferences)) { - throw new com.espacogeek.geek.exception.GenericException("MediaAlreadyExist thrown but no external references are available to lookup existing media"); } ExternalReferenceModel firstReference = externalReferences.iterator().next(); diff --git a/src/test/java/com/espacogeek/geek/query/media/GameQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/GameQueryTest.java index 70ef11fa..aef8a130 100644 --- a/src/test/java/com/espacogeek/geek/query/media/GameQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/GameQueryTest.java @@ -61,7 +61,6 @@ class GameQueryTest { @MockitoBean private AlternativeTitlesRepository alternativeTitlesRepository; - @SuppressWarnings("rawtypes") @MockitoBean private ExternalReferenceRepository externalReferenceRepository; diff --git a/src/test/java/com/espacogeek/geek/query/media/MediaQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/MediaQueryTest.java index c5ab6854..d89b78f3 100644 --- a/src/test/java/com/espacogeek/geek/query/media/MediaQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/MediaQueryTest.java @@ -57,7 +57,6 @@ class MediaQueryTest { @MockitoBean private AlternativeTitlesRepository alternativeTitlesRepository; - @SuppressWarnings("rawtypes") @MockitoBean private ExternalReferenceRepository externalReferenceRepository; diff --git a/src/test/java/com/espacogeek/geek/query/media/MovieQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/MovieQueryTest.java index e433ad22..ce6b2f92 100644 --- a/src/test/java/com/espacogeek/geek/query/media/MovieQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/MovieQueryTest.java @@ -58,7 +58,6 @@ public class MovieQueryTest { @MockitoBean private AlternativeTitlesRepository alternativeTitlesRepository; - @SuppressWarnings("rawtypes") @MockitoBean private ExternalReferenceRepository externalReferenceRepository; diff --git a/src/test/java/com/espacogeek/geek/query/media/TvSerieQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/TvSerieQueryTest.java index 9a6c205c..7632d942 100644 --- a/src/test/java/com/espacogeek/geek/query/media/TvSerieQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/TvSerieQueryTest.java @@ -56,7 +56,6 @@ class TvSerieQueryTest { @MockitoBean private AlternativeTitlesRepository alternativeTitlesRepository; - @SuppressWarnings("rawtypes") @MockitoBean private ExternalReferenceRepository externalReferenceRepository; diff --git a/src/test/java/com/espacogeek/geek/query/media/VisualNovelQueryTest.java b/src/test/java/com/espacogeek/geek/query/media/VisualNovelQueryTest.java index cacac139..8eb72070 100644 --- a/src/test/java/com/espacogeek/geek/query/media/VisualNovelQueryTest.java +++ b/src/test/java/com/espacogeek/geek/query/media/VisualNovelQueryTest.java @@ -61,7 +61,6 @@ class VisualNovelQueryTest { @MockitoBean private AlternativeTitlesRepository alternativeTitlesRepository; - @SuppressWarnings("rawtypes") @MockitoBean private ExternalReferenceRepository externalReferenceRepository; diff --git a/src/test/java/com/espacogeek/geek/services/MediaServiceImplTest.java b/src/test/java/com/espacogeek/geek/services/MediaServiceImplTest.java index 597ce04d..bee26767 100644 --- a/src/test/java/com/espacogeek/geek/services/MediaServiceImplTest.java +++ b/src/test/java/com/espacogeek/geek/services/MediaServiceImplTest.java @@ -11,7 +11,6 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Set; import jakarta.validation.ValidationException; import org.junit.jupiter.api.Test; From 3291375d32d2cf4c2e864b1b9a89f9f606495e51 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 13:08:27 +0000 Subject: [PATCH 12/12] Fix conflict: restore if-guard in searchMedia empty-collection check Co-authored-by: vitorhugo-java <65777252+vitorhugo-java@users.noreply.github.com> --- .../geek/data/impl/GenericMediaDataControllerImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java index ba2aa69c..bfd22880 100644 --- a/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java +++ b/src/main/java/com/espacogeek/geek/data/impl/GenericMediaDataControllerImpl.java @@ -291,6 +291,8 @@ public List searchMedia(String search, MediaApi mediaApi, TypeRefere } catch (MediaAlreadyExist e) { Collection externalReferences = mediaSearch.getExternalReference(); + if (CollectionUtils.isEmpty(externalReferences)) { + throw new com.espacogeek.geek.exception.GenericException("MediaAlreadyExist thrown but no external references are available to lookup existing media"); } ExternalReferenceModel firstReference = externalReferences.iterator().next();