Using Java objects

You use the cfobject tag to create an instance of a Java object. You use other ColdFusion tags, such as cfset and cfoutput, or CFScript to invoke properties (attributes), and methods (operations) on the object.

Method 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. For more information on type conversion issues, see "Java and ColdFusion Data Type Conversions".

The examples in the following sections assume that the name attribute in the cfobject tag specified the value obj, and that the object has a property called Property, and methods called Method1, Method2, and Method3.

Note:   The cfdump tag displays an object's public methods and data.

Using basic object techniques

The following sections describe how to invoke Java objects.

Invoking objects

The cfobject tag makes Java objects available in ColdFusion. It can access any Java class that is available on the JVM classpath or in either of the following locations:

For example:

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

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

If you call a public non-static method on the object without first calling the init method, there ColdFusion makes an implicit call to the default constructor.

To call an object constructor explicitly, use the special ColdFusion init method with the appropriate arguments after you use the cfobject tag; for example:

<cfobject type="Java" class="MyClass" name="myObj">
<cfset ret=myObj.init(arg1, arg2)>

Note:   The init method is not a method of the object, but a ColdFusion identifier that calls the new function on the class constructor. So, if a Java object has an init method, a name conflict exists and you cannot call the object's init method.

To have persistent access to an object, you must use the init function, because it returns a reference to an instance of the object, and cfobject does not.

An object created using cfobject or returned by other objects is implicitly released at the end of the ColdFusion page execution.

Using properties

Use the following coding syntax to access properties if the object does either of the following actions:

To set a property:

<cfset obj.property = "somevalue">

To get a property:

<cfset value = obj.property>

Note:   ColdFusion does not require that property and method names be consistently capitalized. However, you should use the same case in ColdFusion as you do in Java to ensure consistency.

Calling methods

Object methods usually take zero or more arguments. Some methods return values, while others might not. Use the following techniques to call methods:

Note:   When you invoke a Java method, the type of the data being used is important. For more information see "Java and ColdFusion Data Type Conversions".

Calling JavaBean get and set methods

ColdFusion can automatically invoke getPropertyName() and setPropertyName(value) methods if a Java class conforms to the JavaBeans pattern. As a result, you can set or get the property by referencing it directly, without having to explicitly invoke a method.

For example, if the myFishTank class is a JavaBean, the following code returns the results of calling the getTotalFish() method on the myFish object:

<cfoutput>
  There are currently #myFish.TotalFish# fish in the tank.
</cfoutput>

The following example adds one guppy to a myFish object by implicitly calling the setGuppyCount(int number) method:

<cfset myFish.GuppyCount = myFish.GuppyCount + 1>

Note:   You can use the direct reference method to get or set values in some classes that have getProperty and setProperty methods but do not conform fully to the JavaBean pattern. However, you cannot use this technique for all classes that have getProperty and setProperty methods. For example, you cannot directly reference any of the following standard Java classes, or classes derived from them: Date, Boolean, Short, Integer, Long, Float, Double, Char, Byte, String, List, Array.

Calling nested objects

ColdFusion supports nested (scoped) object calls. For example, if an object method returns another object and you must invoke a property or method on that object, you can use the following syntax:

<cfset prop = myObj.X.Property>.

Similarly, you can use code such as the following CFScript line:

GetPageContext().include("hello.jsp?name=Bobby");

In this code, the ColdFusion GetPageContext function returns a Java PageContext object, and the line invokes the PageContext object's include method.

Creating and using a simple Java class

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 show how to use Java effectively in ColdFusion pages.

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 classpath:

public class Employee {
public String FirstName;
public String LastName;
private float Salary;
private int   JobGrade;

public void Employee() {
  FirstName ="";
  LastName ="";
  Salary   = 0.0f;
  JobGrade = 0;
}

public void Employee(String First, String Last) {
  FirstName = First;
  LastName = Last;
  Salary   = 0.0f;
  JobGrade = 0;
}

public void 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;
  }
  else if (Grade.equals("MANAGER")) {
    JobGrade = 2;
  }
  else if (Grade.equals("DEVELOPER")) {
    JobGrade = 1;
  }
}

public int GetJobGrade() {
  return JobGrade;
}

}

A 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 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 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>
Loads the Employee Java class and gives it an object name of emp.
<!--- <cfset emp.init()> --->
Does 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">
Sets the public fields in the emp object to your values.
<cfset firstname=emp.firstname>
<cfset lastname=emp.lastname>
Gets the field values back from emp object.
<cfoutput>
  Employee name is #firstname#
    #lastname#
</cfoutput>
Displays 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 ColdFusion 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()>

