NullPointerException is thrown in Youtube data api v3

Viewed 140

I am using Youtube data api v3 in my app. I want to implement subscriptions.insert method in it, but my code thorws a NullPointerException. Below is my code

public class SubscribeActivity extends YouTubeBaseActivity {

    Button play;
    private static final String DEVELOPER_KEY = "My Api Key";
    private static final Collection<String> SCOPES =
            Arrays.asList("https://www.googleapis.com/auth/youtube.force-ssl");

    private static final String APPLICATION_NAME = "Youtube Promotion";
    private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();

    public static Credential authorize(final NetHttpTransport httpTransport) throws IOException {
        // Load client secrets.
        Reader clientSecretReader = new InputStreamReader(Auth.class.getResourceAsStream("/client_secrets.json"));
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, clientSecretReader);

        GoogleAuthorizationCodeFlow flow =
                new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
                        .build();
        Credential credential =
                new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
        return credential;
    }

    public static YouTube getService() throws GeneralSecurityException, IOException {
        final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        Credential credential = authorize(httpTransport);
        return new YouTube.Builder(httpTransport, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }

    Subscription response;
    YouTube youtubeService;
    Subscription subscription;
    SubscriptionSnippet snippet;
    ResourceId resourceId;
    YouTube.Subscriptions.Insert request;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_subscribe);

        play = findViewById(R.id.youtubePlay);
     

        play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try{

                 
                        youtubeService = getService();
                    

                    // Define the Subscription object, which will be uploaded as the request body.
                     subscription = new Subscription();

                    // Add the snippet object property to the Subscription object.
                     snippet = new SubscriptionSnippet();
                     resourceId = new ResourceId();
                    resourceId.setChannelId("UCFCGruiJ_THqlW-5kYEcrJg");
                    resourceId.setKind("youtube#channel");
                    snippet.setResourceId(resourceId);
                    subscription.setSnippet(snippet);

                    // Define and execute the API request
                    request = youtubeService.subscriptions()
                            .insert("snippet", subscription);
                    response = request.execute();
                    System.out.println(response);
                    Log.d("TAG", "getYoutubeChannel: " + response);
                }catch (IOException e){
                    Log.d("TAG", "IOException: " + e.getMessage());
                }catch (GeneralSecurityException e){
                    Log.d("TAG", "General: " + e.getMessage());
                }


            }
        });

Exception is thrown in these lines

Reader clientSecretReader = new InputStreamReader(Auth.class.getResourceAsStream("/client_secrets.json"));
 Credential credential = authorize(httpTransport);
 youtubeService = getService();

Here is the logcat

2022-06-23 15:38:07.231 14969-14969/com.cigrastudio.youtubepromotion E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.cigrastudio.youtubepromotion, PID: 14969
java.lang.NullPointerException
    at java.io.Reader.<init>(Reader.java:78)
    at java.io.InputStreamReader.<init>(InputStreamReader.java:72)
    at com.cigrastudio.youtubepromotion.SubscribeActivity.authorize(SubscribeActivity.java:51)
    at com.cigrastudio.youtubepromotion.SubscribeActivity.getService(SubscribeActivity.java:65)
    at com.cigrastudio.youtubepromotion.SubscribeActivity$2.onClick(SubscribeActivity.java:103)
    at android.view.View.performClick(View.java:8160)
    at android.widget.TextView.performClick(TextView.java:16222)
    at android.view.View.performClickInternal(View.java:8137)
    at android.view.View.access$3700(View.java:888)
    at android.view.View$PerformClick.run(View.java:30236)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:246)
    at android.app.ActivityThread.main(ActivityThread.java:8653)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

Note: I have generated an API Key in the cloud console for this project and have put client_secrets.json in app/src forlder. Please pardon if I have made any blunder. Thank You

