Retrofit override method failure - java

I am new to android programming and I am trying to connect to server with retrofit and get some data. I made a little example just to check if it would return some data. First there is a problem that I don't know if I even wrote the code to do what I want and second I get the errors:
"Error:(64, 52) error: is not abstract and does not override abstract method failure(RetrofitError) in Callback"
and 2 errors " Error:(67, 13) error: method does not override or implement a method from a supertype"
Here is my code
public class MainActivity extends ListActivity{
public static final String ENDPOINT = "http://tinoba.hostzi.com";
List<Jelovnik> jelovnik;
Button gumb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gumb = (Button)findViewById(R.id.gumb);
}
public void stisni(View view) {
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ENDPOINT)
.build();
JelovnikAPI api = adapter.create(JelovnikAPI.class);
api.getFeed(new Callback<List<Jelovnik>>() {
#Override
public void onResponse(Response<List<Jelovnik>> response, Retrofit retrofit) {
jelovnik = response.body();
gumb.setText(jelovnik.get(0).getIme().toString());
}
#Override
public void onFailure(Throwable throwable) {
}
});
}
}
and my retrofit interface
public interface JelovnikAPI {
#GET("/read.php")
public void getFeed(Callback<List<Jelovnik>> response);
}

The version of Callback you are using is from Retrofit 2 and you are still using Retrofit 1.x. Callback has two methods, failure and success. Your callback should look like
new Callback<List<Jelovnik>>() {
#Override
success(List<Jelovnik> t, Response response) {
}
#Override
public void failure(RetrofitError error) {
}
});

Replace Throwable with RetrofitError:
#Override
public void onFailure(RetrofitError retrofitError) {
}

Related

How to use Retrofit in android studio? and what is my problem?

i made interface like this in "TestService.java"
public interface TestService {
#GET("/api/users/2")
Call<String> getTest();
}
and
"RetrofitClient.java"
public class RetrofitClient {
private static Retrofit instance;
public static Retrofit getInstance() {
if(instance == null)
instance = new Retrofit.Builder()
.baseUrl("https://reqres.in/")
.build();
return instance;
}
}
in "MainActivity.java"
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Retrofit retrofitClient = RetrofitClient.getInstance();
TestService testService = retrofitClient.create(TestService.class);
Call<String> repos = testService.getTest(); //problem
}
}
i'm first at android java, and i don't know how to use Retrofit..
what is the problem and how to print response? ( i need also header information)
You need to asynchronously call it on the main thread.
Call<ResponseBody> repos = testService.getTest();
repos.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//response
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//error
}
});
There are plenty of resources online, to know more you can go through the following articles.
vogella
android.jlelse

Best practice in java to create my own interface instead of existing one in retrofit for example

I am building the network structure in my android application i one of the things i realized is that i want to do is to create my own interface in my requests class .
i have this method for example :
public static void getUserData(String owner, final DataManager.OnDataReceived<Owner> listener) {
Call<Owner> call = getGitService().getUser(owner);
call.enqueue(new Callback<Owner>() {
#Override
public void onResponse(Call<Owner> call, Response<Owner> response) {
}
#Override
public void onFailure(Call<Owner> call, Throwable t) {
}
});
}
now...all my methods respond same way to the call back so why not handle this one time ?
so the way i did it it to create class that implement retrofit Callback interface :
private static class callbackHandler implements Callback {
final DataManager.OnDataReceived listener;
callbackHandler(DataManager.OnDataReceived listener) {
this.listener = listener;
}
#Override
public void onResponse(Call call, Response response) {
listener.onDataReceived(response.body(), getErrorFromResponse(response));
}
#Override
public void onFailure(Call call, Throwable t) {
listener.onDataReceived(null, t.toString());
}
}
so now all the request look like this :
public static void getUserData(String owner, final DataManager.OnDataReceived<Owner> listener) {
Call<Owner> call = getGitService().getUser(owner);
call.enqueue(new callbackHandler(listener));
}
much clearer ...
1 . what do you think about this solution ? i had better way to handle all Callback same way ?
2 . the compiler shout at me that
call.enqueue(new callbackHandler(listener));
and
#Override
public void onResponse(Call call, Response response) {
listener.onDataReceived(response.body(), getErrorFromResponse(response));
}
#Override
public void onFailure(Call call, Throwable t) {
listener.onDataReceived(null, t.toString());
}
and my interface :
public interface OnDataReceived<T> {
void onDataReceived(T data, String error);
}
is unchecked assignment...i understand what that means but not sure how to fix this ?
UPDATE : solution for the unchecked
private static class callbackHandler<T> implements Callback<T> {
final DataManager.OnDataReceived<T> listener;
callbackHandler(DataManager.OnDataReceived<T> listener) {
this.listener = listener;
}
#Override
public void onResponse(Call<T> call, Response<T> response) {
listener.onDataReceived(response.body(), getErrorFromResponse(response));
}
#Override
public void onFailure(Call<T> call, Throwable t) {
listener.onDataReceived(null, t.toString());
}
}
what do you think about this solution ?
This is called the adapter pattern. You are adapting one interface (Callback<Owner>) to another (DataManager.OnDataReceived<Owner>).
If your objective is to be able to replace Retrofit with something else in the future, this sort of adapter is perfectly reasonable. Otherwise, you might consider just having DataManager.OnDataReceived extend Callback and change your method names to match (e.g., onDataReceived() turns into onResponse()), to avoid the need for this adapter.
i understand what that means but not sure how to fix this
callbackHandler implements Callback wipes out the Java generics.
If this is only for use with Owner, use callbackHandler implements Callback<Owner> and have it hold a DataManager.OnDataReceived<Owner>. If you plan to use this for multiple model objects (assuming that Owner is a model), use callbackHandler implements Callback<T> and have it hold a DataManager.OnDataReceived<T>.

