App doesn't get all data from retrofit api - java

I finished turial from https://www.simplifiedcoding.net/retrofit-android-example/
And I wanted to create my own call, I wanted to get from API newest currency exchange, but I've got a problem (i think so this is it) with my model class. I've changed a bit code, and I've received data as "base" and "date", but whenewer I trying to get some currency value (let's take an BGN for example) program shows me always 0.0. How I may fix it? I right about that model class? Is there a problem?
Model
public class Model {
private String base,date;
private double BGN;
public Model(String base, String date, double BGN) {
this.base = base;
this.date = date;
this.BGN = BGN;
}
public String getBase() {
return base;
}
public String getDate() {
return date;
}
public double getBGN() {
return BGN;
}
}
Api (interface)
public interface Api {
String BASE_URL = "https://api.exchangeratesapi.io/";
#GET("latest")
Call<Model> getCurrency();
}
MainActivity
public class MainActivity extends AppCompatActivity {
private TextView textViewResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textViewResult = (TextView) findViewById(R.id.label);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Api.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
Api api = retrofit.create(Api.class);
Call<Model> call = api.getCurrency();
call.enqueue(new Callback<Model>() {
#Override
public void onResponse(Call<Model> call, Response<Model> response) {
List<Model> currencyList = Collections.singletonList(response.body());
for (Model currency : currencyList) {
String content = "";
content += "Base: " + currency.getBase() + "\n";
content += "Date: " + currency.getDate() + "\n";
content += "BGN: " + currency.getBGN() + "\n";
textViewResult.append(content);
}
}
#Override
public void onFailure(Call<Model> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
}
Api, that I trying to use https://exchangeratesapi.io/

To get all the data from retrofit, you need two POJO classes. They need to be like this where you add methods and variables for all the rates you need:
public class Model {
private String base;
private String date;
Rates RatesObject;
// Getter Methods
public String getBase() {
return base;
}
public String getDate() {
return date;
}
public Rates getRates() {
return RatesObject;
}
// Setter Methods
public void setBase(String base) {
this.base = base;
}
public void setDate(String date) {
this.date = date;
}
public void setRates(Rates ratesObject) {
this.RatesObject = ratesObject;
}
}
public class Rates {
private float CAD;
private float CHF;
private float GBP;
private float SEK;
private float EUR;
private float USD;
// Getter Methods
public float getCAD() {
return CAD;
}
public float getCHF() {
return CHF;
}
public float getGBP() {
return GBP;
}
public float getSEK() {
return SEK;
}
public float getEUR() {
return EUR;
}
public float getUSD() {
return USD;
}
// Setter Methods
public void setCAD(float CAD) {
this.CAD = CAD;
}
public void setCHF(float CHF) {
this.CHF = CHF;
}
public void setGBP(float GBP) {
this.GBP = GBP;
}
public void setSEK(float SEK) {
this.SEK = SEK;
}
public void setEUR(float EUR) {
this.EUR = EUR;
}
public void setUSD(float USD) {
this.USD = USD;
}
}

Related

How to retrieve data using retofit in Android Studio

https://pro-api.coinmarketcap.com/v1/tools/price-conversion?symbol=NGN&amount=1000897.01&convert=BTC&CMC_PRO_API_KEY=*********************************
That's the url and here is the json returned from querying that url:
{"status":{"timestamp":"2021-04-20T08:48:16.990Z","error_code":0,"error_message":null,"elapsed":17,"credit_count":1,"notice":null},"data":{"id":2819,"symbol":"NGN","name":"Nigerian Naira","amount":1000897.01,"last_updated":"2021-04-20T08:48:07.000Z","quote":{"BTC":{"price":0.0444454708294559,"last_updated":"2021-04-20T08:48:02.000Z"}}}}
the following is my code in android studio to get data from the above api en point
My pojo classes:
import com.google.gson.annotations.SerializedName;
public class CurrencyModel {
#SerializedName("name")
private String currencyName;
#SerializedName("Amount")
private int currencyAmount;
#SerializedName("quote")
Quota quota;
public CurrencyModel(Quota quota) {
this.quota = quota;
// quota.bitcoinModel.getCoinPrice();
}
public CurrencyModel(String currencyName, int currencyAmount, Quota quota) {
this.currencyName = currencyName;
this.currencyAmount = currencyAmount;
this.quota = quota;
}
public String getCurrencyName() {
return currencyName;
}
public void setCurrencyName(String currencyName) {
this.currencyName = currencyName;
}
public int getCurrencyAmount() {
return currencyAmount;
}
public void setCurrencyAmount(int currencyAmount) {
this.currencyAmount = currencyAmount;
}
public Quota getQuota() {
return quota;
}
public void setQuota(Quota quota) {
this .quota = quota;
}
public class Quota {
int price;
#SerializedName("BTC")
BitcoinModel bitcoinModel;
public Quota(BitcoinModel bitcoinModel) {
this.bitcoinModel = bitcoinModel;
}
public BitcoinModel getBitcoinModel() {
return bitcoinModel = new BitcoinModel(price);
}
public void setBitcoinModel(BitcoinModel bitcoinModel) {
this.bitcoinModel = bitcoinModel;
}
}
public class BitcoinModel {
#SerializedName("price")
private int coinPrice;
public BitcoinModel(int coinPrice) {
this.coinPrice = coinPrice;
}
public int getCoinPrice() {
return coinPrice;
}
public void setCoinPrice(int coinPrice) {
this.coinPrice = coinPrice;
}
}
My activity
public class BitcoinConversionActivity extends AppCompatActivity {
TextInputEditText amountConverted;
Button conversionButton, buyCoinButton;
TextView amountInCurrency;
int amount;
String amountEntered;
Quota quota;
CurrencyModel currencyModel;
JsonPojo pojo;
String symbol = "NGN";
String convert = "BTC";
int amountneeded = 1024587;
String apiKey = "b34416c7-2bb9-44b1-aa76-1293edd14dda";
String currencyName;
int amountnm;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coinconversion);
amountConverted = findViewById(R.id.amount_edit_text);
amountInCurrency = findViewById(R.id.conversion_rate_tv);
conversionButton = findViewById(R.id.conversion_button);
buyCoinButton = findViewById(R.id.buy_exchange_coin_button);
conversionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
amount = Integer.parseInt(amountConverted.getText().toString());
if (TextUtils.isEmpty(Double.toString(amount))){
Toast.makeText(BitcoinConversionActivity.this, "Please Enter a valid Amount", Toast.LENGTH_LONG).show();
}else{
CoinExchange();
}
}
});
}
private void CoinExchange() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://pro-api.coinmarketcap.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
BitcoinInterface service = retrofit.create(BitcoinInterface.class);
Call<CurrencyModel> call = service.loadNairaToBitcionExchange(symbol,amountneeded,convert,apiKey);
call.enqueue(new Callback<CurrencyModel>() {
#Override
public void onResponse(Call<CurrencyModel> call, Response<CurrencyModel> response) {
if (response.isSuccessful()){
String price = response.body().toString();
//amountInCurrency.setText(price);
amountInCurrency.setText("https://pro-api.coinmarketcap.com/"+symbol+amount+convert+apiKey);
Toast.makeText(BitcoinConversionActivity.this, "Data: " + response.body().getQuota().getBitcoinModel().getCoinPrice(), Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(Call<CurrencyModel> call, Throwable t) {
Toast.makeText(BitcoinConversionActivity.this, "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
API interface:
public interface BitcoinInterface {
#GET("v1/tools/price-conversion?")
Call<CurrencyModel> loadNairaToBitcionExchange(#Query("symbol") String coinsSymbol,
#Query("amount") int currencyaAmount,
#Query("convert") String convertedToCurrency,
#Query("CMC_PRO_API_KEY") String ApiKey);
}
The call is returning null and at times zero.
From the API you are not getting exactly the CurrencyModel as response. You are getting another object which is CurrencyModel is a child object.
You have to create resposne object like below:
public class ResponseObject{
//#SerializedName("status")
//private int status;
#SerializedName("data")
private CurrencyModel currencyModel;
//getters and setters goes here
}
And then your interface should be like below as you are expecting ResponseObject here
public interface BitcoinInterface {
#GET("v1/tools/price-conversion?")
Call<ResponseObject> loadNairaToBitcionExchange(#Query("symbol") String coinsSymbol,
#Query("amount") int currencyaAmount,
#Query("convert") String convertedToCurrency,
#Query("CMC_PRO_API_KEY") String ApiKey);
}

Android NetworkBoundResource using repository pattern API error

Hi I am just started with mvvm with repository pattern I am stuck with the API error
I am using the generic API Response class as per google official repo in java
/**
* Generic class for handling responses from Retrofit
*
* #param <T>
*/
public class ApiResponse<T> {
public ApiResponse<T> create(Throwable error) {
return new ApiErrorResponse<>(error.getMessage().equals("") ? error.getMessage() : "Unknown error\nCheck network connection");
}
public ApiResponse<T> create(Response<T> response) {
if (response.isSuccessful()) {
T body = response.body();
if (body instanceof GithubApiResponse) {
if (AppUtils.isValid((GithubApiResponse) body)) {
String errorMsg = "Empty Response.";
return new ApiErrorResponse<>(errorMsg);
}
}
if (body == null || response.code() == 204) { // 204 is empty response
return new ApiEmptyResponse<>();
} else {
return new ApiSuccessResponse<>(body);
}
} else {
String errorMsg = "";
try {
errorMsg = response.errorBody().string();
} catch (IOException e) {
e.printStackTrace();
errorMsg = response.message();
}
return new ApiErrorResponse<>(errorMsg);
}
}
/**
* Generic success response from api
*
* #param <T>
*/
public class ApiSuccessResponse<T> extends ApiResponse<T> {
private T body;
ApiSuccessResponse(T body) {
this.body = body;
}
public T getBody() {
return body;
}
}
/**
* Generic Error response from API
*
* #param <T>
*/
public class ApiErrorResponse<T> extends ApiResponse<T> {
private String errorMessage;
ApiErrorResponse(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getErrorMessage() {
return errorMessage;
}
}
/**
* separate class for HTTP 204 resposes so that we can make ApiSuccessResponse's body non-null.
*/
public class ApiEmptyResponse<T> extends ApiResponse<T> {
}
}
and My networkBoundResource as like this
public abstract class NetworkBoundResource<ResultType, RequestType> {
private AppExecutors appExecutors;
private MediatorLiveData<Resource<ResultType>> results = new MediatorLiveData<>();
public NetworkBoundResource(AppExecutors appExecutors) {
this.appExecutors = appExecutors;
init();
}
private void init() {
// update LiveData for loading status
results.setValue((Resource<ResultType>) Resource.loading(null));
// observe LiveData source from local db
final LiveData<ResultType> dbSource = loadFromDb();
results.addSource(dbSource, new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
results.removeSource(dbSource);
if (shouldFetch(ResultType)) {
// get data from the network
fetchFromNetwork(dbSource);
} else {
results.addSource(dbSource, new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(Resource.success(ResultType));
}
});
}
}
});
}
/**
* 1) observe local db
* 2) if <condition/> query the network
* 3) stop observing the local db
* 4) insert new data into local db
* 5) begin observing local db again to see the refreshed data from network
*
* #param dbSource
*/
private void fetchFromNetwork(final LiveData<ResultType> dbSource) {
Timber.d("fetchFromNetwork: called.");
// update LiveData for loading status
results.addSource(dbSource, new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(Resource.loading(ResultType));
}
});
final LiveData<ApiResponse<RequestType>> apiResponse = createCall();
results.addSource(apiResponse, new Observer<ApiResponse<RequestType>>() {
#Override
public void onChanged(#Nullable final ApiResponse<RequestType> requestObjectApiResponse) {
results.removeSource(dbSource);
results.removeSource(apiResponse);
/*
3 cases:
1) ApiSuccessResponse
2) ApiErrorResponse
3) ApiEmptyResponse
*/
if (requestObjectApiResponse instanceof ApiResponse.ApiSuccessResponse) {
Timber.d("onChanged: ApiSuccessResponse.");
appExecutors.diskIO().execute(new Runnable() {
#Override
public void run() {
// save the response to the local db
saveCallResult((RequestType) processResponse((ApiResponse.ApiSuccessResponse) requestObjectApiResponse));
appExecutors.mainThread().execute(new Runnable() {
#Override
public void run() {
results.addSource(loadFromDb(), new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(Resource.success(ResultType));
}
});
}
});
}
});
} else if (requestObjectApiResponse instanceof ApiResponse.ApiEmptyResponse) {
Timber.d("onChanged: ApiEmptyResponse");
appExecutors.mainThread().execute(new Runnable() {
#Override
public void run() {
results.addSource(loadFromDb(), new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(Resource.success(ResultType));
}
});
}
});
} else if (requestObjectApiResponse instanceof ApiResponse.ApiErrorResponse) {
Timber.d("onChanged: ApiErrorResponse.");
results.addSource(dbSource, new Observer<ResultType>() {
#Override
public void onChanged(#Nullable ResultType ResultType) {
setValue(
Resource.error(
((ApiResponse.ApiErrorResponse) requestObjectApiResponse).getErrorMessage(),
ResultType
)
);
}
});
}
}
});
}
private ResultType processResponse(ApiResponse.ApiSuccessResponse response) {
return (ResultType) response.getBody();
}
private void setValue(Resource<ResultType> newValue) {
if (results.getValue() != newValue) {
results.setValue(newValue);
}
}
// Called to save the result of the API response into the database.
#WorkerThread
protected abstract void saveCallResult(#NonNull RequestType item);
// Called with the data in the database to decide whether to fetch
// potentially updated data from the network.
#MainThread
protected abstract boolean shouldFetch(#Nullable ResultType data);
// Called to get the cached data from the database.
#NonNull
#MainThread
protected abstract LiveData<ResultType> loadFromDb();
// Called to create the API call.
#NonNull
#MainThread
protected abstract LiveData<ApiResponse<RequestType>> createCall();
// Returns a LiveData object that represents the resource that's implemented
// in the base class.
public final LiveData<Resource<ResultType>> getAsLiveData() {
return results;
}
}
my Repository looks like this
#Singleton
public class GithubRepository {
private GithubDao githubDao;
private GithubTrendingApiService githubApiService;
public GithubRepository(GithubDao githubDao, GithubTrendingApiService githubApiService) {
this.githubDao = githubDao;
this.githubApiService = githubApiService;
}
public LiveData<Resource<List<GithubEntity>>> getRepositories() {
return new NetworkBoundResource<List<GithubEntity>, GithubApiResponse>(AppExecutors.getInstance()) {
#Override
protected void saveCallResult(#NonNull GithubApiResponse item) {
List<GithubEntity> repositories = item.getItems();
githubDao.insertRepositories(repositories);
}
#Override
protected boolean shouldFetch(#Nullable List<GithubEntity> data) {
// Timber.d("shouldFetch: repo: " + data.toString());
// int currentTime = (int) (System.currentTimeMillis() / 1000);
// Timber.d("shouldFetch: current time: " + currentTime);
// int lastRefresh = data.getTimestamp();
// Timber.d("shouldFetch: last refresh: " + lastRefresh);
// Timber.d("shouldFetch: it's been " + ((currentTime - lastRefresh) / 60 / 60 / 24) +
// " days since this recipe was refreshed. 30 days must elapse before refreshing. ");
// if ((currentTime - data.getTimestamp()) >= Constants.RECIPE_REFRESH_TIME) {
// Timber.d("shouldFetch: SHOULD REFRESH RECIPE?! " + true);
// return true;
// }
// Timber.d("shouldFetch: SHOULD REFRESH RECIPE?! " + false);
return true;
}
#NonNull
#Override
protected LiveData<List<GithubEntity>> loadFromDb() {
return githubDao.getTrendingRepository();
}
#NonNull
#Override
protected LiveData<ApiResponse<GithubApiResponse>> createCall() {
return githubApiService.fetchTrendingRepositories();
}
}.getAsLiveData();
}
}
Can anyone tell me whats I am doing wrong because I am getting an API error? somehow I am not able to get the correct data that's why the database is also not filling up
my GithubAPi response class is this
public class GithubApiResponse {
public GithubApiResponse() {
this.items = new ArrayList<>();
}
public GithubApiResponse(List<GithubEntity> items) {
this.items = items;
}
private List<GithubEntity> items;
public List<GithubEntity> getItems() {
return items;
}
public void setItems(List<GithubEntity> items) {
this.items = items;
}
}
and the Entity class is this
#Entity
public class GithubEntity implements Parcelable {
public GithubEntity(#NonNull Long id, String author, String name, String avatar,
String url, String description, Integer stars, Integer forks, Integer currentPeriodStars, String language, String languageColor) {
this.id = id;
this.author = author;
this.name = name;
this.avatar = avatar;
this.url = url;
this.description = description;
this.stars = stars;
this.forks = forks;
this.currentPeriodStars = currentPeriodStars;
this.language = language;
this.languageColor = languageColor;
}
#NonNull
#PrimaryKey
private Long id;
#SerializedName("author")
#Expose
private String author;
#SerializedName("name")
#Expose
private String name;
#SerializedName("avatar")
#Expose
private String avatar;
#SerializedName("url")
#Expose
private String url;
#SerializedName("description")
#Expose
private String description;
#SerializedName("stars")
#Expose
private Integer stars;
#SerializedName("forks")
#Expose
private Integer forks;
#SerializedName("currentPeriodStars")
#Expose
private Integer currentPeriodStars;
#SerializedName("language")
#Expose
private String language;
#SerializedName("languageColor")
#Expose
private String languageColor;
#NonNull
public Long getId() {
return id;
}
public void setId(#NonNull Long id) {
this.id = id;
}
protected GithubEntity(Parcel in) {
author = in.readString();
name = in.readString();
avatar = in.readString();
url = in.readString();
description = in.readString();
if (in.readByte() == 0) {
stars = null;
} else {
stars = in.readInt();
}
if (in.readByte() == 0) {
forks = null;
} else {
forks = in.readInt();
}
if (in.readByte() == 0) {
currentPeriodStars = null;
} else {
currentPeriodStars = in.readInt();
}
language = in.readString();
languageColor = in.readString();
}
public static final Creator<GithubEntity> CREATOR = new Creator<GithubEntity>() {
#Override
public GithubEntity createFromParcel(Parcel in) {
return new GithubEntity(in);
}
#Override
public GithubEntity[] newArray(int size) {
return new GithubEntity[size];
}
};
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStars() {
return stars;
}
public void setStars(Integer stars) {
this.stars = stars;
}
public Integer getForks() {
return forks;
}
public void setForks(Integer forks) {
this.forks = forks;
}
public Integer getCurrentPeriodStars() {
return currentPeriodStars;
}
public void setCurrentPeriodStars(Integer currentPeriodStars) {
this.currentPeriodStars = currentPeriodStars;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getLanguageColor() {
return languageColor;
}
public void setLanguageColor(String languageColor) {
this.languageColor = languageColor;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(author);
dest.writeString(name);
dest.writeString(avatar);
dest.writeString(url);
dest.writeString(description);
if (stars == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(stars);
}
if (forks == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(forks);
}
if (currentPeriodStars == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(currentPeriodStars);
}
dest.writeString(language);
dest.writeString(languageColor);
}
}
can anyone guide me so that I can fix this issue? stuck here for 2 days

How to configure project for this exact Json?

I have an issue with Json
when i use Gson everything is working properly, but when i use retrofit2 something is going wrong.
Class structure is exact same between retrofit and gson. difference is one additional interface and retrofit codes which is working in different cases
i uploaded every piece of code here.
String json2 = "{\"busList\":{\"bus\":[{\"forward\":\"true\",\"lat\": \"41.718979\",\"lon\": \"44.770645\",\"nextStopId\": \"1858\",\"routeNumber\": \"42\"},{\"forward\": \"true\",\"lat\": \"41.71735\",\"lon\": \"44.777855\",\"nextStopId\": \"924\",\"routeNumber\": \"42\" }]}}";
//project structure
//Class1
public class FatherBusList {
#SerializedName("busList")
private BusList busList;
public FatherBusList(BusList busList){
this.busList = busList;
}
public BusList getBusList() {
return busList;
}
}
//Class2
public class BusList {
#SerializedName("bus")
private List<Bus> buses;
public BusList (List<Bus> busses){
this.buses = busses;
}
public List<Bus> getBuses() {
return buses;
}
}
//Class3
public class Bus {
private String forward;
private String lat;
private String lon;
private String nextStopId;
private String routeNumber;
public Bus(String forward, String lat, String lon, String nextStopId, String routeNumber) {
this.forward = forward;
this.lat = lat;
this.lon = lon;
this.nextStopId = nextStopId;
this.routeNumber = routeNumber;
}
public String getForward() {
return forward;
}
public String getLat() {
return lat;
}
public String getLon() {
return lon;
}
public String getNextStopId() {
return nextStopId;
}
public String getRouteNumber() {
return routeNumber;
}
}
//retrofit2 code
//Interface for request
public interface TtcApi {
#GET("buses?routeNumber=37&forward=1&_dc=1556996108032")
Call<FatherBusList> getBus();
}
//MainActivivty
public class MainActivity extends AppCompatActivity {
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://transit.ttc.com.ge/pts-portal-services/")
.addConverterFactory(GsonConverterFactory.create())
.build();
TtcApi ttcApi = retrofit.create(TtcApi.class);
Call<FatherBusList> call = ttcApi.getBus();
call.enqueue(new Callback<FatherBusList>() {
#Override
public void onResponse(Call<FatherBusList> call, Response<FatherBusList> response) {
if (!response.isSuccessful()) {
textView.setText("Code: " + response.code());
return;
}
Toast.makeText(MainActivity.this, "Successful", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<FatherBusList> call, Throwable t) {
textView.setText(t.getMessage());
}
});
}
}
I expect to busList have 1 object and this object have arrayList
But its output is null.
{
"bus": [
{
"forward": "true",
"lat": "41.690926",
"lon": "44.816879",
"nextStopId": "1012",
"routeNumber": "37"
}
]
}
I request for your interface, return it.
Your need direct use 'BusList' class entity,don't use 'FatherBusList'

Android - Retrofit2 - java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

I want to get data from the server (https://data.egov.kz/api/v2/zheke_zhane_zandy_tulgalardy_k1/v6?pretty) as an array of json objects. But I get this Log:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
I am using Retrofit2 and here my code:
MainActivity.java
public class MainActivity extends AppCompatActivity
implements GetAdmissionSchedule.GetAdmissionScheduleInterface {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GetAdmissionSchedule getAdmissionSchedule = new GetAdmissionSchedule(this);
getAdmissionSchedule.getAdmissionScheduleList();
}
#Override
public void getAdmissionSchedule(List<AdmissionSchedule> admissionScheduleList) {
// here i get my data
}
}
GetAdmissionSchedule.java
public class GetAdmissionSchedule {
private GetAdmissionScheduleInterface getAdmissionScheduleInterface;
public GetAdmissionSchedule(GetAdmissionScheduleInterface getAdmissionScheduleInterface) {
this.getAdmissionScheduleInterface = getAdmissionScheduleInterface;
}
public interface GetAdmissionScheduleInterface {
void getAdmissionSchedule(List<AdmissionSchedule> admissionScheduleList);
}
public void getAdmissionScheduleList() {
DataEgovApi service = DataEgovBaseURL.getRetrofit();
Call<List<AdmissionSchedule>> call = service.getAdmissionScheduleList();
call.enqueue(new Callback<List<AdmissionSchedule>>() {
#Override
public void onResponse(Call<List<AdmissionSchedule>> call, Response<List<AdmissionSchedule>> response) {
Log.d("MyLogs", "MVD: getAdmissionScheduleList " + response.code());
getAdmissionScheduleInterface.getAdmissionSchedule(response.body());
}
#Override
public void onFailure(Call<List<AdmissionSchedule>> call, Throwable t) {
Log.d("MyLogs", "MVD: getAdmissionScheduleList " + t.getLocalizedMessage());
getAdmissionScheduleInterface.getAdmissionSchedule(null);
}
});
}
}
DataEgovBaseURL.java
public class DataEgovBaseURL {
private static final String BASE_URL = "https://data.egov.kz/";
private static Retrofit retrofit = null;
public static DataEgovApi getRetrofit() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit.create(DataEgovApi.class);
}
}
DataEgovApi.java
public interface DataEgovApi {
#GET("api/v2/zheke_zhane_zandy_tulgalardy_k1/v6?pretty")
Call<List<AdmissionSchedule>> getAdmissionScheduleList();
}
AdmissionSchedule.java (My POJO class)
public class AdmissionSchedule {
#SerializedName("id")
#Expose
private String id;
#SerializedName("vremia")
#Expose
private String vremia;
#SerializedName("adres_ru")
#Expose
private String adresRu;
#SerializedName("doljnost_ru")
#Expose
private String doljnostRu;
#SerializedName("name_ru")
#Expose
private String nameRu;
#SerializedName("data")
#Expose
private String data;
#SerializedName("adres_kz")
#Expose
private String adresKz;
#SerializedName("doljnost_kz")
#Expose
private String doljnostKz;
#SerializedName("name_kz")
#Expose
private String nameKz;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getVremia() {
return vremia;
}
public void setVremia(String vremia) {
this.vremia = vremia;
}
public String getAdresRu() {
return adresRu;
}
public void setAdresRu(String adresRu) {
this.adresRu = adresRu;
}
public String getDoljnostRu() {
return doljnostRu;
}
public void setDoljnostRu(String doljnostRu) {
this.doljnostRu = doljnostRu;
}
public String getNameRu() {
return nameRu;
}
public void setNameRu(String nameRu) {
this.nameRu = nameRu;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getAdresKz() {
return adresKz;
}
public void setAdresKz(String adresKz) {
this.adresKz = adresKz;
}
public String getDoljnostKz() {
return doljnostKz;
}
public void setDoljnostKz(String doljnostKz) {
this.doljnostKz = doljnostKz;
}
public String getNameKz() {
return nameKz;
}
public void setNameKz(String nameKz) {
this.nameKz = nameKz;
}
}
You server url is https and certificate is already not valid.
Change https to http and it will work.
Else you can install valid SSL certificate on the server.

Finding Latitude and Longitude via Zip Codes in Java

I'm having trouble retrieving latitude and longitude values from a given zip code. I'm attempting to do this via a Servlet, i.e. a zip code value is passed into the Servlet, and the Java code then uses the Google Geocode API to retrieve the latitude and longitude values, preferably in a String.
I've roamed all over the net for a simple sample, but there seems to be more Javascript and PHP methods for this than Java.
Could someone please paste a simple sample of how to extract the lat/long values in this manner?
Thanks in advance!!
-Rei
OK long answer. This is some code I have used succesfully to interrogate Google Geocode API. It requires to work with GSon but alternatively you can probably decode the answers manually if you don't want to use GSon:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import org.slf4j.Logger;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
public class GeoCoder {
private Gson gson = new Gson();
private volatile long lastRequest = 0L;
public GeocodeResponse getLocation(String... addressElements) throws JsonSyntaxException, JsonIOException, MalformedURLException,
IOException {
StringBuilder sb = new StringBuilder();
for (String string : addressElements) {
if (sb.length() > 0) {
sb.append('+');
}
sb.append(URLEncoder.encode(string.replace(' ', '+'), "UTF-8"));
}
String url = "http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=" + sb.toString();
// Google limits this web service to 2500/day and 10 requests/s
synchronized (this) {
try {
long elapsed = System.currentTimeMillis() - lastRequest;
if (elapsed < 100) {
try {
Thread.sleep(100 - elapsed);
} catch (InterruptedException e) {
}
}
return gson.fromJson(new BufferedReader(new InputStreamReader(new URL(url).openStream())), GeocodeResponse.class);
} finally {
lastRequest = System.currentTimeMillis();
}
}
}
}
And the other classes:
GeocodeResponse:
import java.util.List;
public class GeocodeResponse {
public enum Status {
OK, ZERO_RESULTS, OVER_QUERY_LIMIT, REQUEST_DENIED, INVALID_REQUEST;
}
public static class Result {
public static enum Type {
street_address,
route,
intersection,
political,
country,
administrative_area_level_1,
administrative_area_level_2,
administrative_area_level_3,
colloquial_area,
locality,
sublocality,
neighborhood,
premise,
subpremise,
postal_code,
natural_feature,
airport,
park,
point_of_interest,
post_box,
street_number,
floor,
room;
}
public static class AddressComponent {
private String long_name;
private String short_name;
private Type[] types;
public String getLong_name() {
return long_name;
}
public void setLong_name(String long_name) {
this.long_name = long_name;
}
public String getShort_name() {
return short_name;
}
public void setShort_name(String short_name) {
this.short_name = short_name;
}
public Type[] getTypes() {
return types;
}
public void setTypes(Type[] types) {
this.types = types;
}
}
private String formatted_address;
private List<AddressComponent> address_components;
private Geometry geometry;
private Type[] types;
public Type[] getTypes() {
return types;
}
public void setTypes(Type[] types) {
this.types = types;
}
public String getFormatted_address() {
return formatted_address;
}
public void setFormatted_address(String formatted_address) {
this.formatted_address = formatted_address;
}
public List<AddressComponent> getAddress_components() {
return address_components;
}
public void setAddress_components(List<AddressComponent> address_components) {
this.address_components = address_components;
}
public Geometry getGeometry() {
return geometry;
}
public void setGeometry(Geometry geometry) {
this.geometry = geometry;
}
}
public static class Geometry {
public static enum LocationType {
ROOFTOP, RANGE_INTERPOLATED, GEOMETRIC_CENTER, APPROXIMATE;
}
public static class ViewPort {
private Location northeast;
private Location southwest;
public Location getNortheast() {
return northeast;
}
public void setNortheast(Location northeast) {
this.northeast = northeast;
}
public Location getSouthwest() {
return southwest;
}
public void setSouthwest(Location southwest) {
this.southwest = southwest;
}
}
private Location location;
private LocationType location_type;
private ViewPort viewport;
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public LocationType getLocation_type() {
return location_type;
}
public void setLocation_type(LocationType location_type) {
this.location_type = location_type;
}
public ViewPort getViewport() {
return viewport;
}
public void setViewport(ViewPort viewport) {
this.viewport = viewport;
}
}
private Status status;
private List<Result> results;
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public List<Result> getResults() {
return results;
}
public void setResults(List<Result> results) {
this.results = results;
}
}
Location:
public class Location {
private double lat;
private double lng;
public Location() {
}
public Location(double lat, double lng) {
this.lat = lat;
this.lng = lng;
}
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
public double getLng() {
return lng;
}
public void setLng(double lng) {
this.lng = lng;
}
}
This isn't as elegant as Guillaume Polet's answer, however it doesn't need additional libraries.
With the argument:
"1600 Amphitheatre Parkway, Mountain View, CA"
It prints the answer:
Latitude: 37.42207610
Longitude: -122.08451870
Here is the code:
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public class GoogleGeoCode
{
private static final String GEO_CODE_SERVER = "http://maps.googleapis.com/maps/api/geocode/json?";
public static void main(String[] args)
{
String code = args[0];
String response = getLocation(code);
String[] result = parseLocation(response);
System.out.println("Latitude: " + result[0]);
System.out.println("Longitude: " + result[1]);
}
private static String getLocation(String code)
{
String address = buildUrl(code);
String content = null;
try
{
URL url = new URL(address);
InputStream stream = url.openStream();
try
{
int available = stream.available();
byte[] bytes = new byte[available];
stream.read(bytes);
content = new String(bytes);
}
finally
{
stream.close();
}
return (String) content.toString();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
private static String buildUrl(String code)
{
StringBuilder builder = new StringBuilder();
builder.append(GEO_CODE_SERVER);
builder.append("address=");
builder.append(code.replaceAll(" ", "+"));
builder.append("&sensor=false");
return builder.toString();
}
private static String[] parseLocation(String response)
{
// Look for location using brute force.
// There are much nicer ways to do this, e.g. with Google's JSON library: Gson
// https://sites.google.com/site/gson/gson-user-guide
String[] lines = response.split("\n");
String lat = null;
String lng = null;
for (int i = 0; i < lines.length; i++)
{
if ("\"location\" : {".equals(lines[i].trim()))
{
lat = getOrdinate(lines[i+1]);
lng = getOrdinate(lines[i+2]);
break;
}
}
return new String[] {lat, lng};
}
private static String getOrdinate(String s)
{
String[] split = s.trim().split(" ");
if (split.length < 1)
{
return null;
}
String ord = split[split.length - 1];
if (ord.endsWith(","))
{
ord = ord.substring(0, ord.length() - 1);
}
// Check that the result is a valid double
Double.parseDouble(ord);
return ord;
}
}

Categories