I am trying to write a backend service in Android, which reads a remote database and executes a query on it, returning the result in a ResultSet object. This is the code for my Java Bean which I return from the API call (called SQLResult):
package com.gradai.rushhour.backend;
import java.sql.ResultSet;
public class SQLResult
{
ResultSet result;
public SQLResult()
{
}
public ResultSet getResult()
{
return result;
}
public void setResult(ResultSet rs)
{
result = rs;
}
}
Now I try to use this API (called sqlBackend) in an AsyncTask in the actual app. In the onPostExecute function, I am getting an error:
error: incompatible types: com.gradai.rushhour.backend.sqlBackend.model.ResultSet cannot be converted to java.sql.ResultSet
This is the code for the said function:
protected void onPostExecute(SQLResult result)
{
ResultSet rs = result.getResult();
Toast toast = Toast.makeText(context, rs.toString(), Toast.LENGTH_LONG);
toast.show();
}
I don't get why is a ResultSet class being created in the backend model. Please help me in understanding what is going on. I'll be glad to provide further code if needed for debugging.
EDIT: These are the import statements used in the AsyncTask program:
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.json.gson.GsonFactory;
import com.gradai.rushhour.backend.sqlBackend.SqlBackend;
import com.gradai.rushhour.backend.sqlBackend.model.SQLResult;
import java.io.IOException;
import java.sql.ResultSet;
Also, please note that: I tried to convert the ResultSet in the API function to an ArrayList, and changed the SQLResult class to contain the same. Now, when I try to access the ArrayList in the same function, I get the error that a List is expected instead of an ArrayList. Could that be helpful?
Related
With AndroidX the InstrumentationRegistry is now deprecated. The documentation states
This method is deprecated. In most scenarios, getApplicationContext() should be used instead of the instrumentation test context. If you do need access to the test context for to access its resources, it is recommended to use getResourcesForApplication(String) instead.
However, I cannot find any examples of how to obtain the instance of PackageManager in test to invoke getResourcesForApplication and which package name should be provided to its string parameter.
For instance, here is the code that currently works:
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
import java.io.InputStream;
import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import static org.junit.Assert.*;
#RunWith(AndroidJUnit4.class)
public class MyTest {
#Test
public void processImage() {
// load image from test assets
AssetManager am = InstrumentationRegistry.getContext().getAssets();
InputStream is = null;
Bitmap image = null;
try {
is = am.open("image.jpg");
image = BitmapFactory.decodeStream(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
if ( is != null ) {
try {
is.close();
} catch (IOException ignored) { }
}
}
assertNotNull(image);
// do something with the image
}
}
Now, how to rewrite this test without using the deprecated InstrumentationRegistry.getContext()? Keep in mind that image.jpg is not part of the application's assets - it's located in src/androidTest/assets folder and gets packaged into AppName-buildType-androidTest.apk (it's not present in the AppName-buildType.apk, for which I know the package name).
How to deduce the package name of the test APK? Is it possible to avoid hardcoding package name strings in my unit test? I am looking for a solution that is as elegant as the original code, but does not use deprecated methods.
I think you should simply use InstrumentationRegistry.getInstrumentation().getContext().getAssets() instead of InstrumentationRegistry.getContext().getAssets().
It will use your test context, so you should get your assets.
I'm trying to authenticate with a REST API via a token using AndroidAnnotations #Rest RestClient Interface.
But due to a lack of documentation I can't get it running using setBearerAuth(String token);
I already have the interface and the class HeadersRequestInterceptor implements ClientHttpRequestInterceptor, but I don't know where to call setBearerAuth(myCustomToken);
If someone could give me a hint I would be very graceful.
Cheers
MyRestClient.java:
#RequiresAuthentication
#Rest(rootUrl = "your_url", converters = {...})
public interface MyRestClient extends RestClientHeaders {
#Post("/somecall")
public void someApiCall();
}
MyActivity.java:
#EActivity
public class MyActivity extends Activity {
#RestService
MyRestClient client;
#Background
void callSomeApi() {
String accessToken = ... ; // was previously returned from server
client.setBearerAuth(accessToken);
client.someApiCall(); // it will add header: Authorization: Bearer accessToken
}
}
I found out a better way, let-me explain:
If you need to apply that in all your Android REST calling, so we need to create a Interceptor to get all REST request made by the application like this:
import android.content.Context;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.androidannotations.rest.spring.annotations.Rest;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.IOException;
/**
* Created by Rafael Rocha on 21/05/2018.
*/
#EBean
public class HttpBasicAuthenticatorInterceptor implements ClientHttpRequestInterceptor {
#RootContext
Context context;
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().add("Authorization",AUTHENTICATION_SCHEME + "your_token_goes_here");
return execution.execute(request, body);
}
}
Replace AUTHENTICATION_SCHEME by your authentication method, in my case was "Bearer" and don't forget to put a blank space between them "Bearer YOUR_TOKEN".
After that is just put a reference in your REST service class on #Rest annotation filling the property "interceptors"
import org.androidannotations.rest.spring.annotations.Accept;
import org.androidannotations.rest.spring.annotations.Get;
import org.androidannotations.rest.spring.annotations.Header;
import org.androidannotations.rest.spring.annotations.Path;
import org.androidannotations.rest.spring.annotations.Rest;
import org.androidannotations.rest.spring.api.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import java.util.List;
/**
* Created by Rafael Rocha on 13/03/2018.
*/
#Rest(rootUrl = RestUtil.ROOT_URL, converters = {MappingJackson2HttpMessageConverter.class}, interceptors = {HttpBasicAuthenticatorInterceptor.class})
#Accept(MediaType.APPLICATION_JSON)
public interface NotificationRest {
//#Header(name = "server_version", value = SERVER_VERSION)
#Get("notificacao/profissional/recentes/{idProfessional}")
List<ResponseNotification> getNotifications(#Path Long idProfessional);
}
The only thing I did was put a Header value in the request header. You can do it to pass other things for example here in my application a need to pass my application android version to server side treats the old application or simply block the access, so I just need to increase on more line in the code
request.getHeaders().add(RestUtil.SERVER_VERSION_HEADER,RestUtil.SERVER_VERSION);
I using Spring Android Rest Template to perform HTTP request. I was testing like so :
package com.mnubo.platform.android.sdk.internal.user.services.impl;
import com.mnubo.platform.android.sdk.models.users.User;
import org.junit.Before;
import org.junit.Test;
import org.springframework.test.web.client.MockRestServiceServer;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
#RunWith(RobolectricTestRunner.class)
#Config(emulateSdk = 18)
public class DummyTest {
private MyApiImpl myApi;
private MockRestServiceServer myapiMockServer;
#Before
public void setUp() throws Exception {
myApi = new MyApiImpl("ACCESS_TOKEN");//break here
myapiMockServer = MockRestServiceServer.createServer(myApi.getRestTemplate());
}
#Test
public void testRestClient() throws Exception {
final User expectedUser = new User();
expectedUser.setUsername("test");
expectedUser.setLastname("lastname");
myapiMockServer.expect(requestTo("http://my-service.com/user/test"))
.andExpect(method(GET))
.andRespond(withSuccess(this.convertToJsonString(expectedUser), APPLICATION_JSON_UTF8));
User user = myApi.userOperations().getUser("test");
userMockServer.verify();
}
}
All of this was working correctly using the RoboelectricTestRunner. But, yesterday Android Studio updated and asked me to update the build tool version to 1.1.0. (com.android.tools.build:gradle:1.1.0).
This version now include supports for Unit testing. See https://sites.google.com/a/android.com/tools/tech-docs/unit-testing-support
The problem : I can't create MyApiImpl anymore because it creates a RestTemplate. This RestTemplate use org.springframework.http.client.HttpComponentsClientHttpRequestFactory and in this class constructor, methods from the org.apache.http package are used.
These methods raised an exception : Eg: Method getSocketFactory in org.apache.http.conn.scheme.PlainSocketFactory
Well, I mocked successfully the getSocketFactory using PowerMock but then I had to mock the register method of SchemeRegistry that is only locally accessible from the constructor (source).
So I gave up trying to mock all of the shenanigans happening inside the RestTemplate and decided to directly mock the RestTemplate.
I need help to mock it correctly so that the MockRestServiceServer can still be used in my test, because right now, the myapiMockServer.verify() assertion fails.
Update
I'm still unable to use the MockRestServiceServer to test my Api, but I managed to test each individual OperationImpl using a mock of the RestTemplate like so :
public class DummyOperationTest {
private DummyOperation dummyOperation;
private RestTemplate mockedRestTemplate = mock(RestTemplate.class);
#Before
public void setUp() throws Exception {
super.setUp();
dummyOperation = new DummyOperationImpl(PLATFORM_BASE_URL, mockedRestTemplate);
}
#Test
public void test() throws Exception {
String calledUrl = PLATFORM_BASE_URL + "/objects?update_if_exists=true";
when(mockedRestTemplate.postForObject(calledUrl, expectedSmartObject, SmartObject.class)).thenReturn(expectedSmartObject);
smartObjectService.create(expectedSmartObject, true);
verify(mockedRestTemplate, atMost(1)).postForObject(calledUrl, expectedSmartObject, SmartObject.class);
}
}
Unfortunately, this still doesn't test the whole request execution. I can't validate that oAuth authentication is correctly added to the headers, or if the conversion of the server response is correct.
Well, it was a matter of mocking. I didn't understood everything correctly but I finally worked it out. Here is an a example that shows how to proceed :
package com.mnubo.platform.android.sdk.internal;
import android.util.Log;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.test.web.client.MockRestServiceServer;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.mockito.PowerMockito.whenNew;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
#RunWith(PowerMockRunner.class)
#PrepareForTest({
Log.class,
PlainSocketFactory.class,
SSLSocketFactory.class,
HttpComponentsClientHttpRequestFactory.class,
ConnManagerParams.class,
AbstractHttpClient.class
})
public class DummyTest {
private final String USER_ACCESS_TOKEN = "user_token";
private final PlainSocketFactory mockedPlainSocketFactory = mock(PlainSocketFactory.class);
private final SSLSocketFactory mockedSSLSocketFactory = mock(SSLSocketFactory.class);
private final SchemeRegistry mockedSchemeRegistry = mock(SchemeRegistry.class);
private final DefaultHttpClient mockedHttpClient = mock(DefaultHttpClient.class);
private final HttpParams mockedHttpParams = mock(HttpParams.class);
private DummyApiImpl dummyApi = new DummyApiImpl(USER_ACCESS_TOKEN);
protected MockRestServiceServer mockServer;
#Before
public void setUp() throws Exception {
mockStatic(Log.class);
mockStatic(PlainSocketFactory.class);
mockStatic(SchemeRegistry.class);
mockStatic(SSLSocketFactory.class);
mockStatic(ConnManagerParams.class);
whenNew(SchemeRegistry.class).withAnyArguments().thenReturn(mockedSchemeRegistry);
whenNew(DefaultHttpClient.class).withAnyArguments().thenReturn(mockedHttpClient);
when(PlainSocketFactory.getSocketFactory()).thenReturn(mockedPlainSocketFactory);
when(SSLSocketFactory.getSocketFactory()).thenReturn(mockedSSLSocketFactory);
when(mockedHttpClient.getParams()).thenReturn(mockedHttpParams);
mockServer = MockRestServiceServer.createServer(dummyApi.getRestTemplate());
}
#Test
public void doOperationTest() throws Exception {
final User testUser = new User();
mockUserServiceServer.expect(requestTo(expectedUrl("/users/test")))
.andExpect(method(POST))
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andRespond(withSuccess());
dummyApi.userOperations().createUser("test", testUser);
mockUserServiceServer.verify();
}
}
The problem occurred when the constructor of the Api was called. This classe extends AbstractOAuth2ApiBinding which constructor create a RestTemplate. This is this object that requires multiple level of mocking.
Once you have mocked the required element to create the RestTemplate, the rest is very easy, thanks to the mock server!
I'm trying to define a subclass of SQLiteCursor, in order to redefine some of its functions (I'm using fillWindow as an example). However, I'm getting a few problems with the database functions.
The code in the method below was copied from the source fo SQLiteCursor (I just removed some junk for the sake of this question).
package com.malabarba.util;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteCursor;
import android.database.sqlite.SQLiteCursorDriver;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteQuery;
import android.util.Log;
public class HugeCursor extends SQLiteCursor {
private SQLiteQuery mQuery;
public HugeCursor(SQLiteDatabase db, SQLiteCursorDriver driver, String editTable, SQLiteQuery query, int c) {
super(db, driver, editTable, query);
mQuery = query;
}
private void fillWindow(int requiredPos) {
int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos, 0);
mQuery.fillWindow(mWindow, startPos, requiredPos, false);
mCursorWindowCapacity = mWindow.getNumRows();
}
}
All the problems seem related to methods not being found:
The method cursorPickFillWindowStartPosition(int, int) is undefined for the type DatabaseUtils.
The method fillWindow(CursorWindow, int, int, boolean) is undefined for the type SQLiteQuery.
Both the functions in items 1 and 2 are defined and not private, so why can't I use them?
I think you are looking at some old-ish code. fillWindow() is now protected. Not sure what's going on with the DatabaseUtils one though.
I am trying to get a list of Files in a Folder from Google Drive from my Android app but have been unsuccessful so far. I'm using google-api-drive-v1-rev4-java-1.6.0-beta and google-api-client-1.9.0. I'm also building my code similar to calendar-android-sample and tasks-android-sample from the samples at http://code.google.com/p/google-api-java-client/wiki/Android.
I cant seem to find how to use files() to get a list of folders or even the id of the folder I want. The tasks-android-sample uses '#default' in the get() method to get a list of tasks. What would I use in the get method to get a list of folders first, search for my folder, get the id, then get a list of files in that folder?
AsyncLoadDocs.java: (Note: I'm using getFields() just to see if the Get object contains any metadata, which at this point doesn't.)
package com.mysite.myapp.docs;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.Drive.Files;
import com.google.api.services.drive.Drive.Files.Get;
import com.google.api.services.drive.model.File;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ArrayAdapter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Asynchronously load the docs with a progress dialog.
*
* #author ms
*/
class AsyncLoadDocs extends AsyncTask<Void, Void, List<String>> {
private static final String TAG = "AsyncLoadDocs";
private final GDocsSync gDocsSync;
private final ProgressDialog dialog;
private final Drive entry = null;
private com.google.api.services.drive.Drive service;
AsyncLoadDocs(GDocsSync gDocsSync) {
this.gDocsSync = gDocsSync;
service = gDocsSync.driveClient;
dialog = new ProgressDialog(gDocsSync);
}
#Override
protected void onPreExecute() {
dialog.setMessage("Loading docs...");
dialog.show();
}
#Override
protected List<String> doInBackground(Void... arg0) {
try {
List<String> folderNames = new ArrayList<String>();
Get get = service.files().get("#default").setProjection("FULL");
String fields = get.getFields();
Log.d(TAG, "Fields: " + fields);
return folderNames;
} catch (IOException e) {
gDocsSync.handleGoogleException(e);
return Collections.singletonList(e.getMessage());
} finally {
gDocsSync.onRequestCompleted();
}
}
#Override
protected void onPostExecute(List<String> result) {
dialog.dismiss();
}
}
Any help would be appreciated. Both Calendar and Tasks samples successfully retrieve data from Google using my API key, why doesn't this Drive code?
The Drive API grants access only to two classes of files:
Files that a user has created with a given Drive app
Files that a user opens with a given Drive app
For security reasons, there's no method to list all files in a user Drive account:
https://developers.google.com/drive/apps_overview#granting_file-level_access
For more options in the Android environment, check out these other answers:
Android API for Google Drive?
Google Drive\Docs API for Android