Calling Java Objects

The cfobject tag can call any Java class that is available on the class path specified on the ColdFusion Administrator JVM and Java Settings page. For example:

<cfobject type="Java" class="MyClass" name="myObj">

Although this tag loads the class, it does not create an instance object. Static methods and fields are accessible after the call to cfobject.

To call the constructors explicitly, use the init method with the appropriate arguments; for example:

<cfset ret=myObj.init(arg1, arg2)>

If you call a public method on the object without first calling the init method, the result is an implicit call to the default constructor.

Arguments and return values can be any valid Java type; for example, simple arrays and objects. ColdFusion does the appropriate conversions when strings are passed as arguments, but not when they are received as return values.

The following sections provide more details on calling Java objects in ColdFusion.

Getting Started with Java

Java is a strongly typed language, unlike ColdFusion, which does not enforce data types. As a result, there are some subtle considerations when calling Java methods. The following sections create and use a Java class to illustrate how to use Java effectively in ColdFusion pages.

Example: the Employee class

The Employee class has four data members: FirstName and LastName are public, and Salary and JobGrade are private. The Employee class has three overloaded constructors and a overloaded SetJobGrade method.

Save the following Java source code in the file Employee.java, compile it, and place the resulting Employee.class file in a directory that is specified in the class path.

public class Employee {


public String FirstName;

public String LastName;

private float Salary;

private int   JobGrade;



public Employee() {

  FirstName ="";

  LastName ="";

  Salary   = 0.0f;

  JobGrade = 0;

}



public Employee(String First, String Last) {

  FirstName = First;

  LastName = Last;

  Salary   = 0.0f;

  JobGrade = 0;

}



public Employee(String First, String Last, float salary, int grade) {

  FirstName = First;

  LastName = Last;

  Salary   = salary;

  JobGrade = grade;

}



public void SetSalary(float Dollars) {

   Salary = Dollars;

}



public float GetSalary() {

  return Salary;

}



public void SetJobGrade(int grade) {

  JobGrade = grade;

}



public void SetJobGrade(String Grade) {

  if (Grade.equals("CEO")) {

    JobGrade = 3;

  }

  if (Grade.equals("MANAGER")) {

    JobGrade = 2;

  }

  if (Grade.equals("DEVELOPER")) {

    JobGrade = 1;

  }

}



public int GetJobGrade() {

  return JobGrade;

}



}

Example: CFML page that uses the Employee class

Save the following text as JEmployee.cfm:

<html>

<body>

<cfobject action=create type=java class=Employee name=emp>

<!-- <cfset void = emp.init()> -->

<cfset emp.firstname="john">

<cfset emp.lastname="doe">

<cfset firstname=emp.firstname>

<cfset lastname=emp.lastname>

</body>



<cfoutput>

  Employee name is  #firstname# #lastname#

</cfoutput>

</html>

When you view the page in your browser, you should get the following output:

Employee name is john doe

Reviewing the code

The following table describes the CFML code and its function:
Code
Description

<cfobject action=create

  type=java class=Employee

  name=emp> 

Load an instance of the Employee Java class named emp.

<!--- <cfset void=emp.init()>

---> 

Do not call a constructor. ColdFusion invokes the default constructor when it first uses the class; in this case, when it processes the next line.

<cfset emp.firstname="john"> 

<cfset emp.lastname="doe"> 

Set the public fields in the emp object to your values.

<cfset firstname=emp.firstname> 

<cfset lastname=emp.lastname> 

Get the field values back from emp object.

<cfoutput> 

  Employee name is  #firstname#

    #lastname# 

</cfoutput> 

Display the retrieved values.

Java considerations

Keep the following points in mind when you write a ColdFusion page that uses a Java class object:

Using an alternate constructor

The following CFML page explicitly calls one of the alternate constructors for the Employee object:

<html>

<body>



<cfobject action=create type=java class=Employee name=emp>

<cfset emp.init("John", "Doe",100000.00, 10 )>

