diff --git a/src/main/java/club/ttg/dnd5/controller/species/SpeciesController.java b/src/main/java/club/ttg/dnd5/controller/species/SpeciesController.java index fa74b22b..b65a269d 100644 --- a/src/main/java/club/ttg/dnd5/controller/species/SpeciesController.java +++ b/src/main/java/club/ttg/dnd5/controller/species/SpeciesController.java @@ -34,8 +34,8 @@ public ResponseEntity> getSubSpeciesByParentUrl( } @GetMapping("/subspecies/{subSpeciesUrl}/related") - @Operation(summary = "Получить все связанные виды по URL подвига", - description = "Возвращает список всех связанных видов, включая родительский вид и подвиды по указанному URL подвига.") + @Operation(summary = "Получить все связанные виды по URL подвида", + description = "Возвращает список всех связанных видов, включая родительский вид и подвиды по указанному URL подвида.") public ResponseEntity> getAllRelatedSpeciesBySubSpeciesUrl( @Parameter(description = "URL подвига", required = true) @PathVariable String subSpeciesUrl) { List relatedSpeciesResponses = speciesService.getAllRelatedSpeciesBySubSpeciesUrl(subSpeciesUrl); diff --git a/src/main/java/club/ttg/dnd5/dto/species/CreateSpeciesDTO.java b/src/main/java/club/ttg/dnd5/dto/species/CreateSpeciesDTO.java index d8033971..55a8ed59 100644 --- a/src/main/java/club/ttg/dnd5/dto/species/CreateSpeciesDTO.java +++ b/src/main/java/club/ttg/dnd5/dto/species/CreateSpeciesDTO.java @@ -15,17 +15,17 @@ @AllArgsConstructor @RequiredArgsConstructor public class CreateSpeciesDTO extends BaseDTO implements HasSourceDTO { + boolean parent; private CreaturePropertiesDTO creatureProperties; private Collection features = new ArrayList<>(); - boolean parent; @Override public Short getPage() { - if (this.getSource() != null) { + if (this.getSource() != null) return this.getSourceDTO().getPage(); - } else { + else return -1; - } + } @Override @@ -34,12 +34,12 @@ public void setPage(Short page) { } @Override - public void setSource(String source) { - this.getSourceDTO().setSource(source); + public String getSource() { + return this.getSourceDTO().getSource(); } @Override - public String getSource() { - return this.getSourceDTO().getSource(); + public void setSource(String source) { + this.getSourceDTO().setSource(source); } } diff --git a/src/main/java/club/ttg/dnd5/model/species/Species.java b/src/main/java/club/ttg/dnd5/model/species/Species.java index 5f7f9870..7ea65d43 100644 --- a/src/main/java/club/ttg/dnd5/model/species/Species.java +++ b/src/main/java/club/ttg/dnd5/model/species/Species.java @@ -30,9 +30,8 @@ public class Species extends CreatureProperties implements HasSourceEntity { @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private Collection subSpecies = new ArrayList<>(); - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "source") - @Cascade(org.hibernate.annotations.CascadeType.ALL) private Source source = new Source(); @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "species_url") diff --git a/src/main/java/club/ttg/dnd5/service/species/SpeciesService.java b/src/main/java/club/ttg/dnd5/service/species/SpeciesService.java index eb8038ba..8afeaa4f 100644 --- a/src/main/java/club/ttg/dnd5/service/species/SpeciesService.java +++ b/src/main/java/club/ttg/dnd5/service/species/SpeciesService.java @@ -18,8 +18,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; import java.util.*; +import java.util.stream.Stream; @Service @RequiredArgsConstructor @@ -47,10 +49,10 @@ public SpeciesResponse findById(String url) { public SpeciesResponse save(CreateSpeciesDTO createSpeciesDTO) { Species species = new Species(); //base - Converter.mapBaseDTOToEntityName(createSpeciesDTO, species); - Converter.mapCreaturePropertiesDTOToEntity(createSpeciesDTO.getCreatureProperties(), species); + Converter.mapBaseDtoToEntityName(createSpeciesDTO, species); + Converter.mapCreaturePropertiesDtoToEntity(createSpeciesDTO.getCreatureProperties(), species); //source - Converter.mapDTOSourceToEntitySource(createSpeciesDTO, species); + Converter.mapDtoSourceToEntitySource(createSpeciesDTO, species); validateAndSaveSource(species.getSource()); //feature @@ -64,22 +66,19 @@ public SpeciesResponse save(CreateSpeciesDTO createSpeciesDTO) { private void validateAndSaveSource(Source source) { if (source != null) { - Optional optionalBook = bookRepository.findById(source.getSourceAcronym()); - if (optionalBook.isPresent()) { - source.setBookInfo(optionalBook.get()); - sourceRepository.save(source); - } else { - throw new EntityNotFoundException("Book not found with ID: " + source.getId()); - } + Book book = bookRepository.findById(source.getSourceAcronym()) + .orElseThrow(() -> new EntityNotFoundException("Book not found with ID: " + source.getId())); + + source.setBookInfo(book); + sourceRepository.save(source); } } public List getSubSpeciesByParentUrl(String parentUrl) { - Species parentSpecies = speciesRepository.findById(parentUrl) - .orElseThrow(() -> new EntityNotFoundException("Parent species not found for URL: " + parentUrl)); - - List subSpeciesList = speciesRepository.findByParent(parentSpecies); - return subSpeciesList.stream() + return speciesRepository.findById(parentUrl) + .map(speciesRepository::findByParent) // Fetch the list of sub-species if parent is found + .orElseThrow(() -> new EntityNotFoundException("Parent species not found for URL: " + parentUrl)) + .stream() .map(species -> toDTO(species, true)) .toList(); } @@ -88,20 +87,13 @@ public List getAllRelatedSpeciesBySubSpeciesUrl(String subSpeci Species subSpecies = speciesRepository.findById(subSpeciesUrl) .orElseThrow(() -> new EntityNotFoundException("Sub-species not found for URL: " + subSpeciesUrl)); - List relatedSpecies = new ArrayList<>(); - - relatedSpecies.add(subSpecies); - - Species parentSpecies = subSpecies.getParent(); - if (parentSpecies != null) { - relatedSpecies.add(parentSpecies); - } - - Collection subSpeciesList = subSpecies.getSubSpecies(); - if (subSpeciesList != null && !subSpeciesList.isEmpty()) { - relatedSpecies.addAll(new ArrayList<>(subSpeciesList)); // Convert Collection to List - } - return relatedSpecies.stream() + return Stream.concat( + Stream.of(subSpecies), // Add sub-species itself to the stream + Stream.concat( + Stream.ofNullable(subSpecies.getParent()), // Add parent if present + subSpecies.getSubSpecies() != null ? subSpecies.getSubSpecies().stream() : Stream.empty() // Add all sub-species if not null + ) + ) .map(species -> toDTO(species, true)) .toList(); } @@ -194,9 +186,9 @@ private void fillParent(Species species, SpeciesResponse speciesResponse) { private Species toEntity(SpeciesResponse dto) { Species species = new Species(); species.setUrl(dto.getUrl()); - Converter.mapBaseDTOToEntityName(dto, species); - Converter.mapDTOSourceToEntitySource(dto.getSourceDTO(), species); - Converter.mapCreaturePropertiesDTOToEntity(dto.getCreatureProperties(), species); + Converter.mapBaseDtoToEntityName(dto, species); + Converter.mapDtoSourceToEntitySource(dto.getSourceDTO(), species); + Converter.mapCreaturePropertiesDtoToEntity(dto.getCreatureProperties(), species); // Handle parent if (dto.getParentUrl() != null) { fillParent(species, dto); @@ -209,14 +201,14 @@ private Species toEntity(SpeciesResponse dto) { private SpeciesResponse toDTO(Species species, boolean hideDetails) { SpeciesResponse dto = new SpeciesResponse(); if (hideDetails) { - Converter.mapEntityToBaseDTOWithHideDetails(dto, species); + Converter.mapEntityToBaseDtoWithHideDetails(dto, species); } else { - Converter.mapEntityToBaseDTO(dto, species); + Converter.mapEntityToBaseDto(dto, species); } - Converter.mapEntitySourceToDTOSource(dto.getSourceDTO(), species); + Converter.mapEntitySourceToDtoSource(dto.getSourceDTO(), species); //creatureProperties - Converter.mapEntityToCreaturePropertiesDTO(dto.getCreatureProperties(), species); + Converter.mapEntityToCreaturePropertiesDto(dto.getCreatureProperties(), species); dto.getCreatureProperties().setSourceResponse((dto.getSourceDTO())); handleParentAndChild(species, dto); @@ -228,7 +220,6 @@ private SpeciesResponse toDTO(Species species, boolean hideDetails) { SpeciesFeatureConverter.convertEntityFeatureIntoDTOFeature(features); dto.setFeatures(speciesFeatureResponses); } - return dto; } @@ -248,19 +239,15 @@ private void handleParentAndChild(Species species, SpeciesResponse dto) { } private void fillSpecies(SpeciesResponse speciesResponse, Species species) { - if (speciesResponse.getSubSpeciesUrls() != null) { - List subSpecies = speciesResponse.getSubSpeciesUrls().stream() - .map(this::findByUrl) - .toList(); - species.setSubSpecies(subSpecies); - } + Optional.ofNullable(speciesResponse.getSubSpeciesUrls()) + .ifPresent(urls -> species.setSubSpecies(urls.stream().map(this::findByUrl).toList())); } @Transactional public void saveSpeciesFeatures(CreateSpeciesDTO createSpeciesDTO, Species species) { SpeciesFeatureConverter.convertDTOFeatureIntoEntityFeature(createSpeciesDTO.getFeatures(), species); Collection features = species.getFeatures(); - if (features != null && !features.isEmpty()) { + if (!CollectionUtils.isEmpty(features)) { features.stream() .map(SpeciesFeature::getSource) .filter(Objects::nonNull) diff --git a/src/main/java/club/ttg/dnd5/utills/Converter.java b/src/main/java/club/ttg/dnd5/utills/Converter.java index 6cd81048..1ab869bf 100644 --- a/src/main/java/club/ttg/dnd5/utills/Converter.java +++ b/src/main/java/club/ttg/dnd5/utills/Converter.java @@ -10,13 +10,14 @@ import club.ttg.dnd5.model.base.NamedEntity; import club.ttg.dnd5.model.book.Book; import club.ttg.dnd5.model.book.Source; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class Converter { // D from DTO, E from Entity - private Converter() { - } - public static E mapBaseDTOToEntityName(D dto, E entity) { + public static E mapBaseDtoToEntityName(D dto, E entity) { entity.setUrl(dto.getUrl()); entity.setImageUrl(dto.getImageUrl()); entity.setName(dto.getNameBasedDTO().getName()); @@ -26,7 +27,7 @@ public static E mapBaseDTOToEntityNam return entity; } - public static D mapEntityToBaseDTO(D dto, E entity) { + public static D mapEntityToBaseDto(D dto, E entity) { dto.setUrl(entity.getUrl()); dto.setImageUrl(entity.getImageUrl()); dto.setNameBasedDTO(new NameBasedDTO()); @@ -37,7 +38,7 @@ public static D mapEntityToBaseDTO(D return dto; } - public static E mapCreaturePropertiesDTOToEntity(D dto, E entity) { + public static E mapCreaturePropertiesDtoToEntity(D dto, E entity) { entity.setSize(dto.getSize()); entity.setType(dto.getType()); entity.setSpeed(dto.getSpeed()); @@ -48,7 +49,7 @@ public static E return entity; } - public static D mapEntityToCreaturePropertiesDTO(D dto, E entity) { + public static D mapEntityToCreaturePropertiesDto(D dto, E entity) { dto.setSize(entity.getSize()); dto.setType(entity.getType()); dto.setSpeed(entity.getSpeed()); @@ -61,7 +62,7 @@ public static D //D - dto, E - entity, Id - id (acronym), R - repository public static - E mapDTOSourceToEntitySource(D dto, E entity) { + E mapDtoSourceToEntitySource(D dto, E entity) { String sourceAcronym = dto.getSource(); Source source = entity.getSource(); if (source == null) { @@ -75,7 +76,7 @@ E mapDTOSourceToEntitySource(D dto, E entity) { return entity; } - public static D mapEntitySourceToDTOSource(D dto, E entity) { + public static D mapEntitySourceToDtoSource(D dto, E entity) { if (entity.getSource() != null) { dto.setSource(entity.getSource().getSourceAcronym()); dto.setPage(entity.getSource().getPage()); @@ -83,8 +84,8 @@ public static D mapEntitySou return dto; } - public static D mapEntityToBaseDTOWithHideDetails(D dto, E entity) { - mapEntityToBaseDTO(dto, entity); + public static D mapEntityToBaseDtoWithHideDetails(D dto, E entity) { + mapEntityToBaseDto(dto, entity); dto.hideDetails(); return dto; } diff --git a/src/main/java/club/ttg/dnd5/utills/species/SpeciesFeatureConverter.java b/src/main/java/club/ttg/dnd5/utills/species/SpeciesFeatureConverter.java index 58ac6715..0f3617ca 100644 --- a/src/main/java/club/ttg/dnd5/utills/species/SpeciesFeatureConverter.java +++ b/src/main/java/club/ttg/dnd5/utills/species/SpeciesFeatureConverter.java @@ -4,18 +4,18 @@ import club.ttg.dnd5.model.species.Species; import club.ttg.dnd5.model.species.SpeciesFeature; import club.ttg.dnd5.utills.Converter; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import java.util.Collection; +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class SpeciesFeatureConverter { - private SpeciesFeatureConverter() { - - } public static SpeciesFeature toEntityFeature(SpeciesFeatureResponse response) { SpeciesFeature speciesFeature = new SpeciesFeature(); - Converter.mapBaseDTOToEntityName(response, speciesFeature); - Converter.mapDTOSourceToEntitySource(response, speciesFeature); + Converter.mapBaseDtoToEntityName(response, speciesFeature); + Converter.mapDtoSourceToEntitySource(response, speciesFeature); speciesFeature.setTags(response.getTags()); speciesFeature.setFeatureDescription(response.getDescription()); return speciesFeature; @@ -23,8 +23,8 @@ public static SpeciesFeature toEntityFeature(SpeciesFeatureResponse response) { public static SpeciesFeatureResponse toDTOFeature(SpeciesFeature feature) { SpeciesFeatureResponse dto = new SpeciesFeatureResponse(); - Converter.mapEntityToBaseDTO(dto, feature); - Converter.mapEntitySourceToDTOSource(dto, feature); + Converter.mapEntityToBaseDto(dto, feature); + Converter.mapEntitySourceToDtoSource(dto, feature); dto.setTags(feature.getTags()); dto.setDescription(feature.getFeatureDescription()); return dto; diff --git a/src/main/tests/club/ttg/dnd5/utills/ConverterTest.java b/src/main/tests/club/ttg/dnd5/utills/ConverterTest.java index 8f146576..d9357dfe 100644 --- a/src/main/tests/club/ttg/dnd5/utills/ConverterTest.java +++ b/src/main/tests/club/ttg/dnd5/utills/ConverterTest.java @@ -63,7 +63,7 @@ public void setUp() { // Test mapping from DTO to Entity for BaseDTO and NamedEntity @Test public void testMapBaseDTOToEntityName() { - NamedEntity result = Converter.mapBaseDTOToEntityName(baseDTO, new Species()); + NamedEntity result = Converter.mapBaseDtoToEntityName(baseDTO, new Species()); assertEquals(baseDTO.getUrl(), result.getUrl()); assertEquals(baseDTO.getNameBasedDTO().getName(), result.getName()); @@ -75,7 +75,7 @@ public void testMapBaseDTOToEntityName() { // Test mapping from Entity to DTO for NamedEntity and BaseDTO @Test public void testMapEntityToBaseDTO() { - BaseDTO result = Converter.mapEntityToBaseDTO(new SpeciesResponse(), namedEntity); + BaseDTO result = Converter.mapEntityToBaseDto(new SpeciesResponse(), namedEntity); assertEquals(namedEntity.getUrl(), result.getUrl()); assertEquals(namedEntity.getName(), result.getNameBasedDTO().getName()); @@ -87,7 +87,7 @@ public void testMapEntityToBaseDTO() { // Test mapping from CreaturePropertiesDTO to CreatureProperties Entity @Test public void testMapCreaturePropertiesDTOToEntity() { - CreatureProperties result = Converter.mapCreaturePropertiesDTOToEntity(creaturePropertiesDTO, new Species()); + CreatureProperties result = Converter.mapCreaturePropertiesDtoToEntity(creaturePropertiesDTO, new Species()); assertEquals(creaturePropertiesDTO.getSize(), result.getSize()); assertEquals(creaturePropertiesDTO.getType(), result.getType()); @@ -101,7 +101,7 @@ public void testMapCreaturePropertiesDTOToEntity() { // Test mapping from CreatureProperties Entity to CreaturePropertiesDTO @Test public void testMapEntityToCreaturePropertiesDTO() { - CreaturePropertiesDTO result = Converter.mapEntityToCreaturePropertiesDTO(new CreaturePropertiesDTO(), creatureProperties); + CreaturePropertiesDTO result = Converter.mapEntityToCreaturePropertiesDto(new CreaturePropertiesDTO(), creatureProperties); assertEquals(creatureProperties.getSize(), result.getSize()); assertEquals(creatureProperties.getType(), result.getType());