Retrofit 2 no annotation found - android

I am trying get specific data from Firebase. Using REST API and Retrofit 2 on client side.
Here is my JSON structure on Firebase:
{
"profiles" : {
"-KAG0XPBVNNF_RT55lwV" : {
"GCMTocken" : "rtdjhsrfjt546456",
"firstName" : "P",
"gender" : 1,
"lastName" : "Strongman",
"likes" : 0,
"nickname" : "drake1",
"uid" : "facebook:957484"
}
}
}
Request interface:
#GET("/profiles.json")
Observable<Profile> getProfile(#Query("orderBy") String key, #Query("equalTo") String uid);
On this request i always get:
java.lang.IllegalArgumentException: No Retrofit annotation found. (parameter #1)
for method FirebaseAPI.getProfile
EDIT
i need this request:
https://incandescent-torch-4.firebaseio.com/profiles.json?orderBy="uid"&equalTo="facebook:95748485767896"
My retrofit setup:
String BASE_FIREBASE_URL = "https://incandescent-torch-4.firebaseio.com";
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_FIREBASE_URL)
.client(okHttpClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
restAPI = retrofit.create(FirebaseAPI.class);
Request from RxJava:
RestFirebaseClient.getInstance().getProfile(authData.getUid())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Profile>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(Profile profile) {
}
});

I observe in your code request #GET request just put "/" & make sure in you url you have to remove "/" at the end of url like -
like this -
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://incandescent-torch-4.firebaseio.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
#GET("/profiles.json")
Observable<Profile> getProfile(#Query("orderBy") String key, #Query("equalTo") String uid);
This is included in documentation of retrofit.

Add Retrofit 2 dependency to Gradle:
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'
compile 'com.squareup.retrofit2:converter-jackson:2.0.0-beta3'
compile 'com.squareup.okhttp3:logging-interceptor:3.0.0-RC1'
Initialize Retrofit:
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY))
.addInterceptor(new TokenInterceptor())
.addInterceptor(new AuthenticationInterceptor())
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://your_url/")
.addConverterFactory(JacksonConverterFactory.create())
.client(client)
.build();
Create Retrofit services, such as:
import retrofit2.Call;
import retrofit2.http.GET;
public interface ProfileService {
#GET("profile")
Call<User> get();
}
I used #GET("profile") and finally url was: http://your_url/profile
You maybe try change Observable<Profile> to Call<Profile> and delete .json from #GET("profiles.json")

Related

Retrofit with OkHTTP not set Content-Type with #FormUrlEncoded