<cfset firstname=emp.firstname>

<cfset lastname=emp.lastname>

<cfset salary=emp.GetSalary()>

<cfset grade=emp.GetJobGrade()>

</body>



<cfoutput>

  Employee name is  #firstname# #lastname# 

  Employee salary and Job Grade #Salary# #grade#

</cfoutput>

</html>

In this example, the constructor takes four arguments; the first two are strings, and third is a float, and the fourth is an integer.

Java and Cold Fusion Data Type Conversions

Cold Fusion is a typeless scripting language (that is, it does not use explicit data types) while Java is strongly typed.

Under most situations, when the method names are not ambiguous, ColdFusion can determine the required types. For example, ColdFusion strings are implicitly converted to the Java String type. Similarly, if a Java object contains a doIt method that expects a parameter of type int, and CFML is issuing a doIt call with a CFML variable x, ColdFusion will converts the variable x to Java int type. However, ambiguous situations can result from Java method overloading, where a class has multiple implementations of the same method that differ only in their parameter types.

The following sections describe how ColdFusion handles the unambiguous situations, and how it provides you with the tools to handle ambiguous ones.

Default data type conversion

Whenever possible, ColdFusion matches Java types to ColdFusion types as listed in the following table. ColdFusion does not support direct conversion of Date/Time variables and structures.
CFML
Java type
Character
String
Numeric
Int/long/float/double (depending on JavaCast)
Boolean
Bool
Array Of Character
Array of String
Array Of Numeric
Array of Java (int/long/float/double)
The conversion rule depends on the Java Method Signature (JavaCast does not help).
Array Of Java Objects
Array of Java Objects

Resolving ambiguous data types with the JavaCast function

You can overload Java methods so a class can have several identically named methods. At runtime, the VM resolves the specific method to use based on the parameters passed in the call and their types.

In the section "Example: the Employee class", the Employee class has two implementations for the SetJobGrade method. One method takes a string variable, the other an integer. If you write code such as the following, which implementation to use is ambiguous:

<cfset  emp.SetJobGrade("1")>

The "1" could be interpreted as string or as number, so there is no way to know which method implementation to use. When a ColdFusion encounters such an ambiguity, it throws a user exception.

The ColdFusion JavaCast function helps you resolve such issues by specifying the Java type of a variable, as in the following line:

