retrofit icon indicating copy to clipboard operation
retrofit copied to clipboard

Parse Kotlin metadata manually to honor nullability and avoid kotlin-metadata-jvm dep

Open AidanLaing opened this issue 5 years ago • 30 comments

Version: 2.6.0-SNAPSHOT Exception: KotlinNullPointerException Message: Response from {path to my suspend fun...} was null but response body type was declared as non-null

The current structure of my suspend fun in my service interface:

@POST("api/...")
suspend fun request(@Body body: Body): Response?

I'm using Gson for serialization.

Is there a way to declare the response body type as nullable that I'm missing? I've tried adding null safety on my response object with ? and @Nullable with no success.

AidanLaing avatar Apr 12 '19 00:04 AidanLaing

Not currently. I'm working on a parser for Kotlin metadata so we don't have to depend on a gigantic jar to read one isNullable boolean.

On Thu, Apr 11, 2019, 8:27 PM Aidan Laing [email protected] wrote:

Version: 2.6.0-SNAPSHOT Exception: KotlinNullPointerException Message: Response from {path to my suspend fun...} was null but response body type was declared as non-null

The current structure of my suspend fun in my service interface:

@POST("api/...") suspend fun request(@Body body: Body): Response?

I'm using Gson for serialization.

Is there a way to declare the response body type as nullable that I'm missing? I've tried adding null safety on my response object with ? and @Nullable with no success.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/3075, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEb6RFk0-5aDUMDF6fMlN9U2r9w7Hks5vf9MHgaJpZM4crGCw .

JakeWharton avatar Apr 12 '19 00:04 JakeWharton

@JakeWharton Please notice that suspend ...: List<*> also is not supported. Version: 2.6.0-SNAPSHOT For instance: suspend fun fetchStrings(): List<String>

rodion-m avatar Apr 18 '19 01:04 rodion-m

I'm not sure how that's related to null body handling. Feel free to file a separate issue with a failing test case.

On Wed, Apr 17, 2019, 9:41 PM Rodion Mostovoy [email protected] wrote:

@JakeWharton https://github.com/JakeWharton Please notice that suspend ...: List<*> also is not supported. Version: 2.6.0-SNAPSHOT For instance: suspend fun fetchStrings(): List

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/3075#issuecomment-484323140, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAQIEKC4PRPCZTA5WTQBNDPQ7GTBANCNFSM4HFMMCYA .

JakeWharton avatar Apr 18 '19 01:04 JakeWharton

Added @JakeWharton I'm getting a similar KotlinNullPointerException using a service that returns 204 (no content) on a delete call. Something like this: @DELETE("/api/{id}") suspend fun deleteItem(@Path("id") id: String) Would that use case also be fixed as part of this issue?

wlara avatar Jun 12 '19 00:06 wlara

No. That's #2867

JakeWharton avatar Jun 12 '19 01:06 JakeWharton

Hi there! Any chance to get update on this issue? :) Want to move to 2.6.0 and remove all other dependencies but can't cause of null response body not supported :(

Hospes avatar Jul 03 '19 07:07 Hospes

Moved to #2867

jgavazzisp avatar Jul 16 '19 19:07 jgavazzisp

That is not related to this issue. It's #2867.

JakeWharton avatar Jul 16 '19 19:07 JakeWharton

So at this moment we should force an exception with a interceptor for 204 responses?

JavierSegoviaCordoba avatar Jul 23 '19 07:07 JavierSegoviaCordoba

This issue has nothing to do with 204 handling and when it's fixed 204 handling won't have changed in any way. That's #2867.

JakeWharton avatar Jul 23 '19 16:07 JakeWharton

Just in case it helps. I was experiencing the exact same KotlinNPE issue over the last 2 days and after trying Converters and Adapters what really worked was to return Response<Unit> in the retrofit method declaration.

I use Retrofit 2.6.0.

claucookie avatar Jul 26 '19 10:07 claucookie

Any progress? We've just changed some of our REST endpoints to 204. So I thought it would be enought to just remove response type (making it Unit), but no.

Using Response<Unit> works :+1:

Pitel avatar Dec 11 '19 14:12 Pitel

Why not:

https://github.com/Kotlin/kotlinx.reflect.lite

vladimirfx avatar Feb 14 '20 08:02 vladimirfx

Because it doesn't provide the necessary info

JakeWharton avatar Feb 14 '20 13:02 JakeWharton

Using Response<Unit> works

In this case retrofit does not throw any exception when got 4xx codes Reproduced at 2.6.2

