wirebox-1.6 - Wirebox and Javaloader mapping

Hey everyone, a question on mapping a java library using wirebox:

I am currently doing the following to use google’s libphonenumber library (http://code.google.com/p/libphonenumber/)

`
component displayname=“phoneValidation” hint=“Phone Validation Functions” {

property name=“javaloader” inject=“coldbox:plugin:JavaLoader” scope=“instance”;

public struct function splitPhoneNumber(required string phoneNumber) {

var phoneUtil = instance.javaLoader.create(“com.google.i18n.phonenumbers.PhoneNumberUtil”).getInstance();
var countryCode = phoneUtil.parse(arguments.phoneNumber,“US”).getCountryCode();
var nationalNumber = phoneUtil.parse(arguments.phoneNumber,“US”).getNationalNumber();
var data = {
countryCode = countryCode,
number = nationalNumber,
lastUpdated = now(),
status = “OK”
};
return data;

}

}

`

I want to use a mapping in wirebox.cfc, something like this:

`
map(“jPhoneUtil”).toJava(“javaLoader:com.google.i18n.phonenumbers.PhoneNumberUtil”).asSingleton();

`

But when I add the following property to my cfc:

`
property name=“jPhoneUtil” inject=“id:jPhoneUtil” scope=“instance”;

`

I get the following error:

Error Type: Object : [N/A]
Error Messages: Object Instantiation Exception.
Class not found: javaLoader:com.google.i18n.phonenumbers.PhoneNumberUtil

Note that I DONT get that error if the mapping is in wirebox.cfc and not used, ONLY once I have added the property to my cfc.

Any ideas would be greatly appreciated!

Ken

Hi Ken,

At what point are you adding the path to your jar to the class path?

In other words, when are you calling JavaLoader.appendPaths(“path/to/libphonenumber.jar”)?

JavaLoader can only instantiate classes of jars that have been loaded.

Kind regards,
Tom

Also not really sure if what you are trying is even possible…

toJava(path) Maps a name to a Java class that can be instantiated via createObject(“java”)

javaLoader:com.google.i18n.phonenumbers.PhoneNumbersUtil would never be able to be instantiated by createObject() as native coldfusion does not know about JavaLoader… Not sure about that at all, but it is my guess.

property name=“jPhoneUtil” inject=“javaLoader:com.google.i18n.phonenumbers.PhoneNumbersUtil” scope=“instance”; would work (if path was loaded), but it wouldn’t be a singleton.

I think you would need to create a singleton provider component that returns an instance of PhoneNumbersUtil and make sure it always returns the same instance.

If that makes sense?

Cheers,
Tom

Thanks Tom,

I’m doing almost exactly what you mentioned, just wondering if there was a more reusable way.

And btw, you asked at what point I add the jar to the class path, I am defining it in coldbox.cfc, the setting is:

`
javaloader_libpath = “~absolutepath~\includes\java”

`

Ken

Hi Ken,

Aha yes that does make sense.

I get the feeling that javaLoader:com.google.i18n.phonenumbers.PhoneNumbersUtil is written in java as a singleton since getInstance() does smell like the java singleton pattern.
So your provider could be as simple as:

/*

  • My PhoneNumbersUtil provider
  • model.providers.PhoneNumbersUtil (or whatever path)
    */
    component {
    property name=“jPhoneUtil” inject=“javaLoader:com.google.i18n.phonenumbers.PhoneNumbersUtil” scope=“instance”;

function init() {
return instance.jPhoneUtil.getInstance();
}
}

in wirebox put:

map(“jPhoneUtil”).to(“model.providers.PhoneNumbersUtil”).asSingleton();

And inside other model components you can now use:

property name=“jPhoneUtil” inject=“id:jPhoneUtil” scope=“instance”;

It is a small trade off compared to wiring your java component straight into wirebox but when refactoring you would still only need to change your code in one location: your provider.

Haven’t done any tests on this so could be wrong, but it seems logical.

Let me know if it helps.

Cheers,
Tom

Tom, don’t forget that the scope=“singleton” will also work on the property as well. Which should work if the class is in the javaloaders known paths. My guess, is that there maybe a bug here, or something that got missed as the injection here should use the paths defined.

Hi Andrew,

True, that would work. But I think the problem here is that you would need to fill in the full path javaLoader:com.google.i18n.phonenumbers.PhoneNumbersUtil
every time you inject the property into a model component.

So while it would indeed work, if one day you want to use another java class, you would need to update that inject in every file using it.
He wants to wire it in wirebox.cfc so that in case of refactoring, he only needs to update one line.

At least that is what I think he is trying to achieve.

Cheers,
Tom

Hey Tom,

Yeah it does make sense now that I read it again, and yes the full path is required. However if you want to setup an alias and use either a singleton or not later then the option is there.