google / agera

Reactive Programming for Android
Apache License 2.0
7.2k stars 639 forks source link

Exception when Response is Empty #144

Closed mahmoud-elnaggar closed 7 years ago

mahmoud-elnaggar commented 7 years ago

I'm making a DELETE request to a server and when it success it returns empty string but in Agera ,the response must not be an empty string because the responseBody will be null so it throws an exception here

  @NonNull
  public static <T> Result<T> success(@NonNull final T value) {
    return new Result<>(checkNotNull(value), null);
  }

is there any workaround for this case ?

ghost commented 7 years ago

Is this done using the net sample extension? If so, do you have a stack trace you can add here?

In general though, a success would always have to contain a non-null value. If you have a value that's null it'd have to use absent or if you have a value that sometimes is null, absentIfNull. Result would support containing an empty string though (if it's a Result of a string that is).

If the sample extension is trying to put a null value in a success, we'll make sure to fix it, but that stack trace would be helpful.

ghost commented 7 years ago

@mahmoud-elnaggar do you have any additional input on this?

mahmoud-elnaggar commented 7 years ago

@ernstsson
I'm very sorry for being late this is my stack trace

java.lang.NullPointerException at com.google.android.agera.Preconditions.checkNotNull(Preconditions.java:40) at com.google.android.agera.Result.success(Result.java:71) at me.drakeet.retrofit2.adapter.agera.CallSupplier.get(CallSupplier.java:47) at me.drakeet.retrofit2.adapter.agera.CallSupplier.get(CallSupplier.java:32) at com.google.android.agera.CompiledRepository.runGetFrom(CompiledRepository.java:340) at com.google.android.agera.CompiledRepository.runFlowFrom(CompiledRepository.java:301) at com.google.android.agera.CompiledRepository.run(CompiledRepository.java:540) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818) 03-06 18:52:53.156 3509-6069/? E/android.os.Debug: ro.product_ship = true 03-06 18:52:53.156 3509-6069/? E/android.os.Debug: ro.debug_level = 0x4f4c 03-06 18:52:53.156 3509-6069/? E/android.os.Debug: sys.mobilecare.preload = false 03-06 18:52:55.446 4399-4485/? E/ContactsProvider_EventLog: Flush buffer to file cnt : 15 size : 40Kb duration : 412ms lastUpdatedAfter : 152052ms

and this is how I initialize my Repository

`public <R> Repository<Result<R>> getRepository(Supplier<Result<R>> supplier) {
    return Repositories
            .repositoryWithInitialValue(Result.<R>absent())
            .observe()
            .onUpdatesPerLoop()
            .goTo(Executors.newSingleThreadExecutor())
            .attemptGetFrom(supplier)
            .orEnd(Result::failure)
            .thenTransform(Result::success)
            .compile();
}`

it is a generic method as you see to use it with different datatype and thats why I don't know how to use absenceIfNull

and this is how I use it with retrofit 2

`private CareemAPI getRetrofitAPI(String baseUrl, Class<CareemAPI> uberAPIClass) throws Exception {
    if (baseUrl == null) throw new Exception();

    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
    loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(60, TimeUnit.SECONDS)
            .addInterceptor(loggingInterceptor)
            .addInterceptor(chain -> {
                Request request = chain.request();
                request = request.newBuilder().addHeader("Authorization", Config.CAREEM_TOKEN).build();
                return chain.proceed(request);
            })
            .build();

    Retrofit retrofit = new Retrofit.Builder()
            .client(client)
            .addCallAdapterFactory(AgeraCallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(baseUrl)
            .build();
    return retrofit.create(uberAPIClass);
}`

the problem when I do a DELETE request which return empty response then Agera throws this exception

thanks for your intention :)

ghost commented 7 years ago

Thanks! The issue is really in https://github.com/drakeet/retrofit-agera-call-adapter that calls Result.success with null here:

https://github.com/drakeet/retrofit-agera-call-adapter/blob/50b2ed6d1ecc89f86a7bcd7c66283df5058dcfe7/agera-call-adapter/src/main/java/me/drakeet/retrofit2/adapter/agera/CallSupplier.java#L47

And possibly also here:

https://github.com/drakeet/retrofit-agera-call-adapter/blob/50b2ed6d1ecc89f86a7bcd7c66283df5058dcfe7/agera-call-adapter/src/main/java/me/drakeet/retrofit2/adapter/agera/CallResponseSupplier.java#L47

I'll file a bug on retrofit-agera-call-adapter, @drakeet looping you in here for ref.