Forum Discussion

cmurray's avatar
cmurray
New Contributor
5 years ago
Solved

Script Snap Error: "[object JavaPackage] is not a Java class in nashorn:mozilla_compat.js"

I have a script snap that I’m using to do some weird data manipulation to amalgamate 3-hourly data and 1-hourly data into a consistent 1-hourly format. Here is my script, I’m using javascript code:

// Ensure compatibility with both JDK 7 and 8 JSR-223 Script Engines
try { load("nashorn:mozilla_compat.js"); } catch (e) { }

// Import the interface required by the Script snap.
importPackage(com.snaplogic.scripting.language);

// Import the serializable Java type we'll use for the output data.
importClass(java.util.Array);

/**
 * Create an object that implements the methods defined by the "ScriptHook"
 * interface.  We'll be passing this object to the constructor for the
 * ScriptHook interface.
 */
var impl = {
    /*
     * These variables (input, output, error, log) are defined by the
     * ExecuteScript snap when evaluating this script.
     */
    input: input,
    output: output,
    error: error,
    log: log,

    /**
     * The "execute()" method is called once when the pipeline is started
     * and allowed to process its inputs or just send data to its outputs.
     *
     * Exceptions are automatically caught and sent to the error view.
     */
    execute: function () {
        this.log.info("Executing Transform Script");
        while (this.input.hasNext()) {
            try {
                // Read the next input document, store it a new LinkedHashMap, and write this as an output document.
                // We must use a serializable Java type liked LinkedHashMap for each output instead of a native
                // JavaScript object so that downstream Snaps like Copy can process it correctly.
                var inDoc = this.input.next();
                var outDoc = new Array();

                var earliestTime = new Date(inDoc.original.start_date);
                var latestTime = new Date(inDoc.original.end_date);

                var forecasts = [];
                for (var i = 0; i < inDoc.entity.forecasts.arrayLength; i++) {
                    var forecast = inDoc.entity.forecasts[i];
                    forecast.validFromDate = new Date(forecast.validFrom);
                    forecast.validUntilDate = new Date(forecast.validUntil);
                    forecasts.push(forecast);
                }

                var checkingTime = earliestTime;
                do {
                    var outputObj = {
                        weatherDate: checkingTime,
                        weatherData: {}
                    };

                    var validPt0s = {};
                    var validPt1h = {};
                    var validPt3h = {};

                    for (var i = 0; i < forecasts.arrayLength; i++) {
                        var forecast = forcasts[i];
                        if (forecast.validFromDate <= checkingTime && forecast.validUntilDate >= checkingTime) {
                            // 1) get the first valid PT0S result
                            if (forecast.validPeriod === "PT0S" && !validPt0s) {
                                validPt0s = forecast;
                                outputObj.weatherData.airTemperatureInCelsius = validPt0s.airTemperatureInCelsius;
                                continue;
                            }
                            // 2) get the first valid PT1H result
                            if (forecast.validPeriod === "PT1H" && !validPt1h) {
                                validPt1h = forecast;
                                outputObj.weatherData.precipitationAmountInMillimeter = validPt1h.precipitationAmountInMillimeter;
                                outputObj.weatherData.netRadiationInJoulePerCentimeterSquare = validPt1h.netRadiationInJoulePerCentimeterSquare;
                                continue;
                            }
                            // 3) get the first valid PT3H result
                            if (forecast.validPeriod === "PT3H" && !validPt3h) {
                                validPt3h = forecast;
                                outputObj.weatherData.averageWindSpeedInKnots = validPt3h.averageWindSpeedInKnots;
                                continue;
                            }
                        }
                    }

                    outDoc.push(outputObj);
                    checkingTime.setMinutes(checkingTime.getMinutes() + 60);
                }
                while (checkingTime <= latestTime)

                this.output.write(inDoc, outDoc);
            }
            catch (err) {
                var errDoc = new LinkedHashMap();
                errDoc.put("error", err);
                this.log.error(err);
                this.error.write(errDoc);
            }
        }
        this.log.info("Script executed");
    },

    /**
     * The "cleanup()" method is called after the snap has exited the execute() method
     */
    cleanup: function () {
        this.log.info("Cleaning up")
    }
};