I'm trying to implement auth via x-www-form-urlencoded with Retrofit 2 on Android but faced a problem, that Header Content-Type not set with #FormUrlEncoded annotation, as well as I'm trying to set it manually, but when I'm setting it with a typo like Cotent-Type it works correctly and I can see it in headers.
Retrofit version: 2.4.0
So my question: why #FormUrlEncoded not set a content type as well as #Header annotation or what can remove it from headers.
My request:
#FormUrlEncoded
#POST("account/login")
Single<LoginResponse> login(#Field("memberId") String memberId,
#Field("pin") String pin);
OkHTTP/Retrofit provider with interceptors:
#Singleton
#Provides
Retrofit provideRetrofit(final OkHttpClient client, final Moshi moshi) {
return new Retrofit.Builder()
.baseUrl(Configuration.BASE_URL)
.client(client)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
#Provides
OkHttpClient provideOkHttpClient(#AppContext final Context context) {
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
.followRedirects(true)
.followSslRedirects(true)
.addInterceptor(createLanguageInterceptor(context));
if (BuildConfig.DEBUG) {
builder.addInterceptor(new LoggingInterceptor());
}
return builder.build();
}
Interceptor createLanguageInterceptor(#AppContext final Context context) {
Locale current = context.getResources().getConfiguration().locale;
return chain -> {
Request.Builder builder = chain.request().newBuilder();
builder.addHeader("Accept-Language", current.getLanguage());
Request request = builder.build();
Response response = chain.proceed(request);
return response;
};
}
As a workaround, I've implemented the following interceptor:
Interceptor createHeaderTransformationInterceptor() {
return chain -> {
final Request request = chain.request();
String dataType = request.header("Data-Type");
final Request resultRequest = dataType == null
? request
: chain.request().newBuilder()
.removeHeader("Data-Type")
.addHeader("Content-Type", dataType)
.build();
return chain.proceed(resultRequest);
};
}
and it works fine with the following annotation:
#Headers({"Data-Type: application/x-www-form-urlencoded"})
UPD: the reason that my interceptor didn't see that is in a place where the content type is stored. The right way to see that header in an interceptor:
if (requestBody.contentType() != null) {
logger.log("Content-Type: " + requestBody.contentType());
}
if (requestBody.contentLength() != -1) {
logger.log("Content-Length: " + requestBody.contentLength());
}
By this Request
#FormUrlEncoded
#POST("account/login")
Single<LoginResponse> login(#Field("memberId") String memberId,
#Field("pin") String pin);
method #POST and #FormUrlEncoded automatic add
Content-Type: application/x-www-form-urlencoded in header you can check in log by
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor.setLevel(HttpLoggingInterceptor.Level.BODY))
.connectTimeout(2, TimeUnit.MINUTES)
.writeTimeout(2, TimeUnit.MINUTES)
.readTimeout(2, TimeUnit.MINUTES)
.build();
it print all log in verbose mode

How can I debug my retrofit API call?

I'm using retrofit to get some data from the Flickr api. The method I'm making the call in looks like this:
public static List<String> getImageIds(int size) {
Call<PhotosList> call = flickrService.getPhotos(apiKey, format, "1");
Log.d("TEMP_TAG", "photo url: " + call.request().url().toString());
photoIds = new ArrayList<String>();
call.enqueue(new Callback<PhotosList>(){
#Override
public void onResponse(Call<PhotosList> call, Response<PhotosList> response) {
Log.d("TEMP_TAG", "it's getting here");
PhotosList photosList = response.body();
List<Photo> photos = photosList.getPhotos().getPhoto();
for(Photo photo : photos) {
Log.d("TEMP_TAG", "adding photo id to list: " + photo.getId());
photoIds.add(photo.getId());
}
}
#Override
public void onFailure(Call<PhotosList> call, Throwable t) {
// TODO: Clean up
Log.d("TEMP_TAG", "photoId: ");
}
});
Log.d("TEMP_TAG", "it's getting here too");
return photoIds;
}
However it is never getting into the onResponse() method. The first log statement within onResponse() never prints, neither does the log statement in onFailure(). When I try entering the URL that is returned by call.request().url().toString() in the browser it works fine, and I get the expected JSON. Why is my enqueue() method never firing?
Thanks for any help!
Use HttpLoggingInterceptor along with Retrofit.
If this helps, add this inside your build.gradle -
//Retrofit and OkHttp for Networking
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
//Logging Network Calls
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
Inside your APIClient class add this -
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
if(retrofit==null){
retrofit = new Retrofit.Builder()
.baseUrl(BuildConfig.baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
return retrofit;
}
}
Kotlin Code
val interceptor : HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client : OkHttpClient = OkHttpClient.Builder().apply {
addInterceptor(interceptor)
}.build()
fun getService(): Service {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(LiveDataCallAdapterFactory())
.client(client)
.build()
.create(Service::class.java)
}
And you will be able to log the Retrofit Network calls that you make.
Let me know if you need more information.
An OkHttp interceptor which logs HTTP request and response data.
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BASIC);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.build();
You can change the log level at any time by calling setLevel.
There are 4 levels: NONE, BASIC, HEADERS, BODY
To log to a custom location, pass a Logger instance to the constructor.
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new
Logger() {
#Override public void log(String message) {
Log.d(TAG, "message: ");
}
});
From Gradle
compile 'com.squareup.okhttp3:logging-interceptor:(insert latest version)'
Follow this reference
EDITED: I also found this library which has a very nice structure and clean log. Try it!!
You can use the following class to log API calls
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
object HTTPLogger {
fun getLogger(): OkHttpClient {
/*
* OKHTTP interceptor to log all API calls
*/
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
return client
}
}
You can then call this class in your retrofit instance class like this
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClientInstance {
private var retrofit: Retrofit? = null
val retrofitInstance: Retrofit?
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(HTTPLogger.getLogger())
.build()
}
return retrofit
}
}
The dependency required is
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'

