15

I can't make a request using Google TTS Client library in java. Each time it throws a bunch of exceptions.

I just try to get a list of available voices.

    GoogleCredentials creds = null;
    TextToSpeechClient textToSpeechClient = null;
    try {
        creds = GoogleCredentials.fromStream(new FileInputStream(credsFile));
        TextToSpeechSettings settings = TextToSpeechSettings.newBuilder().setCredentialsProvider(FixedCredentialsProvider.create(creds)).build();
        textToSpeechClient = TextToSpeechClient.create(settings);
    } catch (IOException e) {
        e.printStackTrace();
        System.exit(-2);
    }

    if (cmd.hasOption('l')) {
        ListVoicesRequest request = ListVoicesRequest.getDefaultInstance();
        ListVoicesResponse response = textToSpeechClient.listVoices(request);
        List<Voice> voices = response.getVoicesList();
        System.out.println("Available voices :");
        for (Voice v : voices) {
            System.out.printf(" - %s, [%d]: %s/%s", v.getName(), v.getLanguageCodesCount(), v.getLanguageCodes(0), v.getSsmlGender());
        }
        textToSpeechClient.close();
        System.exit(0);
    }

I first thought it came from the credentials file. But it's not, the file is correctly located.

And I get this.

avr. 02, 2019 11:36:46 PM io.grpc.internal.ManagedChannelImpl$1 uncaughtException
SEVERE: [Channel<1>: (texttospeech.googleapis.com:443)] Uncaught exception in the SynchronizationContext. Panic!
java.lang.IllegalStateException: Could not find policy 'pick_first'. Make sure its implementation is either registered to LoadBalancerRegistry or included in META-INF/services/io.grpc.LoadBalancerProvider from your jar files.
        at io.grpc.internal.AutoConfiguredLoadBalancerFactory$AutoConfiguredLoadBalancer.<init>(AutoConfiguredLoadBalancerFactory.java:93)
        at io.grpc.internal.AutoConfiguredLoadBalancerFactory.newLoadBalancer(AutoConfiguredLoadBalancerFactory.java:64)
        at io.grpc.internal.ManagedChannelImpl.exitIdleMode(ManagedChannelImpl.java:357)
        at io.grpc.internal.ManagedChannelImpl$ChannelTransportProvider$1ExitIdleModeForTransport.run(ManagedChannelImpl.java:455)
        at io.grpc.SynchronizationContext.drain(SynchronizationContext.java:101)
        at io.grpc.SynchronizationContext.execute(SynchronizationContext.java:130)
        at io.grpc.internal.ManagedChannelImpl$ChannelTransportProvider.get(ManagedChannelImpl.java:459)
        (...) a whole bunch of other lines

How to fix this error ?

Note that I'm using the latest google-cloud-texttospeech library (version 0.85.0-beta).

Bharat Patil
  • 1,398
  • 1
  • 11
  • 28
Gui-Yôm
  • 165
  • 1
  • 8
  • What is "policy 'pick_first'" and where is its implementation? Also, do the words "caused by" appear in the _whole bunch of other lines_ ? – Abra Apr 03 '19 at 19:29
  • I don't know what "policy 'pick_first'" is. Here's the next Caused by : `Caused by: io.grpc.StatusRuntimeException: INTERNAL: Panic! This is a bug!`. This does not help much. However, I think its related to google's servers load balancing. In this context, 'pick_first' would mean "pick first available server". But it looks like the client doesn't know how to handle this strategy. – Gui-Yôm Apr 04 '19 at 10:56
  • Often a stack trace will contain more than one _Caused by:_. Usually the last one points to the part of the code where the exception is occurring. I always look for lines in the stack trace, after the last _Caused by:_ that contain methods that I wrote, i.e. not 3rd party code. I asked about "pick_first" because it appears in the stack trace you posted: `Could not find policy 'pick_first'` – Abra Apr 04 '19 at 11:31
  • Here's the full stacktrace : [https://pastebin.com/D7LqvhqT](https://pastebin.com/D7LqvhqT). The problem is that I can't see the problem in my code. The stacktrace refers to this line in my main() : `textToSpeechClient.listVoices(request);` – Gui-Yôm Apr 04 '19 at 13:21

6 Answers6

13

If you're using Gradle with the ShadowJar plugin, this is all you need to get it to merge the contents of service files from the various gRPC libraries:

shadowJar {
    mergeServiceFiles()
}

Discovered from a thread here.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • For more context, in your build.gradle file put in the dependency of ` id("com.github.johnrengelman.shadow") version "7.1.2"`, and then do something like tasks.shadowJar { archiveBaseName.set("appName") archiveVersion.set("0.0.1") mergeServiceFiles() manifest { attributes["Main-Class"] = "com.appName.ApplicationKt" } } – MQLN Aug 22 '23 at 18:18
7

The io.grpc library registers classes from a file in your META-INF/services.

So, create a file named io.grpc.LoadBalancerProvider in that folder with the content:

io.grpc.internal.PickFirstLoadBalancerProvider

The library should find the class that way.

dhontecillas
  • 103
  • 5
  • Thanks ! But I ended up not using this library anymore, I did the http requests myself. – Gui-Yôm Apr 14 '19 at 18:05
  • Unfortunately, adding this file did not fix the _jar_ issue above in the project. – AdamHurwitz Dec 28 '19 at 23:07
  • 1
    @AdamHurwitz make sure you put the file in the correct place. Take a look at [this](https://github.com/googleapis/google-cloud-java/issues/4700) github thread (link to relevant comment - [here](https://github.com/googleapis/google-cloud-java/issues/4700#issuecomment-477658832) ) – jurl May 27 '20 at 07:46
  • For future folks, my solution using Maven was to do a few different things using the github thread: I needed to update the pom to use the [Services Resource Transfromer](https://github.com/googleapis/google-cloud-java/issues/4700#issuecomment-569456452), and add the transformers included in this [comment](https://github.com/googleapis/google-cloud-java/issues/4700#issuecomment-474739796) – RJohnson Feb 17 '23 at 16:04
6

Another solution. Hope can help somebody.

Problem is the package name of io.grpc.INTERNAL.PickFirstLoadBalacerProvider class. Insert below code lines before you use grpc.

import com.google.cloud.internal.PickFirstLoadBalancer;
...
LoadBalancerRegistry.getDefaultRegistry().register(new PickFirstLoadBalancerProvider());

LoadBalancerProviders are registered at map in the LoadBalancerRegistry and key of map is the name of class (not exactly but does not matter). So LoadBalancerRegistry returns newly registered class to the grpc.

Youngrok Ko
  • 351
  • 1
  • 4
  • 10
  • Thanks. This helped me. Needed to register grpclb `LoadBalancerRegistry.getDefaultRegistry().register(GrpclbLoadBalancerProvider())` – casey Jul 24 '21 at 02:22
  • thanks. works for me. but my import is `import io.grpc.LoadBalancerRegistry;` – ujjal das Apr 30 '23 at 17:21
4

If you use Maven and the maven-shade plugin, be sure to configure the ServicesResourceTransformer:

<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>

3

You can also create multiple entries in io.grpc.LoadBalancerProvider. For Google's Pub/Sub library (Google Chat bot messaging middleware), I see the following:

io.grpc.grpclb.GrpclbLoadBalancerProvider
io.grpc.internal.PickFirstLoadBalancerProvider
io.grpc.util.SecretRoundRobinLoadBalancerProvider$Provider

Multiple entries is a problem if you are creating a fat/shaded jar, since the entries overwrite each other.

halpdoge
  • 642
  • 7
  • 19
0

This probably happens because you have dependency which is already included in some other dependency but with different version.

Alexander
  • 39
  • 4
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 22 '22 at 21:29