Java Callout throwing error "Failed to find the ClassName in java resource"

Not applicable

@Deepika: I am trying to configure Java Callout policy in APIGEE by uploading jar file in resources. This jar works fine when I tried to run it from command prompt but it is not getting deployed on APIGEE Edge throwing error "Failed to find the ClassName in java resource"

1 1 921
1 REPLY 1

Hi -

The first thing to check is that the class name you specify in the Java policy configuration matches the classname that you used in the Java source code. Then you must verify that the Java source code has been properly compiled and is included in the API proxy.

The policy configuration should look like this:

<JavaCallout name='Java-Nanotime'>
  <!-- the following class name must be defined in the referenced jar -->
  <ClassName>com.dinochiesa.edgecallouts.Nanotime</ClassName>
  <!-- the following JAR must have a class of the name specified above -->
  <ResourceURL>java://edge-java-callout-nanotime.jar</ResourceURL>
</JavaCallout>

One thing you said concerns me. you said "it runs fine from the command line." How did you "run" the Execute method? The programming model for callouts in Apigee Edge says that you must specify an Execute method. THAT is the thing that gets executed for each call. I don't believe there is a standard way to run the execute method from a JAR, from the command line. Unless you have rigged up a mocking library, then.... maybe you have some expectations that aren't quite right. Or maybe your understanding is not correct. It might be worth re-reading the very good docs on Java callouts.

If you have verified the class and jar as above, you need to consider dependencies. One common thing that catches people is that all of the classes required by your Jar must be available to Apigee Edge at runtime. So, if you have a Java class that depends on Google's Guava library, or FasterXml Jackson v2.5.0, then you need to include those JARs also in the api proxy bundle . If you do not include all of the appropriate JARs, then Apigee Edge will report an error like "Failed to load class". Essentially it is a class-not-found exception.

What is the missing class? The way to diagnose this is to wrap the body of your Execute method in a try..catch, and emit the exception message (and maybe the stacktrace) into a context variable so that you can see it in the Trace window for Apigee Edge. Like this:

package com.dinochiesa.edgecallouts;
import org.apache.commons.lang.exception.ExceptionUtils;
import com.apigee.flow.execution.ExecutionResult;
import com.apigee.flow.execution.spi.Execution;
import com.apigee.flow.message.MessageContext;
import com.apigee.flow.execution.ExecutionContext;
public class Nanotime implements Execution {
    private final static String varprefix= "nano_";
    private static String varName(String s) { return varprefix + s;}
    public Nanotime() { }
    public ExecutionResult execute (final MessageContext msgCtxt,
                                    final ExecutionContext execContext) {
        try {
            long nano = System.nanoTime();
            // set a variable.
            msgCtxt.setVariable(varName("time"), Long.toString(nano));
            return ExecutionResult.SUCCESS;
            
        }
        catch (java.lang.Exception exc1) {
            msgCtxt.setVariable(varName("error"), exc1.getMessage());
            msgCtxt.setVariable(varName("stacktrace"), ExceptionUtils.getStackTrace(exc1));
            // the following would go to stdout of Message processor
            // System.out.println("Exception:" + exc1.toString()); 
            // exc1.printStackTrace();
            return ExecutionResult.ABORT;
        }
    }
}

Note: the above relies on the ExceptionUtils class from Apache's commons-lang project. You need at least v2.6 of that. BUT, commons-lang is available to the Message Processor, so that is one JAR that you do not need to upload with your Java class.

The next logical question is, which JARS are available to Java callouts that run in Apigee Edge? And I don't think Apigee has ever documented that. But i have written a callout that checks its own classpath to see which JARs are available, and this is a partial list:

bcpkix-jdk15on-1.50.jar
bcprov-jdk15on-1.50.jar
commons-beanutils-1.8.3.jar
commons-beanutils-core-1.7.0.jar
commons-chain-1.2.jar
commons-cli-1.2.jar
commons-codec-1.7.jar
commons-collections-3.2.1.jar
commons-configuration-1.9.jar
commons-dbcp-1.4.jar
commons-digester-2.1.jar
commons-exec-1.3.jar
commons-fileupload-1.2.jar
commons-httpclient-3.1.jar
commons-io-2.0.1.jar
commons-lang-2.6.jar
commons-lang3-3.1.jar
commons-logging-1.1.1.jar
commons-math-2.2.jar
commons-math3-3.2.jar
commons-pool-1.5.4.jar
commons-validator-1.4.1.jar
guava-16.0.1.jar
guice-3.0.jar
jmustache-1.9.jar
json-patch-1.6.jar
json-path-0.8.0.jar
json-schema-core-1.2.1.jar
json-schema-validator-2.2.3.jar
xstream-1.4.7.jar<br>xalan-2.7.1.jar
xeger-1.0.jar

If your JAR depends on a jar that is not listed above, you should include the dependency in the list of JARs that you include in the api proxy bundle.