Retrofit response Cache

There are a lot of complex answers here about Retrofit cache but none seem to help me.
How do I cache my code response coming from the Retrofit response?
My App works fine downloading the JSON below but I need to make a cache for it and I never did cache on Android.
I need to open the App offline and get the result from my Retrofit call as if I was online.
public class APIClient {
public static final String BASE_URL = "https://raw.githubusercontent.com/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
return retrofit;
}}
The json response is VERY simple:
{
"fruits":[
{
"name":"Apple",
"image":"https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Red_Apple.jpg/265px-Red_Apple.jpg",
"price":35
},
{
"name":"Banana",
"image":"https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Bananas_white_background_DS.jpg/320px-Bananas_white_background_DS.jpg",
"price":12
},
{
"name":"Grapes",
"image":"https://upload.wikimedia.org/wikipedia/commons/thumb/b/bb/Table_grapes_on_white.jpg/320px-Table_grapes_on_white.jpg",
"price":45
},
{
"name":"Pineapple",
"image":"https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Pineapple_and_cross_section.jpg/286px-Pineapple_and_cross_section.jpg",
"price":200
},
{
"name":"cherry",
"image":"http://www.desicomments.com/wp-content/uploads/2017/05/Cherry-Image-600x570.jpg",
"price":13
},
{
"name":"clementine",
"image":"http://www.icecreamnation.org/wp-content/uploads/2013/04/Clementine_orange.jpg",
"price":12.4
},
{
"name":"olive",
"image":"https://www.homenaturalcures.com/wp-content/uploads/olive.jpg",
"price":9.5
},
{
"name":"tomato",
"image":"http://cdn2.stylecraze.com/wp-content/uploads/2013/05/tomato-hair-benefits1.jpg",
"price":8.75
},
{
"name":"huckleberry",
"image":"http://farm3.static.flickr.com/2131/2082287810_47339fc93e.jpg",
"price":11.75
},
{
"name":"papaya",
"image":"http://media.mercola.com/assets/images/foodfacts/papaya-nutrition-facts.jpg",
"price":2.75
},
{
"name":"lime",
"image":"https://www.florihana.com/images/stories/virtuemart/product/FLE019%20-%20LIME.jpg",
"price":5.75
},
{
"name":"pear",
"image":"https://www.organicfacts.net/wp-content/uploads/pear.jpg",
"price":4.75
}
]
}
Assuming server respects Cache-Control/If-Modified-Since headers, than all you have to do is to create a Cache object and set it to OkHttpClient. Retrofit will take care of the rest.
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(getCacheDir(), cacheSize);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(cache)
.build();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://10.0.2.2:3000/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
Source: futurestud.io
Inorder cache our server response using retrofit 2.0 and okHttp, we all need is OkHttpClient, AddNetworkInterceptor add cache interceptor, you can not use. AddInterceptor, also need not both at the same time.
This method requires no server-side operation, no other server-side caching strategy, if the server has its own cache strategy code should be modified accordingly to adapt to the server.
You can refer this link , it helped me to solve my problem

Is possible to use multiple retrofit API

I am using retrofit 2. I need to use 2 different Rest API, because they have different base URL, headers and cookies.
public class RestClient {
private static IRestApi REST_CLIENT;
static {
setupRestClient();
}
public static IRestApi get() {
return REST_CLIENT;
}
private static void setupRestClient() {
Interceptor interceptor = new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
//add some cookies & headers
}
};
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(GenericConstants.READ_TIMEOUT, TimeUnit.SECONDS)
.connectTimeout(GenericConstants.CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GenericConstants.BASE_ENDPOINT_INSTAGRAM)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
REST_CLIENT = retrofit.create(IRestApi.class);
}
}
I am using it like so:
Call<Obj> call = RestClient.get().myMethod(params);
I want to create 2 clases like this, because I have 2 types of requests, 1 with headers and cookies and one plain, is this possible?
you can create method of retrofit url like
public Retrofit getAdapter(String url){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit;
}
Use this adapter wherever you want.

