Unable To Initialize/Use Custom Jar

I’m trying to use opencsv.jar but I get the error message below.

— Error Message —
No matching Constructor for au.com.bytecode.opencsv.CSVReader(java.io.InputStreamReader, string, string) found

I’ve copied the opencsv.jar to /opt/lucee/tomcat/lucee-server/context/lib and I can see from Lucee Admin that opencsv is “active”.

The code I’m using is as shown below.
---- CF Code —









<cfif IsDefined (“Server.Railo”) AND IsNumeric(Arguments.TextDelimiter)>
<cfset Arguments.TextDelimiter = Evaluate(“chr(#Arguments.TextDelimiter#)”)>

<cfif IsDefined (“Server.Railo”) AND IsNumeric(Arguments.TextQualifier)>
<cfset Arguments.TextQualifier = Evaluate(“chr(#Arguments.TextQualifier#)”)>


// Initialize FileInputStream
InputStream = createobject(“java”,“java.io.FileInputStream”);
InputStream.init(arguments.CSVFilePath);

// Initialize InputStreamReader
objInputReader = createobject(“java”,“java.io.InputStreamReader”);
objInputReader.init(InputStream, arguments.FileEncoding);

// Initialize CSVReader
objCSVReader = createObject(“java”,“au.com.bytecode.opencsv.CSVReader”);
objCSVReader.init(objInputReader, arguments.TextDelimiter, arguments.TextQualifier);
aData = objCSVReader.readAll();

return aData;

I’m able to run the same code without any issues on another server running Lucee 5.2.6.60, Tomcat 8.5.40 and Java 1.8.0_161. Did something change with Lucee 5.3.5.XX? Am I supposed to call the Jar differently?

Also, I tried to use the latest version of OpenCSV (opencsv-5.1.jar) as well. Copied it to the same /opt/lucee/tomcat/lucee-server/context/lib/. However, on Lucee Admin, I see the OpenCSV 5.1 is “loaded” rather than “active”. Then, when I instantiate <cfset MyC = CreateObject(“java”,“com.opencsv”)>, I get the error message below:

— Error Message With OpenCSV-5.1 —
cannot load class through its string name, because no definition for the class with the specified name [com.opencsv] could be found caused by (java.lang.ClassNotFoundException:com.opencsv;java.lang.ClassNotFoundException:com.opencsv not found by lucee.core [46];java.lang.ClassNotFoundException:com.opencsv;)

Thanks for your help!

Charles Tang

Don’t forget to tell us about your stack!

OS: Centos 7.7.1908
Java Version: 1.8.0_161
Tomcat Version: 9.0.31
Lucee Version: 5.3.5.92

Which version of openCsv were you using before you tried the latest?

With version 5.1.0, CreateObject("java","com.opencsv") will give you a ClassNotFoundException because that’s just the package name.

But I’ve tried various ways (jar, bundle, JavaLoader) of loading the com.opencsv.CSVReader class according to the docs and I can’t get it to work either. Keeps complaining about a missing org/apache/commons/lang3/ObjectUtils class.

There certainly have been some changes to java class loading in recent Lucee versions which have caused issues.

If you need a quick workaround for importing CSVs, you’ll find a ready-made csvToQuery() method in the Lucee Spreadsheet library which uses Apache Commons CSV.

Hi, Julian. Thanks for the tip on the Lucee Spreadsheet library. Was so used to using OpenCSV that I totally overlooked that :-). I’ll change my code to use that instead. Thanks a lot.

Saying that, though, I’d still like to find a way to reliably load/use custom JARs with the new Lucee versions since I need it for other integrations. For OpenCSV, I’m using version 3.1 successfully on an older version of Lucee 5.2.6.60. The same code and same OpenCSV v3.1 doesn’t work on Lucee 5.3.5.92.

So, any insights in that would help greatly!

Thank you very much.

Charles Tang

In my experience the most reliable and flexible way of using custom JARs is still (after all these years, and despite all the promises) Mark Mandel’s JavaLoader. You just pass it an array of jar paths and it will load any class it can find without clashing with existing classes, and without needing engine restarts for changes.

I was able to get openCsv 5.1.0 working by loading the apache.commons.lang3 dependency as follows:

File structure

javaloader/
commons-lang3-3.9.jar
index.cfm
opencsv-5.1.jar

index.cfm

jarPaths  = DirectoryList( ExpandPath( "." ) );// jars are in the same folder as the script
param server.openCsvLoader = New javaloader.JavaLoader( jarPaths  );//only instantiate the loader once to avoid memory leaks
csvReader = server.openCsvLoader.create( "com.opencsv.CSVReader" );
filepath = "[pathToMy].csv";
try{
	file = CreateObject( "java", "java.io.FileInputStream" ).init( JavaCast( "string", filepath ) );
	fileReader = CreateObject( "java", "java.io.InputStreamReader" ).init( file ); // create a reader for this file
	csvReader.init( fileReader );
	dump( csvReader.readAll() );
}
finally{
	file.close();// make sure the input stream is closed
}

You can do it in this dynamic way without JavaLoader and without needing to add jars to the server’s class path, using CreateObject:

jarPaths = ExpandPath( "." );
csvReader = CreateObject( "java", "com.opencsv.CSVReader", jarPaths );
filepath = "[pathToMy].csv";
try{
	file = CreateObject( "java", "java.io.FileInputStream" ).init( JavaCast( "string", filepath ) );
	fileReader = CreateObject( "java", "java.io.InputStreamReader" ).init( file );
	csvReader.init( fileReader );
	dump( csvReader.readAll() );
}
finally{
	file.close();
}

But if different versions of any of the jars have already been loaded by Lucee, you may run into class clashes (i.e. confusion about which classes to use). Also, once loaded, you can’t reload the jars without restarting Lucee.

It is now theoretically possible to do safe, dynamic loading using Lucee’s OSGi functionality, and ideally I’d be using this exclusively instead of JavaLoader. But so far I’ve had mixed results: works with some libraries and not others. OpenCsv does appear to be OSGi friendly, but I couldn’t get it to work using Lucee’s OSGi tools.

SUPER! Thanks a lot for the pointer, Julian. I’ll use Javaloader for now and experiment with OSGi.

Thanks again!

Charles Tang