How to change base URL using retrofit2 and koin 2.0 - java

I have a query that returns a list of servers, and the user can select the server he needs.
Googling did not help, almost no results.
Tell me how to implement basic URL spoofing in real time using Koin and Retrofit?
My Modules:
fun createMainModule(context: Context) = module {
single(named(APP_CONTEXT)) { context }
single(named(RESOURCES)) { context.resources }
single(named(REPOSITORY)) {
Repository(get(named(RETROFIT)))
}
}
fun createNetworkModule(baseUrl: String) = module(override = true) {
single(named(TOKEN_INTERCEPTOR)) { createTokenInterceptor(get(named(DATA_PROVIDER))) }
single(named(OK_HTTP)) { createOkHttpClient(get(named(TOKEN_INTERCEPTOR))) }
single(named(GSON)) { createGson() }
single(named(RETROFIT)) {
createRetrofit(
get(named(RESOURCES)),
get(named(LOG_OUT_SUBJECT)),
get(named(GSON)),
baseUrl,
get(named(OK_HTTP))
)
}

I resolve my problem with comment #sonnet
This code:
class ChangeableBaseUrlInterceptor : Interceptor {
#Volatile
private var host: HttpUrl? = null
fun setHost(host: String) {
this.host = host.toHttpUrlOrNull()
}
fun clear() {
host = null
}
#Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
var request = chain.request()
host?.let {
val newUrl = request.url.newBuilder()
.scheme(it.scheme)
.host(it.toUrl().toURI().host)
.port(it.port)
.build()
request = request.newBuilder().url(newUrl).build()
}
return chain.proceed(request)
}
}

Related

Grails RestBuilder dont findendPoint with Object in signature