Android testing - Robolectric + Mockito + Retrofit getting Wanted but not invoked error

Trying to use Robolectric and Mockito to test my Retrofit calls in my Android app but I am getting the following error:
Wanted but not invoked: mockApi.register(
,
);
-> at ServiceTest.testAPI(ServiceTest.java:58) Actually, there were zero interactions with this mock.
The RetroFit API call is defined in an interface as follows:
#FormUrlEncoded
#POST("/register")
void register(
#FieldMap Map<String, String> registrationParams,
Callback<JsonObject> response) ;
My test class is as follows:
#Config(constants = BuildConfig.class)
#RunWith(TestRunner.class)
public class SharedServiceTest {
private RegistrationActivity activity;
#Mock
private SharedService mockApi;
#Captor
private ArgumentCaptor<Callback<JsonObject>> cb;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ActivityController<RegistrationActivity> controller = Robolectric.buildActivity(RegistrationActivity.class);
activity = controller.get();
controller.create();
}
#Test
public void testAPI() throws Exception {
activity.populateFields();
activity.validateFields();
activity.register("");
Mockito.verify(mockApi).register(Mockito.anyMap(), cb.capture());
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("sessionToken", Mockito.anyString());
jsonObject.addProperty("userId", Mockito.anyString());
cb.getValue().success(jsonObject, null);
Assert.assertTrue(ShadowToast.getTextOfLatestToast().contains("Registration completed"));
}
}
The method in my RegistrationActivity that uses the API is as follows:
public void register(){
MyApplication.getInstance().getSharedService().register(mRegistrationParams, new Callback<JsonObject>() {
#Override
public void success(JsonObject jsonObject, retrofit.client.Response response) {
Toast.makeText(RegistrationActivity.this, "Registration completed", Toast.LENGTH_LONG).show();
}
#Override
public void failure(RetrofitError error) {
Toast.makeText(RegistrationActivity.this, RetrofitUtils.getErrorMessage(error), Toast.LENGTH_LONG).show();
}
});
}
The real Retrofit service comes from my own Application class which I have mocked in my test folder for robolectric to use:
public class TestMyApplication extends MyApplication
implements TestLifecycleApplication {
#Override
public void onCreate() {
super.onCreate();
}
#Override public void beforeTest(Method method) {
}
#Override public void prepareTest(Object test) {
}
#Override public void afterTest(Method method) {
}
#Override public CPSharedService getCPSharedService() {
return Mockito.mock(SharedService.class);
}
}
I have searched over the other questions on SO that have this error but none of them match what I am trying to do here or provide a solution to my issue so I am just wondering what I am doing wrong?
The mocked instance of SharedService in your TestMyApplication is not the same you declared your test class.
The Mockito.verify(mockApi).register(Mockito.anyMap(), cb.capture()); is failing because the instance referred by mockApi field is actually never called.
Another problem is that the getter in TestMyApplication always returns a new mock for each invokation:
#Override public CPSharedService getCPSharedService() {
return Mockito.mock(SharedService.class); //this creates a new "mocked" instance
}
Your scenario is not 100% clear to me, but it would be better if you could let your test set the instance of the mockApi field in your TestMyApplication instance:
public class TestMyApplication extends MyApplication
implements TestLifecycleApplication {
private SharedService sharedService;
#Override
public void onCreate() {
super.onCreate();
}
#Override public void beforeTest(Method method) {
}
#Override public void prepareTest(Object test) {
}
#Override public void afterTest(Method method) {
}
#Override public CPSharedService getCPSharedService() {
return this.sharedService;
}
public void setCPSharedService(SharedService sharedService) {
// store your mock
this.sharedService = sharedService;
}
}
and in your test class:
#Test
public void testAPI() throws Exception {
// configure you TestMyApplication
assertTrue(MyApplication.getInstance() instanceof TestMyApplication);
TestMyApplication testMyApp = (TestMyApplication) MyApplication.getInstance();
testMyApp.setCPSharedService(this.mockApi);
activity.populateFields();
activity.validateFields();
activity.register("");
Mockito.verify(this.mockApi).register(Mockito.anyMap(), cb.capture());
...
}

