
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
NoClassDefFoundError when running routine using an external library
I've been experimenting with all the different ways you can call a method from an external java library from within a Talend job. I was able to create a Routine that calls a method from the Apache Commons Lang library. As a test, I wanted to use the StringUtils.capitalize method to capitalize Strings in a variety of use cases. I figured a Routine would be most appropriate.
I added the Apache Commons Lang jar as a new library in the User Libraries screen. Then, I created a new Routine called ApacheStringUtils. Within it, I created a method called capitalize which called the StringUtils.capitalize method in the Apache Commons Lang library. The Routine looks like this:
package routines;
import org.apache.commons.lang3.StringUtils;
public class ApacheStringUtils {
/**
* capitalize: returns a String with a capitalized first character
*
*
* {talendTypes} String
*
* {Category} User Defined
*
* {param} string str: The string needing to be capitalized.
*/
public static String capitalize(String str) {
return StringUtils.capitalize(str);
}
/**
* uncapitalize: returns a String with an uncapitalized first character
*
*
* {talendTypes} String
*
* {Category} User Defined
*
* {param} string str: The string needing to be uncapitalized.
*/
public static String uncapitalize(String str) {
return StringUtils.uncapitalize(str);
}
}
This Routine showed no errors.
To test, I successfully ran the Routine in a tJava component with the following code:
System.out.println(ApacheStringUtils.capitalize("word"));
This job printed out "Word" as expected.
However, when I tried to use this same routine in a tMap expression, it failed due to the following NoClassDefFoundError exception:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtils
at routines.ApacheStringUtils.uncapitalize(ApacheStringUtils.java:33)
at test_talend.manipulatecsvdatatest_0_1.ManipulateCSVDataTest.tFileInputDelimited_1Process(ManipulateCSVDataTest.java:2242)
at test_talend.manipulatecsvdatatest_0_1.ManipulateCSVDataTest.runJobInTOS(ManipulateCSVDataTest.java:2846)
at test_talend.manipulatecsvdatatest_0_1.ManipulateCSVDataTest.main(ManipulateCSVDataTest.java:2680)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang3.StringUtils
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 4 more
This didn't make much sense to me, as it was running successfully in a tJava component. Why not here? When I pressed Ctrl+Space when filling in my expression, I was even able to see my ApacheStringUtils methods. In fact, the methods from the imported library's StringUtils class showed up as well. I tried using those directly, but received an error that those methods were "undefined for type StringUtils."
So, my question is: Why can I access an imported library via a routine in a tJava component but not a tMap expression?

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I added the Apache Commons Lang jar as a new library in the User Libraries screen. Then, I created a new Routine called ApacheStringUtils
I don't understand where do you put the user library, however, please follows the steps to add external libraries:
create your custom routine first, and then right click on it and select 'Edit Routine Libraries' item to add your user libraries.
Regards
Shong

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I tried running the job once more and received the same NoClassDefFoundError as before.
I'd like to point out once more that the capitalize method in the routine works fine when called from a tJava component. When I try to use it in a tMap component, however, I get the NoClassDefFoundError exception. Any other ideas on what might be wrong?

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
However, I still do not need to do this when calling my routine from a tJava component. I don't know why this is the case - I thought defining a routine and specifying the library required by the Routine meant that I wouldn't need to load the required library in each job the Routine is called from. It's definitely inconvenient for others who wish to use my Routine since they likely won't be aware of the required library when using it. Their job will fail and they will need to look at the code to understand which library it needs. This would especially be a hassle for non-developers who wish to use a custom Routine but don't know much about Java and library dependencies!
I feel as though I'm not doing something correctly, so I will leave as unresolved until I receive an answer.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The code should work both on tMap and tJava component if the library is loaded correctly. I have downloaded the external library commons-lang3-3.1.jar from internet and tested your code, it works on tJava. I am using version 6.1.1. Which version are you using?
Regards
Shong

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am also using 6.1.1. Could you share with me what steps you took to import the Apache commons library such that it will work in the tMap component?