/**
 * The Script Snap will look for a ScriptHook object in the "hook"
 * variable.  The snap will then call the hook's "execute" method.
 */
var hook = new com.snaplogic.scripting.language.ScriptHook(impl);

The error I’m seeing is:

Failure: Cannot evaluate Script file: <WHOLE SCRIPT HERE>, Reason: TypeError: [object JavaPackage] is not a Java class in nashorn:mozilla_compat.js at line number 375 at column number 16, Resolution: Please fix the script file error at line: 375 column: 16

Since the error is pointing somewhere other than my code, is there something that needs to be installed on our own workers? Is this just a misleading error and there is something wrong with my script? I used the boilerplate code as a template so am pretty sure that nashorn:mozilla_compat.js is the right thing to use.

Edit: Here is some input json you should be able to use to reproduce.

[
    {
        "entity": {
            "forecasts": [
                {
                    "validFrom": "2021-03-01T00:00:00Z",
                    "validUntil": "2021-03-01T00:00:00Z",
                    "validPeriod": "PT0S",
                    "airTemperatureInCelsius": 2.0
                },
                {
                    "validFrom": "2021-02-28T23:00:00Z",
                    "validUntil": "2021-03-01T00:00:00Z",
                    "validPeriod": "PT1H",
                    "precipitationAmountInMillimeter": 0.0,
                    "netRadiationInJoulePerCentimeterSquare": -9.8
                },
                {
                    "validFrom": "2021-02-28T21:00:00Z",
                    "validUntil": "2021-03-01T00:00:00Z",
                    "validPeriod": "PT3H",
                    "averageWindSpeedInKnots": 5.1
                },
                {
                    "validFrom": "2021-03-01T01:00:00Z",
                    "validUntil": "2021-03-01T01:00:00Z",
                    "validPeriod": "PT0S",
                    "airTemperatureInCelsius": 1.7
                },
                {
                    "validFrom": "2021-03-01T00:00:00Z",
                    "validUntil": "2021-03-01T01:00:00Z",
                    "validPeriod": "PT1H",
                    "precipitationAmountInMillimeter": 0.0,
                    "netRadiationInJoulePerCentimeterSquare": -7.1
                }
            ]
        },
        "original": {
            "start_date": "2021-03-01T00:00:00.000Z",
            "end_date": "2021-03-01T01:00:00.000Z"
        }
    }
]
  • Hello deeps,

    I'm not sure of how exactly you want your csv to be structured, but you can join the groups array to a string using .join() function in a Mapper Snap, and then you will have a flat structure that you can format as CSV.

     

    Please refer to the attached pipeline, and let me know if this helps you.

    Regards,

    Aleksandar.

1 Reply

    • kmiesse's avatar
      kmiesse
      Contributor

      I have it set to Reuse executions and a Pool size of 10.

  • tstack's avatar
    tstack
    Former Employee

    This sounds like a bug, the snap should not be failing like this. We’re going to take a look at it.

    How are you keeping the pipeline running continuously? The safest approach would be to have the snap that is keeping the pipeline alive finish after some amount of time and then start up another execution.

    • kmiesse's avatar
      kmiesse
      Contributor

      The pipeline has a continuous JMS listener that keeps it executing. Its on a scheduled task so that if it happens to stop it starts up again right away. I can’t set the pipeline or task to stop after a certain period of time, correct? I would have to create another pipeline to monitor other pipeline executions, correct?

      • tstack's avatar
        tstack
        Former Employee

        Ah, I was hoping the JMSConsumer had a timeout. It does have a ‘Control Destination’ that I think you can use to stop it.

        The ability to stop a scheduled task after a period of time was added in the 4.10 release (see the tasks page). Be aware that stopping a pipeline is a pretty harsh operation, any snaps that are actively working will be interrupted and you might lose data.