Skip to content

Commit

Permalink
Jv-rick-and-morty implementation (fix 5 full fix)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkazarian-1 committed Sep 27, 2024
1 parent ff3ac77 commit 933f196
Show file tree
Hide file tree
Showing 18 changed files with 118 additions and 49 deletions.
5 changes: 4 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.2.10</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -97,7 +98,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.3.0</version>
<version>${maven.checkstyle.plugin.version}</version>
<executions>
<execution>
<phase>compile</phase>
Expand All @@ -111,6 +112,8 @@
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<linkXRef>false</linkXRef>
<excludes>target/generated-sources/annotations/**/*.java</excludes>
<includes>src/main/java/**/*.java</includes>
</configuration>
</plugin>
<plugin>
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/mate/academy/rickandmorty/Application.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package mate.academy.rickandmorty;

import lombok.RequiredArgsConstructor;

import mate.academy.rickandmorty.external.api.service.DbSynchronizationService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@RequiredArgsConstructor
public class Application implements CommandLineRunner {
private static final String RICK_AND_MORTY_API_CHARACTER_URL = "https://rickandmortyapi.com/api/character";

private final DbSynchronizationService dbSynchronizationService;

@Override
public void run(String... args) throws Exception {
dbSynchronizationService.synchronize(RICK_AND_MORTY_API_CHARACTER_URL);
dbSynchronizationService.synchronize();
}

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import java.util.List;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Data
@Getter
@Setter
public class CharacterFullResponseDto {
private CharacterMetadataDto info;
private List<CharacterResponseDto> results;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
package mate.academy.rickandmorty.dto.external;

public record CharacterMetadataDto(String next) {
import lombok.Getter;
import lombok.Setter;

import java.util.Objects;
@Getter
@Setter
public class CharacterMetadataDto {
private String next;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package mate.academy.rickandmorty.dto.external;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

public record CharacterResponseDto(@JsonProperty("id") String externalId,
String name,
String status,
String gender) {
import java.util.Objects;
@Getter
@Setter
public final class CharacterResponseDto {
@JsonProperty("id")
private String externalId;
private String name;
private String status;
private String gender;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package mate.academy.rickandmorty.exeption;

public class ConnectionException extends RuntimeException{
public ConnectionException(String message) {
super(message);
}

public ConnectionException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package mate.academy.rickandmorty.exeption;

public class ConvertException extends RuntimeException{
public ConvertException(String message) {
super(message);
}

public ConvertException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package mate.academy.rickandmorty.external.api.service;

import mate.academy.rickandmorty.dto.external.CharacterFullResponseDto;

public interface CharacterClient {
CharacterFullResponseDto getDtoFromApi(String url);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package mate.academy.rickandmorty.external.api.service;

public interface DbSynchronizationService {
void synchronize(String url);
void synchronize();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import mate.academy.rickandmorty.dto.external.CharacterResponseDto;

import java.util.List;

public interface ExternalCharacterService {
void saveOrUpdate(CharacterResponseDto characterResponseDto);
void saveOrUpdate(List<CharacterResponseDto> responseDtoList);
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

import lombok.RequiredArgsConstructor;
import mate.academy.rickandmorty.dto.external.CharacterFullResponseDto;
import mate.academy.rickandmorty.external.api.service.GetClient;
import mate.academy.rickandmorty.exeption.ConnectionException;
import mate.academy.rickandmorty.exeption.ConvertException;
import mate.academy.rickandmorty.external.api.service.CharacterClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class GetCharactersClientImpl implements GetClient<CharacterFullResponseDto> {
public class CharactersClientImpl implements CharacterClient {
private final ObjectMapper objectMapper;

public CharacterFullResponseDto getDtoFromApi(String url) {
Expand All @@ -27,7 +31,7 @@ public CharacterFullResponseDto getDtoFromApi(String url) {
try {
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Can't get response from: " + url, e);
throw new ConnectionException("Can't get response from: " + url, e);
}

return convertResponse(response);
Expand All @@ -38,7 +42,7 @@ private CharacterFullResponseDto convertResponse(HttpResponse<String> response)
return objectMapper.readValue(response.body(),
CharacterFullResponseDto.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(
throw new ConvertException(
"Can't convert response to CharacterFullResponseDto.class", e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,35 @@
import mate.academy.rickandmorty.dto.external.CharacterFullResponseDto;
import mate.academy.rickandmorty.external.api.service.DbSynchronizationService;
import mate.academy.rickandmorty.external.api.service.ExternalCharacterService;
import mate.academy.rickandmorty.external.api.service.GetClient;
import mate.academy.rickandmorty.external.api.service.CharacterClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class DbSynchronizationServiceImpl implements DbSynchronizationService {
private final GetClient<CharacterFullResponseDto> getClient;
private final CharacterClient characterClient;
private final ExternalCharacterService externalCharacterService;

@Value("${mate.academy.rickandmorty.api}")
private String RICK_AND_MORTY_API_CHARACTER_URL;

@Override
public void synchronize(String url) {
CharacterFullResponseDto fullResponseDto = getClient.getDtoFromApi(url);
public void synchronize() {
CharacterFullResponseDto fullResponseDto = characterClient.getDtoFromApi(RICK_AND_MORTY_API_CHARACTER_URL);

if (fullResponseDto.getResults().isEmpty()) {
return;
}

while (true) {
fullResponseDto.getResults().forEach(externalCharacterService::saveOrUpdate);
externalCharacterService.saveOrUpdate(fullResponseDto.getResults());

if (fullResponseDto.getInfo().next() == null) {
if (fullResponseDto.getInfo().getNext() == null) {
break;
}

fullResponseDto = getClient.getDtoFromApi(fullResponseDto.getInfo().next());
fullResponseDto = characterClient.getDtoFromApi(fullResponseDto.getInfo().getNext());
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package mate.academy.rickandmorty.external.api.service.impl;

import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import mate.academy.rickandmorty.dto.external.CharacterResponseDto;
Expand All @@ -16,30 +18,33 @@ public class ExternalCharacterServiceImpl implements ExternalCharacterService {
private final CharacterMapper characterMapper;

@Override
public void saveOrUpdate(CharacterResponseDto characterResponseDto) {
Optional<Character> characterOptional = characterRepository
.findByExternalId(characterResponseDto.externalId())
.stream()
.findFirst();
public void saveOrUpdate(List<CharacterResponseDto> responseDtoList) {
List<Character> listToSave = new LinkedList<>();

if (characterOptional.isEmpty()) {
characterRepository.save(
characterMapper.convertFromResponseDto(characterResponseDto));
} else {
Character character = characterOptional.get();
for (CharacterResponseDto responseDto : responseDtoList) {
Optional<Character> characterOptional = characterRepository
.findFirstByExternalId(responseDto.getExternalId());

if (isEqual(characterResponseDto, character)) {
return;
}
if (characterOptional.isEmpty()) {
listToSave.add(
characterMapper.convertFromResponseDto(responseDto));
} else {
Character character = characterOptional.get();
if (isEqual(responseDto, character)) {
return;
}

characterMapper.updateCharacterFromResponseDto(characterResponseDto, character);
characterRepository.save(character);
Character updateCharacter = characterMapper.convertFromResponseDto(responseDto);
updateCharacter.setId(character.getId());
listToSave.add(updateCharacter);
}
}
characterRepository.saveAll(listToSave);
}

private boolean isEqual(CharacterResponseDto characterResponseDto, Character character) {
return characterResponseDto.name().equals(character.getName())
&& characterResponseDto.gender().equals(character.getGender())
&& characterResponseDto.status().equals(character.getStatus());
return characterResponseDto.getName().equals(character.getName())
&& characterResponseDto.getGender().equals(character.getGender())
&& characterResponseDto.getStatus().equals(character.getStatus());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package mate.academy.rickandmorty.repository;

import java.util.List;
import java.util.Optional;

import mate.academy.rickandmorty.models.Character;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -9,10 +11,10 @@

public interface CharacterRepository extends JpaRepository<Character,Long>,
JpaSpecificationExecutor<Character> {
List<Character> findByExternalId(String externalId);
Optional<Character> findFirstByExternalId(String externalId);

List<Character> findByNameContaining(Pageable pageable, String name);

@Query(value = "SELECT * FROM characters ORDER BY RAND() LIMIT 1", nativeQuery = true)
Character findRandomCharacter();
Optional<Character> findRandomCharacter();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package mate.academy.rickandmorty.service.impl;

import java.util.List;
import java.util.NoSuchElementException;

import lombok.RequiredArgsConstructor;
import mate.academy.rickandmorty.dto.internal.CharacterDto;
import mate.academy.rickandmorty.mapping.CharacterMapper;
Expand All @@ -25,6 +27,8 @@ public List<CharacterDto> findByName(Pageable pageable, String name) {

@Override
public CharacterDto getRandomCharacter() {
return characterMapper.convertToDto(characterRepository.findRandomCharacter());
return characterMapper.convertToDto(
characterRepository.findRandomCharacter()
.orElseThrow(() -> new NoSuchElementException("Random character not found")));
}
}
2 changes: 2 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=true
spring.jpa.open-in-view=false

mate.academy.rickandmorty.api=https://rickandmortyapi.com/api/character
2 changes: 2 additions & 0 deletions src/test/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

mate.academy.rickandmorty.api=https://rickandmortyapi.com/api/character

0 comments on commit 933f196

Please sign in to comment.