Working with Java String objects in integration scripts

This article is intended to help anyone working with Java scripts while modifying or troubleshooting integration scripts. The Integration Agent's JavaScript interpreter (Rhino) allows Java objects to be imported in integration scripts. This can add versatility to your integration, but can also cause some scripts to become error-prone.

Specifically, Java String objects have caused several reported script defects. This article will describe the differences between JavaScript strings and Java String objects, and will recommend techniques for avoiding some of the problems that can result when using Java String objects in integration scripts.

Java String objects versus JavaScript strings

This article will refer to Java String objects (with an uppercase "S") and JavaScript strings (with the "s" in lowercase.) This is purely for clarity, considering the similarity between "Java" and "JavaScript": like the names of the languages, JavaScript strings and objects are superficially very similar to, and easily confused with, their equivalents in Java, which can cause important differences to be overlooked. Hopefully, the lowercase and uppercase "S" will make it easier to distinguish between them.

Each language has an object class called "String" (with an uppercase "S",) but we will try to use the term "Java String object" consistently to distinguish between the Java and JavaScript string entities.

Java String objects and JavaScript strings have many similarities and a few important differences, including:

  • Their class names: "java.lang.String" in Java, and "String" in JavaScript.
  • Some of their methods (which are the functions that determine what an object can do, in object-oriented programming.) For example, Java String objects have a "replaceAll()" method, and JavaScript strings do not.

Because of the differences in methods between JavaScript strings and Java String objects, integration scripts are prone to errors like the following when Java String objects are used in integrations:

Exception - name: [InternalError], message [The choice of Java method java.lang.String.replace matching JavaScript argument types (function,string) is ambiguous; candidate methods are:
class java.lang.String replace(java.lang.CharSequence,java.lang.CharSequence)
class java.lang.String replace(char,char)]

The reason for this particular error is that the integration script has called a Java String object's "replace" method with an argument that it cannot accept. Specifically, a regular expression was passed as an argument. The JavaScript string's "replace" method accepts regular expressions, but the Java String object's "replace()" method does not.

Java String objects have a "replace()" method that accepts only string arguments. For example, the following code would execute without error:

var oldString = new java.lang.String("Working with strings is easy");
var newString = oldString.replace("easy", "hard");

The replace operation would fail if it were written to use a regular expression instead of a string argument, though:

var oldString = new java.lang.String("Working with strings is easy");
var newString = oldString.replace(/e[a-z]+y/g, "hard");

Based on this information, we can infer that the above error message resulted from a script that was written to work with JavaScript strings, but failed when it encountered a Java String object.

Where Java String objects come from

Integration scripts are written in JavaScript, which is distinct from the Java language. In the simplest integration scripts there will be no Java objects.

However, JavaScript has limitations in terms of the functionality that it offers. For example, JavaScript offers very little capability for working with dates and times. Fortunately, the Rhino JavaScript interpreter allows Java classes to be imported, so if we want to work with dates and times, for example, we can import Java classes that will allow us to manipulate and compare timestamps much more easily than we could do in pure JavaScript.

Since many of these Java functions provide output in string format (as opposed to integers, etc,) we shouldn't be surprised to find that the imported Java classes introduce Java String objects into our integrations. However, while we might not expect these Java String objects to replace existing JavaScript string literals, this is exactly what can happen. The problem is complicated by the fact that JavaScript is not a strongly typed language (in fact it is untyped.)

This means that the following chain of events can occur in a JavaScript code fragment:

var jsString = "this is a JavaScript string literal.";  // create a new JavaScript string
jsString = someJavaFunction();  // send the output from imported Java code to the JavaScript string
jsString = jsString.replace(/a[a-z]+c/g, "def");  // expect an error here because jsString has been replaced by a Java String object

In the above code fragment, a JavaScript string has been replaced by a Java String object. Any JavaScript-specific functionality will no longer be available from this object.

In a strongly typed language, we would expect an error if we tried to assign a value of the wrong type to a variable, but in JavaScript this is tolerated.

An example of a JavaScript function that is broken by Java String objects is formatStringForE4X(), which is common in Integration scripts:

  formatStringForE4X: function(string)
  {
    string = string.replace(/<\?(.*?)\?>/g,''); // remove XML processing instructions
    return string;
  }

When implemented in this way, the function will throw a runtime error whenever a Java String object is sent to it (because the function attempts to send a regex to the String object's replace() method.)

To prevent these runtime errors, it is best to replace Java String objects with JavaScript strings wherever feasible.

Converting Java Strings to JavaScript strings

As noted above, it's easy to inadvertently create a Java String object (i.e., when a JavaScript String is expected,) or to convert a JavaScript string to a Java String object without meaning to. Converting back to JavaScript is simple, but not intuitive.

To create a new JavaScript string (as opposed to a Java String object,) use single- or double quotes to define an initial value (empty or otherwise) when declaring the variable, or use the "new String()" syntax:

var jsString1 = '';
var jsString1 = "";
var jsString3 = "I am a JavaScript string literal";
var jsString4 = new String("I am a JavaScript String object");

Confusingly, a variable created with the "new String" syntax will be identified as an "object" by the typeof operator. This makes it difficult to distinguish between a Java String object and a JavaScript String object (since the typeof operator identifies them both as "object". JavaScript string literals, on the other hand, will be identified as "string" by the typeof operator.

typeof jsString1;
(output:) string
typeof jsString3;
(output:) string
typeof jsString4;
(output:) object

More comprehensive information about String literals and String objects in JavaScript is here

To convert a Java String object to its JavaScript equivalent, concatenate the Java String object to an empty string:

var javaString = new java.lang.String("I am a Java object");
typeof javaString;
(output:) object
var jsString5 = "" + javaString;
typeof jsString5;
(output:) string

In the above example, a Java String object has been converted to a JavaScript string by concatenating it to an empty JavaScript string.

Best practice

Converting a potential Java String object to a JavaScript string (ie, by creating a new JavaScript string and then concatenating the Java object to it) has proven to be a reliable way of handling strings of unknown origin. This mechanism has been used successfully with the formatStringForE4X() function mentioned earlier:

  formatStringForE4X: function(string)
  {
    string = "" + string;  // Replace the string with one that is known to be a JavaScript object
    string = string.replace(/<\?(.*?)\?>/g,''); // remove XML processing instructions
    return string;
  }

In general, whenever working with Java String objects (or when receiving data from imported Java classes,) convert the string data to a JavaScript string (as described above) as soon as possible.

 

Information created and supplied by Jeremy Brown.

xMatters reference: DTN-5482

Have more questions? Submit a request

0 Comments

Please sign in to leave a comment.
Powered by Zendesk