I have a code with a RestBuilder that needs to connect to another application, the target endPoint have an object in the signature with the attributes. The problem is the request return 404. How I solve this? I tried use x-www-form-urlencoded (doesn't work)
Request Method:
RestResponse restResponse;
String parameters = '{"qtdThreads":3,"channel":"http://localhost:8081/application2"}'
try {
restResponse = new RestBuilder().post("http://localhost:8080/application/endPoint", {
accept("application/json")
contentType "application/json; utf-8"
body(parameters.getBytes("UTF-8"))
connectTimeout: 1000
})
} catch (Exception e) {
e.printStackTrace();
} finally {
return restResponse;
}
Target endPoint:
Object endPoint(ObjectCommand command) {
render(status: HttpStatus.OK)
}
Object used on signature
import grails.validation.Validateable
#Validateable
class ObjectCommand {
URL channel
Integer qtdThreads
static constraints = {
qtdThreads(validator: { Integer val ->
if (!val || val <= 0) {
return "message1"
}
})
channel(validator: { URL val ->
if (!val) {
return "message2"
}
})
}
}
did you check if the target application is running and exposing that endpoint?

Micronaut get handling object/method in Filter

So i have following controller
Controller("/test")
public class MyController {
#Get("/anno")
#MyAnnotation(value="my annotation value") // <---- i want this value
public Object testAnnotation(HttpRequest<?> request){
return "Hello world";
}
}
I'm trying to implement custom filter on micronauts http server.
#Filter("/**")
public class MyFilter implements HttpServerFilter {
#Override
public Publisher<? extends HttpResponse<?>> doFilter(HttpRequest<?> request, FilterChain chain) {
// HERE
// how to get the MyAnnotation value from the handling method for the request ?
return chain.proceed(request);
}
}
How to get my custom annotation inside the filter ?
Thank you.
You would need AOP, Micronauts supports it. But you get it from a MethodInterceptor, not HttpFilter. Here is the code I modified based on what I wrote for tracing, in Kotlin, it would be very similar in Java:
#Singleton
#InterceptorBean(MyAnnotation::class)
class MyAnnotationInterceptor : MethodInterceptor<Any, Any> {
override fun intercept(context: MethodInvocationContext<Any, Any>): Any? {
val myAnnotation: AnnotationValue<MyAnnotation> = context.getAnnotation(MyAnnotation::class.java)!!
val value = myAnnotation.get("value", String::class.java).orElse(null)
val className = context.declaringType.simpleName
val methodName = context.methodName
val operationName = "$className.$methodName"
val interceptedMethod = InterceptedMethod.of(context)
try {
when (interceptedMethod.resultType()) {
SYNCHRONOUS -> {
try {
return context.proceed()
} catch (e: Exception) {
throw e
} finally {
}
}
COMPLETION_STAGE -> {
try {
var completionStage = interceptedMethod.interceptResultAsCompletionStage()
return interceptedMethod.handleResult(completionStage)
} catch (e: Exception) {
logError(newSpan, e)
throw e
}
}
else -> return interceptedMethod.unsupported()
}
} catch (e: Exception) {
return interceptedMethod.handleException<RuntimeException>(e)
}
}
}
val value = myAnnotation.get("value", String::class.java).orElse(null) is where you get the value.
We use the above code to extract the tracing sampling rate and it works well for us. Note that your annotation will need "around" AOP annotation:
#Retention(RUNTIME)
#Target(CLASS, FILE, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
#Around
annotation class MyAnnotation(
val value: String = "",
)

How to download image using Retrofit or Picasso via HTTP POST method

I have a HTTP post request, it takes a JSON with the following content as request body:
{
"UserName":"ApiService",
"Password":"BandarAndroid",
"AndroidId":"15df3b3a90XXXXX",
"ContentId":"704",
"frame":"1"
}
After requesting to the server, I get only one image in response(Instead of anything (like JSON)).
The appropriate image is created on request and has no web address.
my service Address is :
http://xyz.website.com/api/DownloadFileForAndroid
and my response header is :
cache-control →no-cache
content-length →29837
content-type →image/png
date →Mon, 09 Sep 2019 08:42:23 GMT
expires →-1
pragma →no-cache
server →Microsoft-IIS/8.5
x-aspnet-version →4.0.30319
x-powered-by →ASP.NET
I don't know whether to use retrofit or Picasso to get this photo,
in Picasso: I can't send the amount of JSON in the request body.
in retrofit: I can't get the photo without the url (Address to point to the photo like www.site.com/a.jpg)
As you requested, I am converting my previous solution (Kotlin) to
Java
Example 1: Picasso
public void loadImageWithPicasso(ImageView imageView) {
Picasso.Builder builder = new Picasso.Builder(imageView.getContext());
RequestCreator picassoImageLoader = createPicassoLoader(
builder,
ImageRequest.DEFAULT_JSON_BODY,
"http://shop.atiafkar.ir/api/DownloadFileForAndroid"
);
picassoImageLoader.into(imageView);
}
public RequestCreator createPicassoLoader(Picasso.Builder builder, String body, String url) {
return builder.downloader(new OkHttp3Downloader(createPicassoCallFactory(body)))
.build()
.load(url);
}
private okhttp3.Call.Factory createPicassoCallFactory(String jsonBody) {
final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.build();
final RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), jsonBody);
return new okhttp3.Call.Factory() {
#Override
public okhttp3.Call newCall(Request request) {
Request.Builder builder = request.newBuilder();
builder.post(requestBody);
builder.addHeader("Content-Type", "application/json");
return okHttpClient.newCall(builder.build());
}
};
}
Example 2: Retrofit
public void loadImageWithRetrofit(ImageView imageView) {
final RetrofitImageLoader imageLoader = new RetrofitImageLoader(imageView);
RemoteApi api = RemoteApi.Factory.create();
api.getImage(ImageRequest.DEFAULT_BODY).enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
ResponseBody body = response.body();
if (response.isSuccessful() && body != null) {
imageLoader.execute(body.byteStream());
} else {
Log.d(TAG, "Retrofit onResponse(): CODE = [" + response.code() + "], MESSAGE = [" + response.message() + "]");
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d(TAG, "Retrofit onFailure(): t = [" + t + "]");
}
});
}
RetrofitImageLoader class
public class RetrofitImageLoader extends AsyncTask<InputStream, Integer, Bitmap> {
private ImageView imageView;
private RetrofitImageLoader(ImageView imageView) {
this.imageView = imageView;
}
#Override
protected Bitmap doInBackground(InputStream... inputStreams) {
return BitmapFactory.decodeStream(inputStreams[0]);
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
imageView.setImageBitmap(bitmap);
}
}
RemoteApi interface
public interface RemoteApi {
#Streaming // Important
#POST("/api/DownloadFileForAndroid")
Call<ResponseBody> getImage(#Body ImageRequest body);
class Factory {
private static RemoteApi mInstance;
public static RemoteApi create() {
if (mInstance == null) {
mInstance = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://shop.atiafkar.ir")
.build()
.create(RemoteApi.class);
}
return mInstance;
}
}
}
ImageRequest model class
public class ImageRequest{
public static final ImageRequest DEFAULT_BODY;
public static final String DEFAULT_JSON_BODY;
static {
DEFAULT_BODY = new ImageRequest();
DEFAULT_BODY.setAndroidId("15df3b3a90dc5688");
DEFAULT_BODY.setContentId("704");
DEFAULT_BODY.setFrame("1");
DEFAULT_BODY.setPassword("BandarAndroid");
DEFAULT_BODY.setUserName("ApiService");
DEFAULT_JSON_BODY = new Gson().toJson(DEFAULT_BODY, ImageRequest.class);
}
#SerializedName("UserName")
private String userName;
#SerializedName("ContentId")
private String contentId;
#SerializedName("AndroidId")
private String androidId;
#SerializedName("Password")
private String password;
#SerializedName("frame")
private String frame;
public void setUserName(String userName){
this.userName = userName;
}
public void setContentId(String contentId){
this.contentId = contentId;
}
public void setAndroidId(String androidId){
this.androidId = androidId;
}
public void setPassword(String password){
this.password = password;
}
public void setFrame(String frame){
this.frame = frame;
}
}
I don't know whether to use retrofit or Picasso to get this photo
It is better to use Picasso otherwise you have to write a lot of codes to load images efficiently if you download them using Retrofit.
You would be happy to know that you can use both Retrofit and Picasso depending on your choice to load images from that API.
Before going ahead with example, I want to clear one thing up that you had a misconception that you needed to send the above-mentioned JSON data as header but after playing around with the API I figured out that it takes the JSON as request body.
Examples
RemoteApi.kt
interface RemoteApi {
// Retrofit
#Streaming // Important
#POST("/api/DownloadFileForAndroid")
#Throws(Exception::class)
suspend fun getImage(#Body body: ImageRequest): ResponseBody?
companion object {
// Retrofit
fun create(): RemoteApi {
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://shop.atiafkar.ir")
.build()
return retrofit.create(RemoteApi::class.java)
}
// Picasso
fun getPicassoImageRequest(
builder : Picasso.Builder,
body: String,
url: String = "http://shop.atiafkar.ir/api/DownloadFileForAndroid"
) = builder.downloader(OkHttp3Downloader(getPicassoCallFactory(body)))
.build()
.load(url)
// Picasso
private fun getPicassoCallFactory(jsonBody : String): Call.Factory {
return Call.Factory { request ->
OkHttpClient().run {
RequestBody.create(MediaType.parse("application/json"), jsonBody).let {
newCall(request.newBuilder()
.post(it)
.addHeader("Content-Type", "application/json")
.build()
)
}
}
}
}
}
}
ImageRepository.kt
class ImageRepository(private val api: RemoteApi = RemoteApi.create()) {
companion object {
fun get() = ImageRepository()
}
// Retrofit
suspend fun downloadImage(body : ImageRequest = ImageRequest.default): Bitmap? {
return api.getImage(body)?.run {
withContext(Dispatchers.IO) {
bytes().let {
// to load bitmap efficiently follow the guideline provided by -
// https://developer.android.com/topic/performance/graphics/load-bitmap
// otherwise you may experience OutOfMemoryException
BitmapFactory.decodeByteArray(it, 0, it.size)
}
}
}
}
// Picasso
fun getPicassoImageLoader(
builder : Picasso.Builder,
body: ImageRequest = ImageRequest.default
) = RemoteApi.getPicassoImageRequest(builder, body.toJson())
}
ImageViewModel.kt
class ImageViewModel(private val repository: ImageRepository) : ViewModel() {
private val _progress = MutableLiveData<Boolean>()
val progress = _progress
// Retrofit
val liveImage = liveData {
_progress.value = true
emit(repository.downloadImage())
_progress.value = false
}
// Picasso
fun getPicassoImageLoader(builder: Picasso.Builder) = repository.getPicassoImageLoader(builder)
}
Finally,
ImageActivity.kt
class ImageActivity : AppCompatActivity() {
private lateinit var dataBinding : ActivityImageBinding
private val imageViewModel by lazy { ViewModelProviders.of(this, ImageViewModelFactory()).get(ImageViewModel::class.java) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_image)
dataBinding.lifecycleOwner = this
dataBinding.viewModel = imageViewModel
// Retrofit
imageViewModel.liveImage.observe(this, Observer {
dataBinding.imageView.setImageBitmap(it)
})
// Picasso
imageViewModel.getPicassoImageLoader(Picasso.Builder(this)).into(dataBinding.imageView2)
}
}
ImageRequest.kt
data class ImageRequest(
#field:SerializedName("UserName")
val userName: String? = null,
#field:SerializedName("ContentId")
val contentId: String? = null,
#field:SerializedName("AndroidId")
val androidId: String? = null,
#field:SerializedName("Password")
val password: String? = null,
#field:SerializedName("frame")
val frame: String? = null
) {
companion object {
val default = ImageRequest(
"ApiService",
"704",
"15df3b3a90dc5688",
"BandarAndroid",
"1"
)
}
}
fun ImageRequest.toJson() : String {
return Gson().toJson(this, ImageRequest::class.java)
}

is it possible to access local file from file system using Okhttp

I have cordova webview in that one i'm loading the html from the filesystem i want to intercept the request using OkHttpClient is there any way i can request file from filesystem using OkHttpClient.
i tried to do normal call with okhttp but its giving error
Expected URL scheme 'http' or 'https' but was 'file'
WebResourceResponse getRequestResponse(String url) {
try {
OkHttpClient okHttpClient = new OkHttpClient();
final Call call = okHttpClient.newCall(new
Request.Builder().url(url).build());
final Response response = call.execute();
return new
WebResourceResponse("","",response.body().byteStream());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Use a magic hostname like "filesystem.local" and get an interceptor to handle requests to this host by loading from the filesystem.
val url = "http://filesystem.local/path/to/file.png".toHttpUrl()
You can use such an interceptor where you pass the url to rewrittenIfFileSchemeUrl(…) and use its return value as the actual url for the OkHttp request:
import okhttp3.Interceptor
import okhttp3.Protocol
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import java.io.FileNotFoundException
import java.net.URL
internal object OkHttpFileUrlHandler : Interceptor {
fun rewrittenIfFileSchemeUrl(url: String): String {
return if (url.startsWith("file:")) {
url.replaceFirst("file:", fileSystemMarkerPrefix)
} else url
}
private const val fileSystemMarkerHost = "filesystem.local"
private const val fileSystemMarkerPrefix = "http://$fileSystemMarkerHost"
private fun restoreFileUrl(markedFakeHttpUrl: String): String {
return markedFakeHttpUrl.replaceFirst(fileSystemMarkerPrefix, "file:")
}
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val url = request.url
if (url.host != fileSystemMarkerHost) return chain.proceed(request)
val fileUrl = restoreFileUrl(url.toString())
return try {
Response.Builder()
.body(URL(fileUrl).readBytes().toResponseBody())
.code(200)
.message("Some file")
.protocol(Protocol.HTTP_1_0)
.request(request)
.build()
} catch (e: FileNotFoundException) {
Response.Builder()
.body("".toResponseBody())
.code(404)
.message(e.message ?: "File not found ($fileUrl)")
.protocol(Protocol.HTTP_1_0)
.request(request)
.build()
}
}
}

How to pass a generic class to GsonRequest<T> constructor

How can I pass a generic class to GsonRequest class? Here is my api's response model.
class APIResponse<T> {
var status:Boolean
var data:T?
var collection: ArrayList<T>?
var message:String?
constructor(status:Boolean, data:T?, collection: ArrayList<T>?, message:String?){
this.status = status
this.data = data
this.collection = collection
this.message = message
}
}
And these are the kotlin models of tables in my database. There are used for converting json to models.
class ControlCategory {
var id:Int = 0
var name:String? = null
var control_points:ArrayList<ControlPoint> = ArrayList()
constructor(id:Int, name:String, control_points:ArrayList<ControlPoint>) {
this.id = id
this.name = name
this.control_points = control_points
}
}
class ControlPoint {
var id:Int
var name:String
var control_category: ControlCategory
constructor(id:Int, name:String, control_category:ControlCategory) {
this.id = id
this.name = name
this.control_category = control_category
}
}
Here is my GsonRequest class.
open class GsonRequest<T>(
url: String,
private val clazz: Class<T>,
private val headers: MutableMap<String, String>?,
private val listener: Response.Listener<T>,
errorListener: Response.ErrorListener
) : Request<T>(Method.GET, url, errorListener) {
protected val gson = Gson()
override fun getHeaders(): MutableMap<String, String> = headers ?: super.getHeaders()
override fun deliverResponse(response: T) = listener.onResponse(response)
override fun parseNetworkResponse(response: NetworkResponse?): Response<T> {
return try {
val json = String(
response?.data ?: ByteArray(0),
Charset.forName(HttpHeaderParser.parseCharset(response?.headers)))
Response.success(
gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response))
} catch (e: UnsupportedEncodingException) {
Response.error(ParseError(e))
} catch (e: JsonSyntaxException) {
Response.error(ParseError(e))
}
}
}
How can I pass APIResponse<ControlCategory> to GsonRequest class' :
val controlPointsRequest = GsonRequest<APIResponse<ControlCategory>>(
getString(R.string.apiUrl)+"control-categories",
object: TypeToken<APIResponse<ControlCategory>>(){}.type,
headers,
listener,
error
);
When I pass object: TypeToken<APIResponse<ControlCategory>>(){}.type it gives error.

Categories