Treść:
- Plan działania pozwalający osiągnąć cel
- Poznajemy API Skyscanner
- Tworzenie frameworka aplikacji w oparciu o Spring Boot
- Piszemy klienta na zapytania do API Skyscanner Flight Search w projekcie
- Tworzenie usługi klienta dla żądania lokalizacji
- REST i sposób budowania punktów końcowych REST;
- relacyjne bazy danych;
- praca mavena (w szczególności czym jest zależność);
- obiekt JSON;
- zasady logowania.
- Możesz wybrać lot na konkretną datę i śledzić jego cenę. Użytkownik identyfikowany jest poprzez adres e-mail. Gdy tylko zostanie dokonana subskrypcja zmiany ceny, użytkownik otrzyma powiadomienie e-mailem.
- Co 30 minut (interwał ten konfiguruje się w aplikacji.properties) dla wszystkich abonamentów przeliczana jest minimalna cena za lot. Jeśli jedna z wartości spadnie, użytkownik otrzyma powiadomienie e-mailem.
- Wszystkie subskrypcje z nieaktualną datą emisji zostaną usunięte.
- Za pośrednictwem REST API możesz:
- utwórz subskrypcję;
- edytować;
- otrzymywać wszystkie subskrypcje e-mailem;
- usuń subskrypcję.
Plan działania pozwalający osiągnąć cel
Trzeba zacząć od tego, że skądś trzeba wziąć informacje o lotach. Zazwyczaj strony internetowe udostępniają otwarty interfejs API REST, za pomocą którego można uzyskać informacje.
API (interfejs programowania aplikacji) to interfejs, za pomocą którego można wchodzić w interakcję z aplikacją. Na tej podstawie możemy zbudować pomost do tego, czym jest interfejs API REST. REST API to interfejs żądań REST, którego można używać do komunikacji z aplikacją internetową. |
Poznajemy API Skyscanner
Skorzystajmy z linku do rakuten api . Najpierw musisz się zarejestrować.Wszystko to jest potrzebne, aby otrzymać unikalny klucz umożliwiający korzystanie z ich witryny i wysyłanie żądań do publicznych interfejsów API, które są na niej opublikowane. Jednym z tych interfejsów API jest wyszukiwarka lotów Skyscanner, której potrzebujemy . Teraz zastanówmy się, jak to działa. Znajdźmy żądanie GET List Places. Na obrazku widać, że należy uzupełnić dane i uruchomić Test Endpoint , w efekcie czego po prawej stronie otrzymamy odpowiedź w postaci obiektu JSON: a żądanie zostanie utworzone w następujący sposób:
https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/{country}/{currency}/{locale}/?query={query}
i wszystkie parametry zostaną podstawione do tego wzoru, otrzymamy:
https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/UK/GBP/en-GB/?query=Stockholm
i do tych żądań zostaną przekazane dwa nagłówki:
.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", "sing-up-for-key"),
jeżeli sign-up-for-key
jest wydawane po rejestracji. Aby śledzić spadek cen, będziemy potrzebować punktu końcowego Przeglądaj oferty . Znajdź to sam :)
Tworzenie frameworka aplikacji w oparciu o Spring Boot
Aby szybko i łatwo utworzyć projekt za pomocą Spring Boot, możesz użyć Spring Individualizr . Wybierz następujące opcje:- Projekt Mavena
- Jawa
- 2.1.10
- group - cokolwiek uznasz za konieczne, na przykład ru.javarush
- artefakt - dokładnie taki sam, na przykład monitorowanie lotów
- w poszukiwaniu zależności szukamy:
- Wiosenna sieć
- Nadawca poczty Java
- Dane wiosenne Jpa
- Baza danych H2
- KONTROLER - zaloguj się do aplikacji. API REST zostanie opisane tutaj
- USŁUGA to warstwa logiki biznesowej. Cała logika aplikacji zostanie opisana tutaj.
- REPOZYTORIUM - warstwa do pracy z bazą danych.
Piszemy klienta na zapytania do API Skyscanner Flight Search w projekcie
Skyscanner udostępnił artykuł na temat korzystania z ich API (nie będziemy tworzyć sesji z aktywnym żądaniem). Co to znaczy „napisać klienta”? Musimy utworzyć żądanie na konkretny adres URL z określonymi parametrami i przygotować DTO (obiekt transferu danych) dla przesyłanych z powrotem do nas danych. Na stronie znajdują się cztery grupy żądań:- Wyszukiwanie lotów na żywo - w tej chwili nie uznamy tego za niepotrzebne.
- Miejsca - napiszmy.
- Przeglądaj ceny lotów – skorzystamy z jednego zapytania, w którym uzyskasz wszystkie informacje.
- Lokalizacja - dodajmy ją, abyśmy wiedzieli jakie dane są obsługiwane.
Utwórz usługę klienta dla żądania lokalizacji:
Plan jest prosty jak rzepa na parze: utwórz zapytanie, spójrz na parametry, spójrz na odpowiedź. Istnieją dwa zapytania: Lista znaczników i Waluty. Zacznijmy od walut. Z rysunku wynika, że jest to żądanie bez dodatkowych pól: potrzebne jest do uzyskania informacji o obsługiwanych walutach: Odpowiedź ma postać obiektu JSON, który zawiera zbiór takich samych obiektów, np.:{
"Code":"LYD"
"Symbol":"د.ل."
"ThousandsSeparator":","
"DecimalSeparator":"."
"SymbolOnLeft":true
"SpaceBetweenAmountAndSymbol":false
"RoundingCoefficient":0
"DecimalDigits":3
}
Utwórzmy CurrencyDto dla tego obiektu:
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* Data transfer object for Currency.
*/
@Data
public class CurrencyDto {
@JsonProperty("Code")
private String code;
@JsonProperty("Symbol")
private String symbol;
@JsonProperty("ThousandsSeparator")
private String thousandsSeparator;
@JsonProperty("DecimalSeparator")
private String decimalSeparator;
@JsonProperty("SymbolOnLeft")
private boolean symbolOnLeft;
@JsonProperty("SpaceBetweenAmountAndSymbol")
private boolean spaceBetweenAmountAndSymbol;
@JsonProperty("RoundingCoefficient")
private int roundingCoefficient;
@JsonProperty("DecimalDigits")
private int decimalDigits;
}
Gdzie:
- @Data to adnotacja z projektu Lombok , która generuje wszystkie metody pobierające, ustawiające i przesłaniające metody toString(), równości() i hashCode(). Co poprawia czytelność kodu i przyspiesza czas zapisu obiektów POJO ;
- @JsonProperty("Kod") to adnotacja z projektu Jackson, która informuje, jakie pole zostanie przypisane do tej zmiennej. Oznacza to, że do zmiennej code zostanie przypisane pole w formacie JSON równe Code .
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-java</artifactId>
<version>1.4.9</version>
</dependency>
Następnie napiszemy usługę, która będzie wykonywać żądania REST. Oczywiście dla każdego klienta/usługi stworzymy interfejs i jego implementację:
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
/**
* Service, which is manipulating with Rest calls.
*/
public interface UniRestService {
/**
* Create GET request based on provided {@param path} with needed headers.
*
* @param path provided path with all the needed data
* @return {@link HttpResponse<jsonnode>} response object.
*/
HttpResponse<jsonnode> get(String path);
}
I jego realizacja:
import com.github.romankh3.flightsmonitoring.exception.FlightClientException;
import com.github.romankh3.flightsmonitoring.client.service.UniRestService;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* {@inheritDoc}
*/
@Slf4j
@Service
public class UniRestServiceImpl implements UniRestService {
public static final String HOST = "https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com";
public static final String PLACES_FORMAT = "/apiservices/autosuggest/v1.0/%s/%s/%s/?query=%s";
public static final String CURRENCIES_FORMAT = "/apiservices/reference/v1.0/currencies";
public static final String COUNTRIES_FORMAT = "/apiservices/reference/v1.0/countries/%s";
public static final String PLACES_KEY = "Places";
public static final String CURRENCIES_KEY = "Currencies";
public static final String COUNTRIES_KEY = "Countries";
@Value("${x.rapid.api.key}")
private String xRapidApiKey;
/**
* {@inheritDoc}
*/
@Override
public HttpResponse<jsonnode> get(String path) {
HttpResponse<jsonnode> response = null;
try {
response = Unirest.get(HOST + path)
.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", xRapidApiKey)
.asJson();
} catch (UnirestException e) {
throw new FlightClientException(String.format("Request failed, path=%s", HOST + path), e);
}
log.info("Response from Get request, on path={}, statusCode={}, response={}", path, response.getStatus(), response.getBody().toString());
return response;
}
}
Jej istotą jest to, że wszystkie interesujące nas żądania tworzone są pod żądania GET, a usługa ta przyjmuje gotowe żądanie i dodaje niezbędne nagłówki takie jak:
.header("x-rapidapi-host", "skyscanner-skyscanner-flight-search-v1.p.rapidapi.com")
.header("x-rapidapi-key", xRapidApiKey)
Aby pobrać dane z właściwości, użyj adnotacji @Value, jak pokazano poniżej:
@Value("${x.rapid.api.key}")
private String xRapidApiKey;
Mówi, że w application.properties będzie właściwość o nazwie x.rapid.api.key, którą należy wstrzyknąć do tej zmiennej. Pozbywamy się zakodowanych na stałe wartości i wyprowadzamy definicję tej zmiennej z kodu programu. Co więcej, publikując tę aplikację na GitHubie, nie dodaję wartości tej właściwości. Odbywa się to ze względów bezpieczeństwa. Napisaliśmy usługę, która będzie działać z żądaniami REST, teraz czas na usługę Lokalizacji. Budujemy aplikację w oparciu o OOP, dlatego tworzymy interfejs LocalizationClient i jego implementację LocalizationClientImpl :
import com.github.romankh3.flightsmonitoring.client.dto.CountryDto;
import com.github.romankh3.flightsmonitoring.client.dto.CurrencyDto;
import java.io.IOException;
import java.util.List;
/**
* Client for SkyScanner localisation.
*/
public interface LocalisationClient {
/**
* Retrieve the market countries that SkyScanner flight search API support. Most suppliers (airlines,
* travel agents and car hire dealers) set their fares based on the market (or country of purchase).
* It is therefore necessary to specify the market country in every query.
*
* @param locale locale of the response.
*
* @return the collection of the {@link CountryDto} objects.
*
* @throws IOException
*/
List<CountryDto> retrieveCountries(String locale);
/**
* Retrieve the currencies that we ScyScanner flight search API.
*
* @return the collection of the {@link CurrencyDto} objects.
*
* @throws IOException
*/
List<CurrencyDto> retrieveCurrencies();
}
i wdrożenie LocalizationClientImpl
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.COUNTRIES_FORMAT;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.COUNTRIES_KEY;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.CURRENCIES_FORMAT;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.CURRENCIES_KEY;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.romankh3.flightsmonitoring.client.dto.CountryDto;
import com.github.romankh3.flightsmonitoring.client.dto.CurrencyDto;
import com.github.romankh3.flightsmonitoring.client.service.LocalisationClient;
import com.github.romankh3.flightsmonitoring.client.service.UniRestService;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.io.IOException;
import java.util.List;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* {@inheritDoc}
*/
@Component
public class LocalisationClientImpl implements LocalisationClient {
@Autowired
private UniRestService uniRestService;
@Autowired
private ObjectMapper objectMapper;
/**
* {@inheritDoc}
*/
@Override
public List<CountryDto> retrieveCountries(String locale) throws IOException {
HttpResponse<JsonNode> response = uniRestService.get(String.format(COUNTRIES_FORMAT, locale));
if (response.getStatus() != HttpStatus.SC_OK) {
return null;
}
String jsonList = response.getBody().getObject().get(COUNTRIES_KEY).toString();
return objectMapper.readValue(jsonList, new TypeReference<List<CountryDto>>() {
});
}
/**
* {@inheritDoc}
*/
@Override
public List<CurrencyDto> retrieveCurrencies() throws IOException, UnirestException {
HttpResponse<JsonNode> response = uniRestService.get(CURRENCIES_FORMAT);
if (response.getStatus() != HttpStatus.SC_OK) {
return null;
}
String jsonList = response.getBody().getObject().get(CURRENCIES_KEY).toString();
return objectMapper.readValue(jsonList, new TypeReference<List<CurrencyDto>>() {
});
}
}
Gdzie
- @Autowired to adnotacja mówiąca, że należy wstrzyknąć obiekt do tej klasy i używać go bez jego tworzenia, czyli bez nowej operacji Object;
- @Component to adnotacja mówiąca, że ten obiekt musi zostać dodany do kontekstu aplikacji, aby można go było później wstrzyknąć za pomocą adnotacji @Autowired;
- ObjectMapper objectMapper to obiekt z projektu Jackson, który tłumaczy to wszystko na obiekty Java.
- WalutaDTO i krajDto:
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* Data transfer object for Currency.
*/
@Data
public class CurrencyDto {
@JsonProperty("Code")
private String code;
@JsonProperty("Symbol")
private String symbol;
@JsonProperty("ThousandsSeparator")
private String thousandsSeparator;
@JsonProperty("DecimalSeparator")
private String decimalSeparator;
@JsonProperty("SymbolOnLeft")
private boolean symbolOnLeft;
@JsonProperty("SpaceBetweenAmountAndSymbol")
private boolean spaceBetweenAmountAndSymbol;
@JsonProperty("RoundingCoefficient")
private int roundingCoefficient;
@JsonProperty("DecimalDigits")
private int decimalDigits;
}
и
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* Data transfer object for Country.
*/
@Data
public class CountryDto {
@JsonProperty("Code")
private String code;
@JsonProperty("Name")
private String name;
}
Aby wstrzyknąć ObjectMapper do dowolnej części projektu, dodałem utworzenie i dodanie go do ApplicationContext za pośrednictwem klasy konfiguracyjnej.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link Configuration} class.
*/
@Configuration
public class Config {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
return objectMapper;
}
}
Adnotacja @Configuration informuje Springa, że w tej klasie będą pewne konfiguracje. I właśnie w tym celu dodałem ObjectMapper. Podobnie dodajemy PlacesClient i PlacesClientImpl:
import com.github.romankh3.flightsmonitoring.client.dto.PlaceDto;
import com.github.romankh3.flightsmonitoring.client.dto.PlacesDto;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.io.IOException;
import java.util.List;
/**
* SkyScanner client.
*/
public interface PlacesClient {
/**
* Get a list of places that match a query string based on arguments.
*
* @param query the code of the city.
* @param country the code of the country.
* @param currency the code of the currency.
* @param locale the code of the locale.
* @return the collection of the {@link PlaceDto} objects.
*/
List<PlacesDto> retrieveListPlaces(String query, String country, String currency, String locale)
throws IOException, UnirestException;
}
I
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.PLACES_FORMAT;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.PLACES_KEY;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.romankh3.flightsmonitoring.client.dto.PlacesDto;
import com.github.romankh3.flightsmonitoring.client.service.PlacesClient;
import com.github.romankh3.flightsmonitoring.client.service.UniRestService;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.io.IOException;
import java.util.List;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* {@inheritDoc}
*/
@Service
public class PlacesClientImpl implements PlacesClient {
@Autowired
private UniRestService uniRestService;
@Autowired
private ObjectMapper objectMapper;
/**
* {@inheritDoc}
*/
@Override
public List<PlacesDto> retrieveListPlaces(String query, String country, String currency, String locale)
throws IOException, UnirestException {
HttpResponse<JsonNode> response = uniRestService
.get(String.format(PLACES_FORMAT, country, currency, locale, query));
if (response.getStatus() != HttpStatus.SC_OK) {
return null;
}
String jsonList = response.getBody().getObject().get(PLACES_KEY).toString();
return objectMapper.readValue(jsonList, new TypeReference<List<PlacesDto>>() {
});
}
}
gdzie PlacesDto ma postać:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.github.romankh3.flightsmonitoring.client.service.PlacesClient;
import lombok.Data;
/**
* Using for {@link PlacesClient}.
*/
@Data
public class PlacesDto {
@JsonProperty("PlaceId")
private String placeId;
@JsonProperty("PlaceName")
private String placeName;
@JsonProperty("CountryId")
private String countryId;
@JsonProperty("RegionId")
private String regionId;
@JsonProperty("CityId")
private String cityId;
@JsonProperty("CountryName")
private String countryName;
}
I wreszcie obsługa klienta, która na podstawie niezbędnych danych zwróci cenę minimalną za lot i wszystkie niezbędne informacje: FlightPriceClient i FlightPriceClientImpl. Zrealizujemy tylko jedno żądanie, przeglądajQuotes. Cena lotuKlient:
import com.github.romankh3.flightsmonitoring.client.dto.FlightPricesDto;
/**
* Browse flight prices.
*/
public interface FlightPricesClient {
/**
* Browse quotes for current flight based on provided arguments. One-way ticket.
*
* @param country the country from
* @param currency the currency to get price
* @param locale locale for the response
* @param originPlace origin place
* @param destinationPlace destination place
* @param outboundPartialDate outbound date
* @return {@link FlightPricesDto} object.
*/
FlightPricesDto browseQuotes(String country, String currency, String locale, String originPlace,
String destinationPlace, String outboundPartialDate);
/**
* Browse quotes for current flight based on provided arguments. Round trip ticket.
*
* @param country the country from
* @param currency the currency to get price
* @param locale locale for the response
* @param originPlace origin place
* @param destinationPlace destination place
* @param outboundPartialDate outbound date
* @param inboundPartialDate inbound date
* @return {@link FlightPricesDto} object.
*/
FlightPricesDto browseQuotes(String country, String currency, String locale, String originPlace,
String destinationPlace, String outboundPartialDate, String inboundPartialDate);
}
LotCenaKlientImpl
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.CURRENCIES_KEY;
import static com.github.romankh3.flightsmonitoring.client.service.impl.UniRestServiceImpl.PLACES_KEY;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.romankh3.flightsmonitoring.client.dto.CarrierDto;
import com.github.romankh3.flightsmonitoring.client.dto.CurrencyDto;
import com.github.romankh3.flightsmonitoring.client.dto.FlightPricesDto;
import com.github.romankh3.flightsmonitoring.client.dto.PlaceDto;
import com.github.romankh3.flightsmonitoring.client.dto.QuoteDto;
import com.github.romankh3.flightsmonitoring.client.dto.ValidationErrorDto;
import com.github.romankh3.flightsmonitoring.client.service.FlightPricesClient;
import com.github.romankh3.flightsmonitoring.client.service.UniRestService;
import com.github.romankh3.flightsmonitoring.exception.FlightClientException;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import java.io.IOException;
import java.util.List;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* {@inheritDoc}
*/
@Service
public class FlightPricesClientImpl implements FlightPricesClient {
public static final String BROWSE_QUOTES_FORMAT = "/apiservices/browsequotes/v1.0/%s/%s/%s/%s/%s/%s";
public static final String OPTIONAL_BROWSE_QUOTES_FORMAT = BROWSE_QUOTES_FORMAT + "?inboundpartialdate=%s";
public static final String QUOTES_KEY = "Quotes";
public static final String ROUTES_KEY = "Routes";
public static final String DATES_KEY = "Dates";
public static final String CARRIERS_KEY = "Carriers";
public static final String VALIDATIONS_KEY = "ValidationErrors";
@Autowired
private UniRestService uniRestService;
@Autowired
private ObjectMapper objectMapper;
/**
* {@inheritDoc}
*/
@Override
public FlightPricesDto browseQuotes(String country, String currency, String locale, String originPlace,
String destinationPlace, String outboundPartialDate) {
HttpResponse<JsonNode> response = uniRestService.get(String
.format(BROWSE_QUOTES_FORMAT, country, currency, locale, originPlace, destinationPlace,
outboundPartialDate));
return mapToObject(response);
}
public FlightPricesDto browseQuotes(String country, String currency, String locale, String originPlace,
String destinationPlace, String outboundPartialDate, String inboundPartialDate) {
HttpResponse<JsonNode> response = uniRestService.get(String
.format(OPTIONAL_BROWSE_QUOTES_FORMAT, country, currency, locale, originPlace, destinationPlace,
outboundPartialDate, inboundPartialDate));
return mapToObject(response);
}
private FlightPricesDto mapToObject(HttpResponse<JsonNode> response) {
if (response.getStatus() == HttpStatus.SC_OK) {
FlightPricesDto flightPricesDto = new FlightPricesDto();
flightPricesDto.setQuotas(readValue(response.getBody().getObject().get(QUOTES_KEY).toString(),
new TypeReference<List<QuoteDto>>() {
}));
flightPricesDto.setCarriers(readValue(response.getBody().getObject().get(CARRIERS_KEY).toString(),
new TypeReference<List<CarrierDto>>() {
}));
flightPricesDto.setCurrencies(readValue(response.getBody().getObject().get(CURRENCIES_KEY).toString(),
new TypeReference<List<CurrencyDto>>() {
}));
flightPricesDto.setPlaces(readValue(response.getBody().getObject().get(PLACES_KEY).toString(),
new TypeReference<List<PlaceDto>>() {
}));
return flightPricesDto;
}
throw new FlightClientException(String.format("There are validation errors. statusCode = %s", response.getStatus()),
readValue(response.getBody().getObject().get(VALIDATIONS_KEY).toString(),
new TypeReference<List<ValidationErrorDto>>() {
}));
}
private <T> List<T> readValue(String resultAsString, TypeReference<List<T>> valueTypeRef) {
List<T> list;
try {
list = objectMapper.readValue(resultAsString, valueTypeRef);
} catch (IOException e) {
throw new FlightClientException("Object Mapping failure.", e);
}
return list;
}
}
gdzie FlightClientException wygląda następująco:
import com.github.romankh3.flightsmonitoring.client.dto.ValidationErrorDto;
import java.util.List;
/**
* A {@link RuntimeException} that is thrown in case of an flight monitoring failures.
*/
public final class FlightClientException extends RuntimeException {
public FlightClientException(String message) {
super(message);
}
public FlightClientException(String message, Throwable throwable) {
super(message, throwable);
}
public FlightClientException(String message, List<ValidationErrorDto> errors) {
super(message);
this.validationErrorDtos = errors;
}
private List<ValidationErrorDto> validationErrorDtos;
}
W rezultacie, według danych PlacesCl
GO TO FULL VERSION