<cfset  emp.SetJobGrade(JavaCast("int", "1")>

The JavaCast function takes two parameters: a string representing the Java data and the variable whose type your are setting. You can specify the following Java data types: bool, int, long, float, double, and String.

For more information on the JavaCast function, see CFML Reference.

Exception Handling

Use the cftry and cfcatch tags to can catch exceptions thrown by Java objects. Use the CFML GetException function to retrieve the Java exception object. The following example demonstrates the GetException function.

Example: exception-throwing class

The following Java code defines the foo class that throws a sample exception. It also defines a fooException class that extends the Java built-in Exception class and includes a method for getting an error message.

public class foo {

  public foo() {

  }

  public void doException() throws fooException {

    throw new fooException("I am throwing a throw Exception ");

  }

}



Class fooException



public class fooException extends Exception {

  public String GetErrorMessage() {

    return "Error Message from fooException";

  }

}

Example: CFML Java exception handling code

The following CFML code calls the foo class doException method. The cfcatch block handles the resulting exception by calling the CFML GetException function to retrieve the Java exception object and then calling the object's GetErrorMessage method to get the error information.

<cfobject action=create type=java class=foo name=Obj>

<cftry>

  <cfset VOID = Obj.doException() >

  <cfcatch type="Any">

    <cfset exception=GetException(Obj)>

    <cfset message=exception.GetErrorMessage()>

    <cfoutput>

      <br>The exception message is: #message#<br>

    </cfoutput> 

  </cfcatch>

</cftry>

Reviewing the code

The following table describes the code and its function:
Code
Description

<cfobject action=create type=java 

class=foo name=Obj> 

Load an instance of the Java foo class named Obj.

<cftry> 

<cfset VOID = Obj.DoException() > 

Inside a cftry block. call the doException method of the Obj object. This method throws an exception of the fooException type.

<cfcatch type="Any"> 

Catch any exceptions and handle them in this block.

<cfset exception=GetException(Obj)> 

<cfset 

message=exception.GetERrorMessage()> 

Get the exception data by calling the CFML GetException function and passing it the Obj object. Set the message variable to the string returned by the exception object's GetErrorMessage method.

<cfoutput> 

  <br>The exception message is: 

     #message#<br> 

</cfoutput> 

Output the message string.

Note that after you call GetException, the exception object is just like any other Java component object, and you can call any methods on it.

The class loading mechanism

In ColdFusion prior to version 5, Java classes were loaded on demand and they were not unloaded until the server restarted. This is the way a typical Java application works and is appropriate for production systems. However, if you change a Java method implementation, you must shut down the server and restart it before ColdFusion can use the new class implementation.

In version 5, ColdFusion Server uses a custom class loader to load Java classes on the fly, similar to Java Servlet engines. This enables you to modify Java method implementations and use the new code from ColdFusion without restarting the server.

ColdFusion 5 introduces the concept of dynamic load path, a directory that you can specify on Cold Fusion Administrator JVM and Java Settings page. You deposit your Java class files in this directory when you update the class implementation. ColdFusion checks the class file time stamp when an object of the class is created. If ColdFusion detects a new class file, it loads the class from that directory.

To use this feature, make sure that the Java implementation classes that you modify are not in the general JVM class path. In addition, do not package the classes into jar files or zip files. In all other ways, ColdFusion Class loader follows Java conventions including those for package names and directory name mapping.

Suppose the directory "C:\classes" is the designated "hot" dynamic class path and you have a class com.Allaire.Employee. You put the Employee.class file in the following location:

C:\ classes\com\Allaire\Employee.class

The dynamic class-loading feature is meant for development uses, and incurs a slight performance penalty associated with checking time stamps during disk IO operations. For that reason, you do not use this feature in a production environment where there might be high volume of traffic.

To disable automatic class loading, put all classes in the normal Java class path. Classes located on the Java class path are loaded once per server lifetime and can only be reloaded by stopping and restarting ColdFusion Server.

A more complex Java example

The following code provides a more complete example of using Java with cfobject. The Example class manipulates integer, float, array, Boolean, and Example object types.

The Example class

The following Java code defines the Example class. The Java class Example has one public integer member, mPublicInt. Its constructor initializes mPublicInt to 0 or an integer argument. The class has the following public methods:
Method
Description
ReverseString
Reverses the order of a string.
ReverseStringArray
Reverses the order of elements in an array of strings.
Add
Overloaded: Adds and returns two integers or floats or adds the mPublicInt members of two Example class objects and returns an Example class object.
SumArray
Returns the sum of the elements in an integer array.
SumObjArray
Adds the values of the mPublicInt members of an array of Example class objects and returns an Example class object.
ReverseArray
Reverses the order of an array of integers.
Flip
Switches a boolean value.

public class Example {

  public   int      mPublicInt;



  public Example() {

      mPublicInt = 0;

  }



  public Example(int IntVal) {

      mPublicInt = IntVal;

  }



  public String ReverseString(String s) {

      StringBuffer buffer = new StringBuffer(s);

      return new String(buffer.reverse());

  }



  public String[] ReverseStringArray(String [] arr) {

    String[] ret = new String[arr.length];

    for (int i=0; i < arr.length; i++) {

      ret[arr.length-i-1]=arr[i];

    }

    return ret;

  }



  public int Add(int a, int b) {

      return (a+b);

  }



  public float Add(float a, float b) {

      return (a+b);

  }



  public Example Add(Example a, Example b) {

      return new Example(a.mPublicInt + b.mPublicInt);

  }



 static  public int SumArray(int[] arr) {

    int sum=0;

    for (int i=0; i < arr.length; i++) {

      sum += arr[i];

    }

    return sum;

  }



  static  public Example SumObjArray(Example[] arr) {

    Example sum= new Example();

    for (int i=0; i < arr.length; i++) {

      sum.mPublicInt += arr[i].mPublicInt;

    }

    return sum;

  }



  static public int[] ReverseArray(int[] arr) {

    int[] ret = new int[arr.length];

    for (int i=0; i < arr.length; i++) {

      ret[arr.length-i-1]=arr[i];

    }

    return ret;

  }





  static public boolean Flip(boolean val) {

      System.out.println("calling flipboolean");

      return val?false:true;

  }

}

The useExample CFML Page

The following useExample.cfm page uses the Example class to manipulate numbers, strings, Booleans, and Example objects. Note the use of the JavaCast CFML function to ensure that CFML variables convert into the appropriate Java data types.

<html>

<head>

  <title>CFOBJECT and Java Example</title>

</head>

<body>



<!--- Create a reference to an Example object --->

<cfobject action=create type=java class=Example name=obj>

<!--- Create the object and initialize its public member to 5 --->

<cfset x=obj.init(JavaCast("int",5))>



<!--- Create an array and populate it with string values,

    then use the Java object to reverse them. --->

<cfset myarray=ArrayNew(1)>

<cfset myarray[1]="First">

<cfset myarray[2]="Second">

<cfset myarray[3]="Third">

<cfset ra=obj.ReverseStringArray(myarray)>



<!--- Display the results --->

<cfoutput>

  <br>  

  original array element 1: #myarray[1]#<br>

  original array element 2: #myarray[2]#<br>

  original array element 3: #myarray[3]#<br>

  after reverse  element 1: #ra[1]#<br>

  after reverse  element 2: #ra[2]#<br>

  after reverse  element 3: #ra[3]#<br>

  <br>

</cfoutput>





<!--- Use the Java object to flip a Boolean value, reverse a string,

    add two integers, and add two float numbers --->

<cfset c=obj.Flip(true)>

<cfset StringVal=obj.ReverseString("This is a test")>

<cfset IntVal=obj.Add(JavaCast("int",20),JavaCast("int",30))>

<cfset FloatVal=obj.Add(JavaCast("float",2.56),JavaCast("float",3.51))>



<!--- Display the results --->

<cfoutput>

  <br>

  StringVal: #StringVal#<br>

  IntVal: #IntVal#<br>

  FloatVal: #FloatVal#<br>

  <br>

</cfoutput>





<!--- Create a two-element array, sum its values, 

    and reverse its elements --->

<cfset intarray=ArrayNew(1)>

<cfset intarray[1]=1>

<cfset intarray[2]=2>

<cfset IntVal=obj.sumarray(intarray)>

<cfset reversedarray=obj.ReverseArray(intarray)>



<!--- Display the results --->

<cfoutput>

  <br>

  IntVal1 :#IntVal#<br>

  array1: #reversedarray[1]#<br>

  array2: #reversedarray[2]#<br>

  <br>

</cfoutput><br>





<!--- Create a ColdFusion array containing two Example objects.

    Use the SumObjArray method to add the objects in the array

    Get the public member of the resulting object--->

<cfset oa=ArrayNew(1)>

<cfobject action=create type=java class=Example name=obj1>

<cfset VOID=obj1.init(JavaCast("int",5))>

<cfobject action=create type=java class=Example name=obj2>

<cfset VOID=obj2.init(JavaCast("int",10))>

<cfset oa[1] = obj1>

<cfset oa[2] = obj2>

<cfset result = obj.SumObjArray(oa)>

<cfset intval = result.mPublicInt>



<!--- Display the results --->

<cfoutput>

  <br>

  intval1: #intval#<br>

  <br>

</cfoutput><br>

</body>

</html>



Banner.Novgorod.Ru