1

Good morning, I consume API in JSON format, data on the latest exchange rates.

I want this data to be downloaded to me at the beginning of the application and saved in the database. I use spring JPA.

The problem is I do not know how I should write it down.

I have a class responsible for the connection which returns the output in the form of a String. Another creates de-serialization.

I also have two classes of model that I can use to download data.

I do not want to create a separate class in which the program will pull out each value individually. I was thinking about the map but I do not know how to do it.

Some code:

Model 1

@Data
@AllArgsConstructor
@Entity
public class CurrencyData {

    @Id
    @GeneratedValue( strategy = GenerationType.AUTO )
    private Long id;

    @SerializedName("rates")
    @Expose
    @Embedded
    private Rates rates;

    @SerializedName("base")
    @Expose
    @Embedded
    private String base;

    @SerializedName("date")
    @Expose
    @Embedded
    private String date;

}

Model 2

@Data
@AllArgsConstructor
@Embeddable
public class Rates {

    protected Rates(){}

    @SerializedName("CAD")
    @Expose
    private Double cAD;
    @SerializedName("HKD")
}

ConnectService with string api output

private static final String REQUEST_CURRENCY = "https://api.exchangeratesapi.io/latest?base=USD";

public String connect() {

    String output = null;
    try {

        System.out.println("URL String : " + REQUEST_CURRENCY);

        URL url = new URL(REQUEST_CURRENCY);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Accept", "application/json");

        if (conn.getResponseCode() != 200) {
            throw new TODO("TODO : ", e.getMessage());
        } else {

            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();

            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();
            output = response.toString();
        }
    } catch (Exception e) {

        throw new OutputFromApiException("ConnectService CurrencyData-API: output is : ", e.getMessage());
    }

    return output;
}

GsonConvert- Deserialization

public CurrencyData gsonCurrency(String answer) {

    Gson g = new Gson();
    CurrencyData currencyData = null;

    try {
         currencyData = g.fromJson(answer, CurrencyData.class);

    } catch (Exception e) {
       throw new OutputFromApiException("HistoricalFlight API output is empty ", e.toString());
    }


   return currencyData;
}

Repository

@Repository
public interface CurrencyRepository extends JpaRepository<CurrencyData, Long> {
}

... And probably I have to write something here..

@Bean
CommandLineRunner runner(CurrencyRepository currencyRepository) {
    return args -> {
        currencyRepository.save();
    };
}
Yavuz Tas
  • 344
  • 3
  • 16
Grafik Krystian
  • 179
  • 2
  • 13

2 Answers2

1

If you are using Spring Boot I think you should define a main class that implements CommandLineRunner instead of defining it as a @Bean. It should be something like:

@SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootConsoleApplication.class, args);
    }

    @Autowired
    CurrencyRepository currencyRepository;

    @Autowired
    ConnectService connectionService;

    @Override
    public void run(String... args) {

        String output = connectionService.connect();
        CurrencyData currencyData = connectionService.gsonCurrency(output);
        currencyRepository.save(currencyData);

    } 
}

Also I assumed that your jpa configuration is correct and your CurrencyRepository works as expected. If you do not have a manually created database structure than you may consider adding to application.properties file as:

spring.jpa.hibernate.ddl-auto=update

This will provide you that JPA creates or updates the proper database structures on every boot by using your entities configuration.

EDIT: Sorry I forgot to mention about that you should pass the entity which you want to persist into database. I edited the code as I guess gsonCurrency method is a method inside ConnectionService. Also you can pass a parameter to connectionService.connect() method for base if you want to fetch different data according to different base currencies like this:

CurrencyData currencyDataUSD = connectionService.gsonCurrency(connectionService.connect("USD"));
CurrencyData currencyDataEUR = connectionService.gsonCurrency(connectionService.connect("EUR"));
// and go on if you like
Yavuz Tas
  • 344
  • 3
  • 16
0

You can use Spring Boot and Rest Template so that you can easily manage the message conversion without having to write the low level HttpConnection. There are two ways to execute a method when an application startup happens in Spring Boot, CommandLineRunner and ApplicationRunner, and here we are using the first as shown below :

@SpringBootApplication
public class Application {

private static final Logger log = LoggerFactory.getLogger(Application.class);

public static void main(String args[]) {
    SpringApplication.run(Application.class);
}

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

@Bean
public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
    return args -> {
        Quote quote = restTemplate.getForObject(
                "https://gturnquist-quoters.cfapps.io/api/random", Quote.class);
        log.info(quote.toString());
    };
}

}

Source: https://spring.io/guides/gs/consuming-rest/

royalghost
  • 2,773
  • 5
  • 23
  • 29
  • Ok thank You! But I am still don't know how can I save to database. I have tried to add @entity annotation but without expected result .. I have got errors for example : "Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Repeated column in mapping for entity: com.flightradar.flightradar.model.currency.CurrencyData column: hash (should be mapped with insert="false" update="false")" Can You write me exactly what should I do ? – Grafik Krystian Jun 29 '19 at 15:35
  • You need to create a database and use the Repository interface to save it - https://spring.io/guides/gs/accessing-data-jpa/ – royalghost Jun 29 '19 at 17:14