Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaLoader.create Creation of Multiple Instances (initUseJavaProxyCFC) #10

Closed
de-robat opened this issue Mar 20, 2014 · 7 comments
Closed

Comments

@de-robat
Copy link

I found the behaviour of the JavaLoader a bit missleading whenever coldfusion ist setted to "Disable access to internal ColdFusion Java components" via the CF-Administrator. In those cases the JavaLoader switches the underlying loading procedures to use a different JavaProxy Implementation in the "initUseJavaProxyCFC" function beeing written in JavaLoader.cfc . The weird thing here is that by using the Proxy from coldfusion "coldfusion.runtime.java.JavaProxy" the init() function calls to java proxys work differently than the once beeing issued over JavaProxy.cfc Component.

Usually a call of init() on an JavaProxy leads to the invocation of a constructur and thus result in the return of a new instance. However when the JavaProxy.cfc component is used subsequent init calls lead to the return of one and the same Instance all over again.
This is due to:

//make sure we only ever have one instance
if(_hasClassInstance())
{
    return _getClassInstance();
}

The bad thing about that is that you can't rely on the functionality and always have to code for the case where no new Instances are created. Is there a reason why the JavaProxy Component is behaving differently and if yes than please indicate that in the "hint" attribute of the:

<cffunction 
    name="init" 
    hint="create an instance of this object"
    access="public" 
    returntype="any" 
    output="false" >

description.
Besides that flaw wich cost me quite some time today i love the JavaLoader! Its really great and much appreciated. Thank you very much.

@markmandel
Copy link
Owner

Yeah, but you really shouldn't be writing code that way anyway ;)

@de-robat
Copy link
Author

Ok, so what am i missing? How else should it be used then? I mean i feel like there is a change in the way the api works in one vs the other case. Im just using JavaLoader.create(...) and then call "init" on the Proxy returned - thats it. And "init" alters its behaviour regarding on the runtime. So what am i doing wrong? Ty for the quick reply!

@markmandel
Copy link
Owner

While I admit, you can do what you are doing with the ColdFusion based proxy, I think it leads to some pretty nasty confusion when you look at the code.

I would write all code as:

hello1 = loader.create("HelloWorld").init();
hello2 = loader.create("HelloWorld").init();

Doing it like this

proxy = loader.create("HelloWorld")
hello1 = proxy.init();
hello2= proxy.init();

Just feels mega weird to me. As it steps far away from what a "normal" object construction would look like.

YMMV.

@de-robat
Copy link
Author

Ok. Actually thats just what i changed my code to be like. But using Coldbox, i used to prepare my proxys within the onDependencyInjectionComplete (onDIComplete). And from there on just used the proxy object for instantiiation which seemed advantageous in terms of performance - instead of recreating a proxy all over again. (especially when using java classes which are beeing instantiiated hundereds of times)

...
property name="JavaLoader" inject="coldbox:plugin:JavaLoader";
...

// wait for the plugin to be loaded
public void function onDIComplete() onDIComplete {
    jdomDoc = JavaLoader.create("org.jdom2.Document")
    jdomEl = JavaLoader.create("org.jdom2.Element");
    ...
}
...
private void function someFunction() {
    // create instances
    var doc = jdomDoc.init(...);
    for(...) {
        doc.addContent( jdomEl.init(...) );
    }
}

Maybe, in most circumstances, a neglectable performance gain though. So i can life with the solution presented by you. Nevertheless it may be a good idea to change the documentation to state that intended (and slightly variant to the original api) use more explicity.

Appendix for reference: "quick and dirty measurement" shows time for reinstantiating proxys again and again is of an order of 3-4 bigger than reusing the proxy object in plain coldfusion.

<html>
    <title>test</title>
    <body>
        <div>
        <cfscript>
            sb = createobject("java", "java.lang.StringBuilder");
            runs = 100000;

            // reuse the proxy
            start = Now();
            for(i = 0; i < runs; i++){
                myBuilder = sb.init("test");
            }
            end = Now();
            writeOutput("one Proxy: " & (end.getTime() - start.getTime()));


            // reinstantiiate the proxy
            start = Now();
            for(i = 0; i < runs; i++){
                myBuilder = createobject("java", "java.lang.StringBuilder").init("test");
            }
            end = Now();
            writeOutput("<br>" & runs & " Proxys: " & (end.getTime() - start.getTime()));
        </cfscript>
        </div>
    </body>
</html>

//result
one Proxy: 78
100000 Proxys: 226

@markmandel
Copy link
Owner

The wiki is open 😄 feel free to make the appropriate changes.

@edwardbeckett
Copy link

"using java classes which are beeing instantiiated hundereds of times..."

Therein lies the rub ...

http://coldfusiondesignpatterns.org/singleton.html

@de-robat
Copy link
Author

@edwardbeckett Nope, unfortunately i think it doesn't. You noticed that the previously describe behaviour of the JavaProxy.cfc Component actually practically adheres to the Singeltons pattern? And thats what introduces the problem in the first place.

There are several use cases in which singeltons simply do not work for you. One of those is beeing depicted in my example. If you build up an XML in-memory object by the use of a Java-Bib such as JDOM, you simply have a scenario where you need one instance for each and every node in your dom. That is due to every node having its own attribute-set, its own naming and content elements. And in lots of different kinds of applications, hundereds of nodes are rather common than unusual (performance improvements would be still possible in such cases, but i won't elaborate on those in this context as they don't add to the discussion).

The JavaProxy, as implemented by plain coldfusion instead, works as a singelton to a java class. Which is perfectly fine, and exactly the behaviour i would have anticipated the JavaProxy.cfc Component to have as well - but the init function is more a kind of a factory resulting in new objects every time it is called - and here is where the difference im targeting at is introduced.

Anyhow. I think we discussed this one more than enough. Im going to edit the wiki as suggested by markmandel. And as long as my request is not considered as beeing valid to be integrated into the code base (i still think its rather a bug than a design decision) i could still fork it. Sadly that way it won't get integrated within the coldbox framework any time soon. But please feel free to close this issue @markmandel .

Finally, once more, let me express my appreciation for your JavaLoader implementation. Its a really easy way to get different java-classes integrated into your coldfusion project by still keeping things like dependency managment via maven completly intact and simultaneously keepping your app structures clean an comprehensive. So kudos to you and thanks for your responses!

( quite a verbose discussion, i simply tried to make my point :) )

@de-robat de-robat closed this as completed Nov 4, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants