Skip to content
Advertisement

Google Cloud Function java.lang.NoClassDefFoundError while following example code

i try to test a gcloud function with a storage trigger. The gcloud function should call a gcloud service which is public, but require authentication. I can execute the function locally without any problem. But on gcloud I can found a NoClassDefFoundError in the function logs.

Failed to execute functions.HelloGcs java.lang.NoClassDefFoundError: io/opencensus/trace/propagation/TextFormat$Setter at com.google.api.client.http.HttpRequest.(HttpRequest.java:203) at com.google.api.client.http.HttpTransport.buildRequest(HttpTransport.java:115) at com.google.api.client.http.HttpRequestFactory.buildRequest(HttpRequestFactory.java:86) at com.google.api.client.http.HttpRequestFactory.buildGetRequest(HttpRequestFactory.java:117) at com.google.auth.oauth2.ComputeEngineCredentials.runningOnComputeEngine(ComputeEngineCredentials.java:285) at com.google.auth.oauth2.DefaultCredentialsProvider.tryGetComputeCredentials(DefaultCredentialsProvider.java:314) at com.google.auth.oauth2.DefaultCredentialsProvider.getDefaultCredentialsUnsynchronized(DefaultCredentialsProvider.java:223) at com.google.auth.oauth2.DefaultCredentialsProvider.getDefaultCredentials(DefaultCredentialsProvider.java:126) at com.google.auth.oauth2.GoogleCredentials.getApplicationDefault(GoogleCredentials.java:124) at com.google.auth.oauth2.GoogleCredentials.getApplicationDefault(GoogleCredentials.java:96) at functions.HelloGcs.makeGetRequest(HelloGcs.java:44) at functions.HelloGcs.accept(HelloGcs.java:37) at functions.HelloGcs.accept(HelloGcs.java:21) at com.google.cloud.functions.invoker.BackgroundFunctionExecutor$TypedFunctionExecutor.serviceLegacyEvent(BackgroundFunctionExecutor.java:285) at com.google.cloud.functions.invoker.BackgroundFunctionExecutor.lambda$serviceLegacyEvent$8(BackgroundFunctionExecutor.java:375) at com.google.cloud.functions.invoker.BackgroundFunctionExecutor.runWithContextClassLoader(BackgroundFunctionExecutor.java:382) at com.google.cloud.functions.invoker.BackgroundFunctionExecutor.serviceLegacyEvent(BackgroundFunctionExecutor.java:375) at com.google.cloud.functions.invoker.BackgroundFunctionExecutor.service(BackgroundFunctionExecutor.java:330) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:755) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:547) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1297) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:485) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1212) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at com.google.cloud.functions.invoker.runner.Invoker$NotFoundHandler.handle(Invoker.java:392) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.Server.handle(Server.java:500) at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383) at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:547) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:270) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:388) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806) at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938) at java.base/java.lang.Thread.run(Thread.java:829) Caused by: java.lang.ClassNotFoundException: io.opencensus.trace.propagation.TextFormat$Setter at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) … 47 more

Setup:

As you can see, I use the cloud trigger java example code from here: https://cloud.google.com/functions/docs/calling/storage?hl=de#functions-calling-storage-java

I have extended the code by a static function from here: https://cloud.google.com/run/docs/authenticating/service-to-service#acquire-token

The code of the final demo class:

package functions;

import com.google.cloud.functions.BackgroundFunction;
import com.google.cloud.functions.Context;
import functions.eventpojos.GcsEvent;

import java.io.IOException;
import java.util.logging.Logger;

import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.IdTokenCredentials;
import com.google.auth.oauth2.IdTokenProvider;


public class HelloGcs implements BackgroundFunction<GcsEvent> {
    private static final Logger logger = Logger.getLogger(HelloGcs.class.getName());

    private static final String PATH = "https://demo/api/smoke";

    @Override
    public void accept(GcsEvent event, Context context) {
        logger.info("Event: " + context.eventId());
        logger.info("Event Type: " + context.eventType());
        logger.info("Bucket: " + event.getBucket());
        logger.info("File: " + event.getName());
        logger.info("Metageneration: " + event.getMetageneration());
        logger.info("Created: " + event.getTimeCreated());
        logger.info("Updated: " + event.getUpdated());
        logger.info("Call: " + PATH);
        try {
            makeGetRequest(PATH);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

      public static HttpResponse makeGetRequest(String serviceUrl) throws IOException {
        GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
        if (!(credentials instanceof IdTokenProvider)) {
          throw new IllegalArgumentException("Credentials are not an instance of IdTokenProvider.");
        }
        IdTokenCredentials tokenCredential =
            IdTokenCredentials.newBuilder()
                .setIdTokenProvider((IdTokenProvider) credentials)
                .setTargetAudience(serviceUrl)
                .build();

        GenericUrl genericUrl = new GenericUrl(serviceUrl);
        HttpCredentialsAdapter adapter = new HttpCredentialsAdapter(tokenCredential);
        HttpTransport transport = new NetHttpTransport();
        HttpRequest request = transport.createRequestFactory(adapter).buildGetRequest(genericUrl);
        return request.execute();
      }
}

The example code was uploaded with

gcloud functions deploy java-gcs-function
–entry-point functions.HelloGcs
–runtime java11
–memory 512MB
–trigger-resource YOUR_TRIGGER_BUCKET_NAME
–trigger-event google.storage.object.finalize

The owner of the function is an additional service account (as described here https://cloud.google.com/run/docs/authenticating/service-to-service chapter “Set up the service account”)

Thanks in advance and any help will be much appreciated.

Advertisement

Answer

The exception is saying that an external library you depend on is not available on the classpath of the program.

The easiest way to resolve that would be to submit your code as a fat jar such that all dependencies are available at runtime.

Advertisement