Update 1 I have made the following changes

 private static final String DEVELOPER_KEY = "My Api Key";
    private static final Collection<String> SCOPES =
            Arrays.asList("https://www.googleapis.com/auth/youtube.force-ssl");
    private static final String CLIENT_SECRETS= "client_secrets.json";

    private static final String APPLICATION_NAME = "Youtube Promotion";
    private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();


    public  Credential authorize(final NetHttpTransport httpTransport) throws IOException {
        // Load client secrets.


        FileReader clientSecretReader = (FileReader) new InputStreamReader(getAssets().open(CLIENT_SECRETS));
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, clientSecretReader);
        GoogleAuthorizationCodeFlow flow =
                new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
                        .build();
        credential =
                new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
        return credential;
    }


    public  YouTube getService() throws GeneralSecurityException, IOException {
        final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        Credential credential = authorize(httpTransport);
        return new YouTube.Builder(httpTransport, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }

    Subscription response;
    YouTube youtubeService;
    Subscription subscription;
    SubscriptionSnippet snippet;
    ResourceId resourceId;
    YouTube.Subscriptions.Insert request;

    public static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
    private static final String CREDENTIALS_DIRECTORY = ".oauth-credentials";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_subscribe);

        play = findViewById(R.id.youtubePlay);
        youTubePlayerView = findViewById(R.id.youtubePlayerView);

        youtubeService = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).build();

        onInitializedListener = new YouTubePlayer.OnInitializedListener() {
            @Override
            public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
                youTubePlayer.loadVideo("vwpJQTRj7tU");
            }

            @Override
            public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {

            }
        };
        youTubePlayerView.initialize(DEVELOPER_KEY, onInitializedListener );

        play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try{
                        youtubeService = getService();
                    // Define the Subscription object, which will be uploaded as the request body.
                     subscription = new Subscription();

                    // Add the snippet object property to the Subscription object.
                     snippet = new SubscriptionSnippet();
                     resourceId = new ResourceId();
                    resourceId.setChannelId("UCFCGruiJ_THqlW-5kYEcrJg");
                    resourceId.setKind("youtube#channel");
                    snippet.setResourceId(resourceId);
                    subscription.setSnippet(snippet);

                    // Define and execute the API request
                    request = youtubeService.subscriptions()
                            .insert("snippet", subscription);
                    response = request.execute();
                    System.out.println(response);
                    Log.d("TAG", "getYoutubeChannel: " + response);
                }catch (IOException e){
                    Log.d("TAG", "IOException: " + e.getMessage());
                }catch (GeneralSecurityException e){
                    Log.d("TAG", "General: " + e.getMessage());
                }


            }
        });

This code throws IOException: client_secrets.json

Location of client_secrets.json file

2 Answers

Edit 3 Note: I have generated an API Key in the cloud console for this project and have put client_secrets.json in app/src forlder.

Currently, your file is in the resource folder, So move that file into the assets folder, and apply the below functions.

Edit 2

as you mentioned now error was changed to the authorize, you have to put your json file in asset so you can easily read that file. InputStreamReader(getAssets().open("client_secrets.json"))

public Credential authorize(final NetHttpTransport httpTransport) throws IOException {
    // Load client secrets.
    Reader clientSecretReader = new InputStreamReader(getAssets().open("client_secrets.json"));
    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, clientSecretReader);

    GoogleAuthorizationCodeFlow flow =
            new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
                    .build();
    Credential credential =
            new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
    return credential;
}

getService() Function Should me non-static

 public YouTube getService() throws GeneralSecurityException, IOException {
        final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        Credential credential = authorize(httpTransport);
        return new YouTube.Builder(httpTransport, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }

Wrong condition

if (youtubeService != null) {
    youtubeService = getService();
}

The above condition reinitialize youtubeService object if its not null, means if its null then it will do nothing.

This condition should be

if (youtubeService == null) {
    youtubeService = getService();
}

I'd assume that the problem stems from this line:

new InputStreamReader(Auth.class.getResourceAsStream("/client_secrets.json"));

Passing an actual InputStream might evetually help; or at least check for it:

if (Auth.class.getResourceAsStream("/client_secrets.json") == null) {
    throw new IOException();
}

Credential should be initialized with that JSON file / or contents. Not getting a handle to the InputStreamReader and not reading BufferedInputStream will not result in a valid Credential.

The default location for file client_secret.json would be:

src/main/resources/client_secret.json

It seems as if you try to run common Java on Android, which is quite unlikely to succeed.
On Android this would be requireContext().getResources() with R.raw.client_secret:

src/main/res/raw/client_secret.json
Related