microsoftgraph / msgraph-sdk-android

Microsoft Graph SDK for Android! https://graph.microsoft.io
Other
51 stars 43 forks source link

Error trying to download a json file from OneDrive #34

Closed kumaraish closed 7 years ago

kumaraish commented 7 years ago

Using the following code to download a .json file from OneDrive throws exception -

InputStream in = graphServiceClient
                    .getMe()
                    .getDrive()
                    .getItems(path)
                    .getContent()
                    .buildRequest()
                    .get();

Exception thrown -

 D/DefaultHttpProvider[sendRequestInternal] - 196: Starting to send request, URL https://graph.microsoft.com/v1.0/me/drive/items/XXXXXXXXXXXXXXX!375/content
 D/DefaultHttpProvider[sendRequestInternal] - 200: Request Method GET
     ...

D/DefaultHttpProvider[sendRequestInternal] - 239: Response code 200, OK
D/DefaultHttpProvider[sendRequestInternal] - 267: Response json
D/NativeCrypto: ssl=0x7f51e9e200 sslRead buf=0x7f6a32f800 len=2048,timeo=0
E/DefaultHttpProvider[sendRequestInternal] - 292: Error during http request
E/DefaultHttpProvider[sendRequestInternal] - 292: Throwable detail: 
          com.microsoft.graph.core.ClientException: Error during http request
              at com.microsoft.graph.http.DefaultHttpProvider.sendRequestInternal(DefaultHttpProvider.java:289)
              at com.microsoft.graph.http.DefaultHttpProvider.send(DefaultHttpProvider.java:157)
              at com.microsoft.graph.http.BaseStreamRequest.send(BaseStreamRequest.java:81)
              at com.microsoft.graph.generated.BaseDriveItemStreamRequest.get(BaseDriveItemStreamRequest.java:59)
              ...
           Caused by: java.lang.RuntimeException: Failed to invoke public java.io.InputStream() with no args
              at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:107)
              at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:186)
              at com.google.gson.Gson.fromJson(Gson.java:810)
              at com.google.gson.Gson.fromJson(Gson.java:775)
              at com.google.gson.Gson.fromJson(Gson.java:724)
              at com.google.gson.Gson.fromJson(Gson.java:696)
              at com.microsoft.graph.serializer.DefaultSerializer.deserializeObject(DefaultSerializer.java:63)
              at com.microsoft.graph.http.DefaultHttpProvider.handleJsonResponse(DefaultHttpProvider.java:338)
              at com.microsoft.graph.http.DefaultHttpProvider.sendRequestInternal(DefaultHttpProvider.java:268)
              at com.microsoft.graph.http.DefaultHttpProvider.send(DefaultHttpProvider.java:157) 
              at com.microsoft.graph.http.BaseStreamRequest.send(BaseStreamRequest.java:81) 
              at com.microsoft.graph.generated.BaseDriveItemStreamRequest.get(BaseDriveItemStreamRequest.java:59) 
              ...
           Caused by: java.lang.InstantiationException: Can't instantiate abstract class java.io.InputStream
              at java.lang.reflect.Constructor.newInstance(Native Method)
              at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:104)
              at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:186) 
              at com.google.gson.Gson.fromJson(Gson.java:810) 
              at com.google.gson.Gson.fromJson(Gson.java:775) 
              at com.google.gson.Gson.fromJson(Gson.java:724) 
              at com.google.gson.Gson.fromJson(Gson.java:696) 
              at com.microsoft.graph.serializer.DefaultSerializer.deserializeObject(DefaultSerializer.java:63) 
              at com.microsoft.graph.http.DefaultHttpProvider.handleJsonResponse(DefaultHttpProvider.java:338) 
              at com.microsoft.graph.http.DefaultHttpProvider.sendRequestInternal(DefaultHttpProvider.java:268) 
              at com.microsoft.graph.http.DefaultHttpProvider.send(DefaultHttpProvider.java:157) 
              at com.microsoft.graph.http.BaseStreamRequest.send(BaseStreamRequest.java:81) 
              at com.microsoft.graph.generated.BaseDriveItemStreamRequest.get(BaseDriveItemStreamRequest.java:59) 
              ...
iambmelt commented 7 years ago

Hi @kumaraish - thank you for reporting this issue. I'll be investigating this today, and will report back with a status

iambmelt commented 7 years ago

@kumaraish - I was able to reproduce this issue, and can confirm there is a bug with the library. I will see that this issue is entered into our bug tracker, and is addressed in future builds.

Additionally, two things worth calling out:

  1. OneDrive appears to set a Content-Type: application/json header to files suffixed with .json. This causes the response body to fail coercion into an InputStream because this code path is taken instead of this one. In its current form, the msgraph-sdk-android expects all /content requests to return a stream, although [as you've discovered] this is clearly not correct 100% of the time. As there is currently no available fix or workaround for this I suggest either renaming the file or falling back to REST/HTTP.
  2. EDITED* Alternative syntax for downloads: To fetch the content of a DriveItem, you may use the following syntax
InputStream is = mGraphServiceClient
                                    .getMe()
                                    .getDrive()
                                    .getItems()
                                    .byId("<your id here>")
                                    .getContent()
                                    .buildRequest()
                                    .get();
kumaraish commented 7 years ago

@iambmelt Thanks for the update. Could you please comment on if there is any advantage of doing .getItems().byId("<your id here>").getContent() over .getItems("<your id here>").getContent() . Either of them seems to work fine.

On a side note, as a temporary workaround for downloading json files from OneDrive, I am using @microsoft.graph.downloadUrl returned as part of the DriveItem metadata.

iambmelt commented 7 years ago

@kumaraish Apologies for the confusion; if both appear to be working acceptably (Content-Type bug aside), then feel free to use either. In my testing I had tried your sample code (thanks for providing this, btw) - saw it fail, then continued testing with an alternative implementation (matching my desc). I'll modify the above post to reflect this syntax as alternative.

Thank you for providing your workaround solution as well.

iambmelt commented 7 years ago

Closing this issue.

The current recommended pattern to download JSON from OneDrive is to request the DriveItemMetadata and perform a GET to the payload's @microsoft.graph.downloadUrl property