Custom xml converter with Retrofit 2.0.2 is never called

I have to use retrofit 2.0.2 with xml api response. But my custom xml converter is never called.
Playing around with this I found out:
if I use Volley to parse the same response, the same custom xml converter IS called;
if I apply GsonConverterFactory to my RestClient and parse json response, my custom JsonAdapter (#JsonAdapter(SomeAdapter.class)) IS called.
Anyone, how make my simple xml converter to be called? Am I doing something wrong, or retrofit 2.0.2 somehow doesn't support simple xml converter.
My java class where I parse response:
import org.simpleframework.xml.Element;
import org.simpleframework.xml.convert.Convert;
public class PassengerResponse {
#Element
#Convert(value = SomeConverter.class)
private String id;
}
Custom xml converter that is never called:
import org.simpleframework.xml.convert.Converter;
import org.simpleframework.xml.stream.InputNode;
import org.simpleframework.xml.stream.OutputNode;
public class SomeConverter implements Converter<String> {
#Override
public String read(InputNode node) throws Exception {
return null;
}
#Override
public void write(OutputNode node, String value) throws Exception {
}
}
My retrofit RestClient:
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;
public class RestClient2 {
private UserApiJSON userPassengerApi;
private static final int TIMEOUT = 120000;
private static RestClient2 INSTANCE;
public static RestClient2 getInstance() {
if (INSTANCE == null) {
INSTANCE = new RestClient2();
}
return INSTANCE;
}
private RestClient2() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(SimpleXmlConverterFactory.create())
.client(okHttpClient.newBuilder().connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(loggingInterceptor)
.build())
.build();
userPassengerApi = retrofit.create(UserApiJSON.class);
}
public UserApiJSON getUserPassengerApi() {
return userPassengerApi;
}
}
Actually SimpleXmlConverterFactory has different method to create its instance.) If all you need is to make your custom Converer(s) work, do the next:
Strategy strategy = new AnnotationStrategy();
Serializer serializer = new Persister(strategy);
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(SimpleXmlConverterFactory.create(serializer))
.client(okHttpClient.newBuilder().connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(loggingInterceptor).build())
.build();
Note: if you add different converters, order does metter. Why? Watch Jake Wharton presentation.
To use your custom converter you have create custom Converter.Factory. And than add it to the retrofit using method addConverterFactory(). Below working example:
public class StringConverterFactory extends Converter.Factory {
public static StringConverterFactory create() {
return new StringConverterFactory();
}
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if (String.class.equals(type)) {
return new Converter<ResponseBody, String>() {
#Override
public String convert(ResponseBody value) throws IOException {
return value.string();
}
};
}
return null;
}
}
And than add it retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(SimpleXmlConverterFactory.create())
.addConverterFactory(StringConverterFactory.create())
.client(okHttpClient.newBuilder().connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(loggingInterceptor)
.build())
.build();
In Retrofit 2 allows multiple converters. There is video by Jake Wharton who talks about Retrofit 2 and it features like a multiple converters.
Inside Retrofit class there is a method nextRequestBodyConverter which returns converter for appropriate Type
public UsStatesApi providesApi(){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Strategy strategy = new AnnotationStrategy();
Serializer serializer = new Persister(strategy);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(2, TimeUnit.MINUTES)
.writeTimeout(2, TimeUnit.MINUTES)
.readTimeout(2, TimeUnit.MINUTES)
.build();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create(serializer))
.baseUrl("http://www.google.com")
.client(okHttpClient)
.build();
return retrofit.create( UsStatesApi.class);
}

Categories

Resources