tracker issue : CF-4201310

select a category, or use search below
(searches all categories and all time range)
Title:

CF -> Java Lambdas

| View in Tracker

Status/Resolution/Reason: To Fix//Investigate

Reporter/Name(from Bugbase): Luis Majano / Luis Majano ()

Created: 02/22/2018

Components: Java Integration

Versions: 13.0

Failure Type: Others

Found In Build/Fixed In Build: /

Priority/Frequency: Normal /

Locale/System: / iOS All

Vote Count: 7

Doing modern Java integration sucks at this point with CFML. No easy way to class load dynamically, extend java objects and implement java objects from CFCs.  Please look at my other tickets on extending java classess and implementing them from CFCs.

This one is for java lambdas.  This is in much much more usage in modern Java APIs and integrating them with CFML is horrible and cumbersome. 

I propose a CF -> Java lambda translation.   First, lambdas need to be implemented first so please address this, lucee has them already.

- Ability to create Java Lambdas as proxies so we can pass them into Java. This should be dynamic, meaning if we define a lambda and pass it to the java function the type inference should kick in from Java.

Let's look at an example, here is a Java Interface:
{code:java}
java
// Interface
public interface StateChangeListener {

    public void onStateChange(State oldState, State newState);

}

// Class accepting the interface
public class StateOwner {

    public void addStateListener( StateChangeListener listener) { ... }

}
{code}


Right now, we would have to create a CFC and use dynamic proxy in order to satisfy this interface. Cumbersome for a single function interface.  In Java I would do two things:

{code:java}
**Inline Interface**
java

stateOwner.addStateListener( new StateChangeListener() {

    public void onStateChange(State oldState, State newState) {
        // do something with the old and new state.
    }
} );
{code}


**Lambda**
{code:java}
java
StateOwner stateOwner = new StateOwner();

stateOwner.addStateListener(
    ( oldState, newState ) -> System.out.println( "State changed" )
);

{code}

So why not do this automatically cast a CFML lambda to a Java Lambda.

cfml
{code:java}
stateOwner = new java:StateOwner();

stateOwner.addStateListener(
    ( oldState, newState ) => systemOutput( "State changed" )
);
{code}


As you can see, they would be a CFML lambda tht satisfies the interface.

Attachments:

Comments:

The more Java libraries I integrate with via CFML the more painful this sort of thing becomes. CFML really needs to have a better Java bridge in today's world.
Comment by Bradley W.
29268 | July 11, 2018 04:40:59 AM GMT
@Bradley Wood: We might be taking this feature in the next release. Just to cover up for all the problems that you are facing, Can you attach the code or a sample test for it?
Comment by Ashudeep S.
29269 | July 11, 2018 05:43:58 AM GMT
Luis has a pretty good example in the description. Basically, allow an anonymous CFML function to be passed as a lambda to a Java library. This is possible now but only using createDynamicProxy() and an intermediate CFC file. Note, Luis example uses the "arrow function" format that java lambdas use but that is really a separate enhancement. There's no reason this wouldn't work with the standard closure syntax as well. If you are looking at ways to improve java interop, many Java libs expect you to extend a class and override a method or implement an interface. In Java you can do both of these very easily and on the fly right there in your code without needing to create a separate .java file. In CFML if you are using one of these Java libraries, it is a pain to do this. Implementing a java interface can be done again via createDymanicProxy() but extending java classes is impossible. I've had to resort to compiling custom jars before just to work around this. Take this Java example: https://www.programcreek.com/java-api-examples/java.net.Authenticator In Java, you are able to create a class on the fly and override methods right there in the middle of your Java code. Not only can I not do this with CFML classes in CFML but I certainly can't do this with Java classes in CFML which is a pain. Instead I have to create and compile an actual Java class here: https://github.com/Ortus-Solutions/commandbox/blob/development/src/java/com/ortussolutions/commandbox/authentication/ProxyAuthenticator.java And explicitly create it for use here: https://github.com/Ortus-Solutions/commandbox/blob/fce1f75154a8aecdc8bc0d41d5a71aed2dc1a1b9/src/cfml/system/util/ProgressableDownloader.cfc#L180 This sort of boilerplate makes interfacing with modern Java libraries way more complicated than it should be. It's sad when the Java version of the code is actually smaller and tighter than the CFML version of the same thing. CF needs to step their game here.
Comment by Bradley W.
29276 | July 11, 2018 06:18:05 AM GMT