i'm migrating from okhttp 3.14 to okhttp4, accordings to migration guide, when replacing "response.body()?" call to "response.body?" IDE shows error " Cannot access 'body': it is package-private in 'Response' " at last line of code
val request = Request.Builder().url(url).build()
val response = coreNetwork.getOkHttp().newCall(request).execute()
val stream = response.body?.source()?.inputStream()
if i'm trying "response.body()?" call, shows error " Using 'body(): ResponseBody?' is an error. moved to val " as expected.
Solved, i'm start watching to what version of okhttp linked every import, and one interface linked to okhttp-3.12.0.jar. This interface belongs to separate gradle module, and i found that i forgot add a dependency ' implementation "com.squareup.okhttp3:okhttp:4.2.2" ' to .gradle file of that module. (in that case class should not found okhttp dependency at all, but somehow found old version and depends on it)
This is an expected error message looking at the code for Response.kt in the 4.2.x version of the branch:
#JvmName("-deprecated_body")
#Deprecated(
message = "moved to val",
replaceWith = ReplaceWith(expression = "body"),
level = DeprecationLevel.ERROR)
fun body(): ResponseBody? = body
so the solution would be to call response.body? which it looks like you are already doing...
see: https://github.com/square/okhttp/blob/okhttp_4.2.x/okhttp/src/main/java/okhttp3/Response.kt#L202 for details
Related
I am using AWS SDK for Kotlin in my Android project and my app always crashes with error
aws.sdk.kotlin.runtime.auth.credentials.CredentialsProviderException: No credentials could be loaded from the chain: CredentialsProviderChain -> EnvironmentCredentialsProvider -> ProfileCredentialsProvider -> StsWebIdentityProvider -> EcsCredentialsProvider -> ImdsCredentialsProvider
I am using AWS secret manager and implementing the SDK in gradle as -
implementation 'aws.sdk.kotlin:secretsmanager:0.17.5-beta'
My Kotlin code looks like -
SecretsManagerClient { region = "ap-south-1" }.use { secretsClient ->
CoroutineScope(Dispatchers.IO).launch {
val secretValueRequest = GetSecretValueRequest {
secretId = "prod"
}
val response = secretsClient.getSecretValue(secretValueRequest)
val secret = response.secretString
print("Secret: $secret")
}
}
I tried to setup the credential in my Mac computer as mentioned in this article, for both environment variable and also having a file named credentials .
Can anyone please help me to fix the issue
Your problem here is the Android app will not read creds from the file system of your machine. To get around this, you can use the StaticCredentialsProvider shown in this example that is referenced from the Kotlin DEV Guide.
https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/cross_SnsPublishSubscription_kotlin_topic.html
Github URL
https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/kotlin/usecases/subpub_app_android
Once you follow this -- you can successfully make AWS Service calls from the Android app.
UPDATE
After talking with the Kotlin team, you can setup your creds as environment variables then use this provider - which is mentioned in the docs here:
https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/credential-providers.html
Code that works....
SnsClient { credentialsProvider = EnvironmentCredentialsProvider(); region = "us-east-1" }.use { snsClient ->
val result = snsClient.subscribe(request)
showToast(result.subscriptionArn.toString())
}
This Kotlin Android example will be updated and published soon as well.
Basically, I can't find an implementation of com.google.api.client.http.HttpTransport that works in Android SDK 31.
I'm trying to get started with the google-signin API, and I'm getting a ClassCastException.
I'm using code taken nearly verbatim from the google api examples.
val credentialStream = resources.openRawResource(R.raw.credentials)
?: throw FileNotFoundException("Resource not found: $CREDENTIALS_FILE_PATH")
val clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, InputStreamReader(credentialStream))
// Build flow and trigger user authorization request.
val flow = GoogleAuthorizationCodeFlow.Builder(NetHttpTransport(), JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(FileDataStoreFactory(requireContext().filesDir?.resolve(File(TOKENS_DIRECTORY_PATH))))
.setAccessType("offline")
.build()
val receiver = LocalServerReceiver.Builder().setPort(8888).build()
//returns an authorized Credential object.
return AuthorizationCodeInstalledApp(flow, receiver).authorize("user#gmail.com")
Every test results in an exception at the last line.
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/sun/net/httpserver/HttpServer;
...
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.sun.net.httpserver.HttpServer" on path: DexPathList[[dex file "/data/d ...
Any ideas? I'm pretty novice to android development.
One solution I found was to add rt.jar from the desktop JVM as a dependency, because it includes that missing class. Check here:
Is it possible to use com.sun.net.httpserver package in android program?
The solution I ended up using was to using Google Play Services instead of GoogleAuthorizationCodeFlow.
In gradle:
implementation 'com.google.android.gms:play-services-auth:20.1.0'
implementation ('com.google.api-client:google-api-client-android:1.34.0')
In my ViewModel:
val applicationName = "My Application"
val scopes = listOf( ... some scopes go here ...)
val credential = GoogleAccountCredential.usingOAuth2(application, scopes)
.setBackOff(ExponentialBackOff())
.setSelectedAccountName(accountName)
credential can then be used to access other parts of the Google API.
I am writing a unit test and I want to throw an HttpException with an error code 409.
This is what I tried but it gives me an error
Using 'parse(String): MediaType?' is an error. moved to extension function
This is a kotlin file and Retrofit 2.6.0, and ResponseBody is okhttp3 - 3.12.12
What I have tried
every(call.execute()).thenThrow(HttpException(
Response.error<Any>(409, ResponseBody.create(
MediaType.parse("plain/text"), ""
))
))
how can i solve this please
thanks
R
For Kotlin:
currently ResponseBody.create methods are deprecated (at least in OkHttp3 ver. 4.9.1). Following extension method can be used:
"raw response body as string".toResponseBody("plain/text".toMediaTypeOrNull())
i just throw this:
throw HttpException(Response.error<ResponseBody>(500 ,ResponseBody.create(MediaType.parse("plain/text"),"some content")))
I've encountered this before. At some point, some dependencies of OkHttp3 changed, and the resulting error message isn't super helpful. What I believe you are looking for is the new .toMediaType() Kotlin extension function. So instead of:
ResponseBody.create(MediaType.parse("plain/text"), "")
Please try:
ResponseBody.create("plain/text".toMediaType(), "")
You'll likely need to import this extension. If your IDE doesn't automatically suggest it, please try importing via import okhttp3.MediaType.Companion.toMediaType.
I am using Dialogflow Java Client library in my android app, to run the detect intent API as given in below link.
https://github.com/dialogflow/dialogflow-java-client-v2/blob/master/samples/src/main/java/com/example/dialogflow/DetectIntentTexts.java
I modified the code given in above link slightly to authenticate the client first before sending the detect intent request. My sample code is as follows:
SessionsSettings sessionsSettings = SessionsSettings.newBuilder().setCredentialsProvider(credentialsProvider).build();
SessionsClient sessionsClient = SessionsClient.create(sessionsSettings);
SessionName session = SessionName.of(PROJECT_ID, sessionId);
System.out.println("Session Path: " + session.toString());
TextInput.Builder textInput = TextInput.newBuilder().setText(text).setLanguageCode(langCode);
QueryInput queryInput=QueryInput.newBuilder().setText(textInput).build();
DetectIntentResponse response = sessionsClient.detectIntent(session, queryInput);
where
CredentialsProvider credentialsProvider = new CredentialsProvider() {
#Override
public Credentials getCredentials() throws IOException {
InputStream fileStream = appContext.getApplicationContext().getAssets().open("MyDialogflowProject-4cxxxxx.json");
return ServiceAccountCredentials.fromStream(fileStream);
}
};
But I get the following error
com.google.api.gax.rpc.UnauthenticatedException:
io.grpc.StatusRuntimeException: UNAUTHENTICATED: Credentials require
channel with PRIVACY_AND_INTEGRITY security level. Observed security
level: NONE
at com.google.api.gax.rpc.ApiExceptionFactory.createException(ApiExceptionFactory.java:73)
Can anyone please tell how to set the Security Level for SessionSettings in this case ?
Try to update library versions you are using. On transport layer Security Level should be setup.
For example gradle dependencies from my hello world project which is working with dialogflow v2:
dependencies {
compile ("com.google.api.grpc:proto-google-common-protos:1.12.0")
compile ("io.grpc:grpc-netty:1.14.0")
compile ("io.grpc:grpc-protobuf:1.14.0")
compile ("io.grpc:grpc-stub:1.14.0")
compile ("com.google.auth:google-auth-library-oauth2-http:0.10.0")
compile ("com.google.cloud:google-cloud-storage:1.38.0")
compile ("io.netty:netty-tcnative-boringssl-static:2.0.12.Final")
compile ("com.google.cloud:google-cloud-dialogflow:0.55.1-alpha")
}
In my case, I have found out that I have set the IntelliJ environment variable to FIRESTORE_EMULATOR_HOST=localhost:8080 to use the Firebase emulators in the past.
Later I tried to push data to Cloud Firestore without removing that variable, but the attempts were unsuccessful with the error PRIVACY_AND_INTEGRITY.
After some time, I found the localhost setting and removed it. Once removed, I was able to push the data to the cloud without any issues.
I have an android app with Realm and some Realm Module that help me to isolate synced Realm and i decide to migrate from Java to Kotlin.
#RealmModule(classes = arrayOf(Category::class, Product::class))
private class ShopModule
fun getShop(user: SyncUser, path: String): RealmConfiguration {
return SyncConfiguration.Builder(user, path)
.modules(ShopModule())
.build()
}
function getShop return RealmConfiguration to use in Realm.getInstance().
After some converting show me some error when build() has occurred:
io.realm.exceptions.RealmException: Could not find io.realm.ShopModuleMediator
please help me to continue my migration. I can't understand what's wrong because this method works for me in java.
UPDATE:
After good Q&A in comments and so many change and try in my project i found when using kotlin in my project ShopModuleMediator was not generated and when convert app project from Java to Kotlin project has worked befor clean Project.
🎉🎉 Congratulation with release Realm Java 4.1.0 this problem has been resolved and i share my test project you can see result but an important note that for using in instant app you must use https network and can't use http in instant app and i share another app that work when run in app mode but when run in instantapp has occurred an error : not permitted by network security policy this is because using http in authentication url.