<cfoutput>
  Employee name is  #firstname# #lastname#<br> 
  Employee salary #DollarFormat(Salary)#<br>
  Employee Job Grade  #grade#
</cfoutput>

</body>
</html>

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

Java and ColdFusion Data Type Conversions

ColdFusion does not use explicit types for variables, while Java is strongly typed. However, ColdFusion data does use a number of underlying types to represent data.

Under most situations, when the method names are not ambiguous, ColdFusion can determine the data types that are required by a Java object, and often it can convert ColdFusion data to the required types. For example, ColdFusion text 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 that contains an integer value, ColdFusion 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 automatically matches Java types to ColdFusion types.

The following table lists how ColdFusion converts ColdFusion data values to Java data types when passing arguments. The left column represents the underlying ColdFusion representation of its data. The right column indicates the Java data types into which ColdFusion can automatically convert the data:
CFML
Java
Integer
short, int, long  (short and int might result in a loss of precision).
Real number
float double  (float might result in a loss of precision.
Boolean
boolean
Date-time
java.util.Date
String, including lists
String
short, int, long, float, double, java.util.Date, when a CFML string represents a number or date.
boolean, for strings with the value Yes, No, True, and False (case-insensitive).
Array
java.util.Vector (ColdFusion Arrays are internally represented using an instance of a java.util.Vector object.)
ColdFusion can also map a CFML array to any of the following when the CFML array contains consistent data of a type that can be converted to the Java array's data type: byte[], char[], boolean[], int[], long[], float[], double[], String[], or Object[]. When a CFML array contains data of different of types, the conversion to a simple array type might fail.
Structure
java.util.Map
Query object
java.util.Map
XML document object
Not supported.
ColdFusion component
Not applicable.

The following table lists how ColdFusion converts data returned by Java methods to ColdFusion data types:
Java
CFML
boolean/Boolean
Boolean
byte/Byte
String
char/Char
String
short/Short
Integer
int/Integer
Integer
long/Long
Integer
float/Float
Real Number
double/Double
Real Number
String
String
java.util.Date
Date-time
java.util.List
Comma-delimited list
byte[]
Array
char[]
Array
boolean[]
Array
String[]
Array
java.util.Vector
Array
java.util.Map
Structure

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 JVM resolves the specific method to use based on the parameters passed in the call and their types.

In the section "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 a string or as a number, so there is no way to know which method implementation to use. When 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 you are setting. You can specify the following Java data types: boolean, int, long, float, double, and String.

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

Handling Java exceptions

You handle Java exceptions just as you handle standard ColdFusion exceptions, with the cftry and cfcatch tags. You specify the name of the exception class in the cfcatch tag that handles the exception. For example, if a Java object throws an exception named myException, you specify myException in the cfcatch tag.

Note:   To catch any exception generated by a Java object, specify java.lang.Exception for the cfcatch type attribute. To catch any Throwable errors, specify java.lang.Throwable in the cfcatch tag type attribute.

The following sections show an example of throwing and handling a Java exception.

For more information on exception handling in ColdFusion, see Chapter 14, "Handling Errors".

Example: exception-throwing class

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

The myException class has the following code. It throws an exception with a message that is passed to it, or if no argument is passed, it throws a canned exception.

//class myException
public class myException extends Exception 
{
  public myException(String msg) {
    super(msg);
  }
  public myException() {
    super("Error Message from myException");
  }
}

The testException class contains one method, doException, which throws a myException error with an error message, as follows:

public class testException {
  public testException () 
  {
  }
  public void doException() throws myException {
        throw new myException("Throwing an exception from testException class");
    }
}

Example: CFML Java exception handling code

The following CFML code calls the testException class doException method. The cfcatch block handles the resulting exception.

<cfobject action=create type=java class=testException name=Obj>
<cftry>
  <cfset Obj.doException() >
  <cfcatch type="myException">
    <cfoutput>
      <br>The exception message is: #cfcatch.Message#<br>
    </cfoutput> 
  </cfcatch>
</cftry>

Examples: using Java with CFML

The following sections show several examples of using Java objects in CFML. They include examples of using a custom Java class, a standard Java API class in a user-defined function, a JavaBean, and an Enterprise JavaBean (EJB).

Using a Java API in a UDF

The following example of a user defined function (UDF) is functionally identical to the GetHostAddress function from the NetLib library of UDFs from the Common Function Library Project, http://www.cflib.org. It uses the InetAddress class from the standard Java 2 java.net package to get the Internet address of a specified host:

function GetHostAddress(host) {
   // Define the function local variables.
   var iaddrClass="";
   var address="";
   
   // Initialize the Java class.
   iaddrClass=CreateObject("java", "java.net.InetAddress");

   // Get the address object.
   address=iaddrClass.getByName(host);

   // Return the address
   return address.getHostAddress();
}

Using an EJB

ColdFusion can use EJBs that are served by JRun 4.0 servers. The JRun Server Jrun.jar file must have the same version as the Jrun.jar file in ColdFusion.

To call an EJB, you use cfobject type="Java" to create and call the appropriate objects. Before you can use an EJB you must do the following:

  1. Have a properly deployed EJB running on a J2EE server. The bean must be registered with the JNDI server.
  2. Have the following information:
  3. Install the EJB home and component interface compiled classes on your ColdFusion web server, either as class files in the web_root/WEB-INF/classes directory or packaged in a JAR file the web_root/WEB-INF/lib directory.

Note:   To use an EJB served by a JRUN server, your ColdFusion installation and the JRun server that hosts the EJB must have the same version of the jrun.jar file (located in cf_root\runtime\lib directory in ColdFusion).

While the specific steps for using an EJB depend on the EJB server and on the EJB itself, they generally correspond to the following order:

To use an EJB:

  1. Use the cfobject tag to create an object of the JNDI naming context class (javax.naming.Context). You will use fields from this class to define the information that you use to locate the EJB. Because you only use fields, you do not initialize the object.
  2. Use the cfobject tag to create a java.util.Properties class object that will contain the context object properties.
  3. Call the init method to initialize the Properties object.
  4. Set the Properties object to contain the properties that are required to create an initial JNDI naming context. These include the INITIAL_CONTEXT_FACTORY and PROVIDER_URL properties. You might also need to provide SECURITY_PRINCIPAL and SECURITY_CREDENTIALS values required for secure access to the naming context. For more information on these properties, see the JNDI documentation.
  5. Use the cfobject tag to create the JNDI InitialContext (javax.naming. InitialContext) object.
  6. Call the init method for the InitialContext object with the Properties object values to initialize the object.
  7. Call the InitialContextext object's lookup method to get a reference to the home interface for the bean that you want. Specify the JNDI name of the bean as the lookup argument.
  8. Call the create method of the bean's home object to create a new instance of the bean. If you are using Entity beans, you typically use a finder method instead. A finder method locates one or more existing entity beans.
  9. Now you can use the bean's methods as required by your application.
  10. When finished, call the context object's close method to close the object.

The following code shows this process using a simple Java Entity bean on a JRun 4.0 server. It calls the bean's getMessage method to obtain a message.

<html>
<head>
  <title>cfobject Test</title>
</head>

<body>
<H1>cfobject Test</H1>
<!--- Create the Context object to get at the static fields. --->
<CFOBJECT 
  action=create 
  name=ctx 
  type="JAVA" 
  class="javax.naming.Context">

<!--- Create the Properties object and call an explicit constructor--->
<CFOBJECT 
  action=create 
  name=prop 
  type="JAVA" 
  class="java.util.Properties">

<!--- Call the init method (provided by cfobject)
      to invoke the Properties object constructor. --->
<cfset prop.init()>

<!--- Specify the properties These are required for a remote server only --->
<cfset prop.put(ctx.INITIAL_CONTEXT_FACTORY, "jrun.naming.JRunContextFactory")>
<cfset prop.put(ctx.PROVIDER_URL, "localhost:2908")>
<!--- <cfset prop.put(ctx.SECURITY_PRINCIPAL, "admin")>
    <cfset prop.put(ctx.SECURITY_CREDENTIALS, "admin")>
 --->
<!--- Create the InitialContext  --->
<CFOBJECT 
  action=create 
  name=initContext 
  type="JAVA" 
  class="javax.naming.InitialContext">

<!--- Call the init method (provided through cfobject)
      to pass the properties to the InitialContext constructor. --->
<cfset initContext.init(prop)>

<!--- Get reference to home object. --->
<cfset home = initContext.lookup("SimpleBean")>

<!--- Create new instance of entity bean.
      (hard-wired account number). Alternatively,
      you would use a find method to locate an
      existing entity bean. --->
<cfset mySimple = home.create()>

<!--- Call a method in the entity bean. --->
<cfset myMessage = mySimple.getMessage()>

<cfoutput>
  #myMessage#<br>
</cfoutput>

<!--- Close the context. --->
<cfset initContext.close()>

</body>
</html>

Using a custom Java class

The following code provides a more complex custom class than in the example "Creating and using a simple Java class". 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 ColdFusion page

The following useExample.cfm page uses the Example class to manipulate numbers, strings, Booleans, and Example objects. The JavaCast CFML function ensures 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>

Comments