Android/Java retrofit: Class cannot be converted to Callback

I'm new to retrofit and i am trying te get a json response to an object called RootObject. The error that i am stuck with is :
"Error:(21, 44) error: incompatible types: NewsController cannot be
converted to Callback>"
Does someone now my mistake here? thanks in regards!
public class NewsController {
public void getNews(){
Retrofit retrofit = new Retrofit.Builder().baseUrl("apilink").addConverterFactory(GsonConverterFactory.create()).build();
GetNewsService service = retrofit.create(GetNewsService.class);
try {
service.GetNewsItems().enqueue(this); //asynchronous
Response<List<RootObject>> response = service.GetNewsItems().execute(); //synchronous
}
catch (IOException e){
}
}
}
class to put the data:
public class RootObject implements Serializable {
public ArrayList<Result> results ;
public int nextId;
public ArrayList<Result> getResults() { return results; }
public int getNextId() { return nextId; }
public String toString() {
return String.format("JEEJ" + nextId);
}
}
Interface:
public interface GetNewsService {
#GET("/Articles")
Call<List<RootObject>> GetNewsItems();
}
First of all,
change your interface to this:
public interface GetNewsService {
#GET("/Articles")
void GetNewsItems(Callback<List<RootObject>> cb);
}
Also change your newsController class.
public class NewsController {
private RestAdapter restAdapter;
static final String API_URL = "[Enter your API base url here]";
public void getNews(){
OkHttpClient mOkHttpClient = new OkHttpClient();
mOkHttpClient.setConnectTimeout(15000,TimeUnit.MILLISECONDS);
mOkHttpClient.setReadTimeout(15000,TimeUnit.MILLISECONDS);
restAdapter = new RestAdapter.Builder().setEndpoint(API_URL).setClient(new OkClient(mOkHttpClient)).setLogLevel(RestAdapter.LogLevel.FULL) .build();
GetNewsService service = restAdapter.create(GetNewsService.class);
Callback<List<RootObject> cb = new Callback<List<RootObject>>() {
#Override
public void success(List<RootObject> rootObjectList, Response response) {
//whatever you want to do with the fetched news items
}
#Override
public void failure(RetrofitError error) {
//whatever you want to do with the error
}
};
service.GetNewsItems(cb);
}
}
You'll need to add the following dependencies in your build.gradle:
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.google.code.gson:gson:2.3.1'
compile 'com.squareup.okhttp:okhttp:2.4.0'
#megh vidani's answer works, but he had you switch your code from Retrofit 2 to Retrofit 1. Here is how to do it in Retrofit 2. You would need to go back to your original gradle settings, etc. --
public class NewsController {
public void getNews(){
Retrofit retrofit = new Retrofit.Builder().baseUrl("apilink").addConverterFactory(GsonConverterFactory.create()).build();
GetNewsService service = retrofit.create(GetNewsService.class);
service.GetNewsItems().enqueue(new Callback<List<RootObject>>() {
#Override
public void onResponse(Response<List<RootObject>> response) {
// Handle your response
// Note HTTP errors are delivered here, you can check
// response.isSuccess() or response.code() to determine
// HTTP failures
}
#Override
public void onFailure(Throwable t) {
// Network errors
}
});
}
}

Android Tests: Stubbing out Retrofit with Mockito