september669 avatar Feb 20 '20 02:02 september669

That is the expected behavior for that return type.

JakeWharton avatar Feb 20 '20 02:02 JakeWharton

Is it something that is open for a PR or do you want to implement it yourself in Retrofit or as an external project and use it here? I see that there is an old branch so I'd like to ask first before spending some time on it.

MiSikora avatar Feb 25 '20 10:02 MiSikora

Feel free to give it a shot

On Tue, Feb 25, 2020, at 5:31 AM, Michał Sikora wrote:

Is it something that is open for a PR or do you want to implement it yourself in Retrofit or as an external project and use it here? I see that there is an old branch https://github.com/square/retrofit/tree/jakew/nully/2019-02-15 so I'd like to ask first before spending some time on it.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/retrofit/issues/3075?email_source=notifications&email_token=AAAQIELMEQYZS3ED6MORGVDRETXOJA5CNFSM4HFMMCYKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEM3NYOQ#issuecomment-590797882, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAQIENX2JYOB4K4V6XXXVDRETXOJANCNFSM4HFMMCYA.

JakeWharton avatar Feb 25 '20 13:02 JakeWharton

Found that empty response failed with the NPE mentioned. To cope with that problem, I wrapped all my backend json calls (on the backend side) inside an array. So if the result was empty, I returned an empty array at least.

Just a tip to solve the problem if you have access and ability to change your backend data source.

RG

RoarGronmo avatar Apr 08 '20 12:04 RoarGronmo

Using Response<Unit> works

In this case retrofit does not throw any exception when got 4xx codes Reproduced at 2.6.2

Hi, to handle empty response only choice seems like Response<Void> but that makes 4xx look like success. Any proper way to handle both empty response AND see 4xx as error (e.g. @GET suspend fun should throw exception) ?

Update: Using custom response converter suggested in #1554 works fine, (not converting empty body and returning null in such cases). But return type in API interface must be Unit instead of Any?. Otherwise it throws exception written above by OP

jemshit avatar Jul 03 '20 13:07 jemshit

https://github.com/square/retrofit/issues/3075#issuecomment-586156499

Why not:

https://github.com/Kotlin/kotlinx.reflect.lite

https://github.com/square/retrofit/issues/3075#issuecomment-586279157

Because it doesn't provide the necessary info

Are you sure? It looks to me like you can read "one isNullable boolean" right here: https://github.com/Kotlin/kotlinx.reflect.lite/blob/47bfb95540f361143add39300017c6904720812a/src/main/java/kotlinx/reflect/lite/api.kt#L45-L47

magneticflux- avatar Oct 04 '20 02:10 magneticflux-

Any new on this?

How to handle 400 codes and empty body? I tried everything in this topic, but nothing worked.

Success called with the 400 error

klaszlo8207 avatar Oct 21 '20 17:10 klaszlo8207

I have added wrong headers that caused me that HTTP 400 Bad request error.

removing the following worked .addHeader("Content-Encoding", "UTF-8") .header("Accept-Encoding", "identity")

  might help someone
  

GiridharaSPK avatar Feb 05 '21 07:02 GiridharaSPK

@JakeWharton not any updates about this? Its been 2 years since issue has open :D

rezznov avatar Mar 09 '21 12:03 rezznov

right now I handled this by a simple try catch like this

try {
                ResultWrapper.Success(request.invoke())
            } catch (e: KotlinNullPointerException) {
                ResultWrapper.NoContentError
            }

rezznov avatar Mar 09 '21 13:03 rezznov

Having an interceptor that rewrites the http 204 and 205 responses to 200 should work best.

LouisCAD avatar Mar 09 '21 13:03 LouisCAD

Hi, I hit this a few times recently, so I thought I'd give it a shot: https://github.com/square/retrofit/pull/3544. Any feedback is welcome.

ferinagy avatar Apr 21 '21 06:04 ferinagy

If you get No type arguments expected for class Response when using Response<Unit>, make sure you're using retrofit2.Response<> and not something like okhttp3.Response. That fixed the issue for me

Snailedlt avatar May 20 '21 09:05 Snailedlt

If you get No type arguments expected for class Response when using Response<Unit>, make sure you're using retrofit2.Response<> and not something like okhttp3.Response. That fixed the issue for me

This saved me a lot of digging, was using a Response<T> class from my module

tamimattafi avatar Oct 03 '22 03:10 tamimattafi

any suggestion for flow?

MoustafaElsaghier avatar Jul 19 '23 10:07 MoustafaElsaghier