In my MainActivity I have a method called getAPI that returns an OTBServiceWrapper. This is used to setup retrofit for calling to an API.
In my MainActivityTest file I am trying to stub out the new OTBService().getService() call that the getApi method is making so I can return a MockedOTBService which changes the client to a custom one that return json.
As is, the current implementation will it the MockedOTBService if I had to place a logger within MockedOTBService but also falls through and calls the real api, which is not want I want in a test.
I am trying to stub the Retrofit API calls using Mockito and return json. I cant seem to understand why the stub is being called yet is not stubbing the method in question.
Notes:
I am using ActivityInstrumentationTestCase2
I am only running one test
If I add a verify(mockedOTBService, atLeastOnce()).getService(); is says it was never called.
If I change the when...thenReturn to use a mMainActivity = spy(getActivity()) there is not change and the real API is called.
Logcat Output
Logger﹕ MockedOTBService was called // Mock is called
Logger﹕ Real OTBService was called // Real API is called
Logger﹕ MainActivity getAPI method class is "$Proxy1" // Mock is shown in MainActivity
Logger﹕ RealAPIResponse JSON Parsed ID: 266 // Real API response returned
Real Flow
MainActivity.onCreate() > OTBService.getService() > OTBServiceWrapper.createSearch(...)
Trying to Achieve within Tests
MainActivity.onCreate() > MockedOTBService.getService() > OTBServiceWrapper.createSearch(...)
MainActivity.java
public class MainActivity extends Activity {
private OTBServiceWrapper serviceWrapper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getApi().createSearch(...)
}
public OTBServiceWrapper getApi() {
return new OTBService().getService();
}
}
OTBService.java
public class OTBService {
public OTBServiceWrapper getService() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(Constants.API_URL)
.build();
return restAdapter.create(OTBServiceWrapper.class);
}
}
OTBServiceWrapper.java
public interface OTBServiceWrapper {
#POST(Constants.API_SEARCHES_POST_URL)
void createSearch(#Body Request request, Callback<Request.Response> callback);
}
MainActivityTest.java
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
private OTBService mMockedOTBService;
private MainActivity mMainActivity;
private View mSearchButton;
public MainActivityTest() { super(MainActivity.class); }
#Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(true);
System.setProperty("dexmaker.dexcache", getInstrumentation().getTargetContext().getCacheDir().getPath());
mMockedOTBService = mock(OTBService.class);
when(mMockedOTBService.getService()).thenReturn(new MockedOTBService(getInstrumentation().getContext()).getService());
mMainActivity = getActivity();
mSearchButton = mMainActivity.findViewById(R.id.AbSearchButton);
mYourHolidayButton = mMainActivity.findViewById(R.id.AbYourHolidayButton);
}
public void testButtonActions() {
TouchUtils.clickView(this, mSearchButton);
...
}
}
MockedOTBService.java
public class MockedOTBService {
private Context context;
public MockedOTBService(Context context) { this.context = context; }
public OTBServiceWrapper getService() {
RestAdapter restAdapter;
restAdapter = new RestAdapter.Builder()
.setClient(new LocalJsonClient(context))
.setEndpoint(Constants.API_TEST_URL)
.build();
return restAdapter.create(OTBServiceWrapper.class);
}
}
LocalJsonClient.java
#SuppressLint("DefaultLocale")
public class LocalJsonClient implements Client { ... }
build.gradle
dependencies {
androidTestCompile 'com.google.dexmaker:dexmaker:1.0'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0'
}
Remove the need for mocking your request by allowing the Activity to set the service.
In your MainActivity create a class variable and a class setter for the service. It needs to be a at the class scope to prevent the OnCreate method being called before you have set the service to what you want it to be. Also create an instance getter which sets the service if you have not already.
In your test before you call getActivity() set the service to be your mock service. (Maybe think about moving this out to a support object).
MainActivity.java
public class MainActivity extends Activity {
private static OTBServiceWrapper serviceWrapper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getServiceWrapper.createSearch(...)
}
public OTBServiceWrapper getServiceWrapper() {
if (serviceWrapper == null) {
MainActivity.setServiceWrapper(new OTBService().getService());
}
return serviceWrapper;
}
public static void setServiceWrapper(OTBServiceWrapper serviceWrapper) {
MainActivity.serviceWrapper = serviceWrapper;
}
}
MainActivityTest.java
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
private MainActivity mMainActivity;
public MainActivityTest() { super(MainActivity.class); }
#Override
protected void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(true);
MainActivity.setServiceWrapper(
new MockedOTBService(getInstrumentation().getContext()).getService()
);
mMainActivity = getActivity();
}
}

Categories