Resource Storing lambdas on disk

Discussion in 'Spigot Plugin Development' started by AuroraLS3, Aug 7, 2018.

  1. Hello.

    Here is a neat trick you might not be aware of in Java - You can store lambdas with the help of Serializable interface. (You can store almost anything with Serializable interface, when used correctly)

    I found it on StackOverflow while researching ways of making a flexible extension system for data analysis that could store object mutation information in a database. (One server defines data and mutation operations, second server performs mutation and displays the result)

    Code (Text):
    // Lambda
    Function<String, String> function = (Function<String, String> & Serializable) string -> string + "world";

    byte[] output;
    try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
       try (ObjectOutput oo = new ObjectOutputStream(out)) {
            oo.writeObject(function);
        }
        output = out.toByteArray();
    }

    // Save result, you can use a database - or use a FileOutputStream instead of ByteArrayOutputStream
    Code (Text):
    byte[] output; // Load result elsewhere

    Function<String, String> outputFunction;
    try (ObjectInput oi = new ObjectInputStream(new ByteArrayInputStream(output))) {
        outputFunction = (Function<String, String>) oi.readObject();
    }

    System.out.println(outputFunction.apply("hello "));
    prints
    Code (Text):
    hello world
    Disclaimer: I don't know the limitations yet as I have only dabbed around with it in a single run-time instance. I just wanted to share

    PS: if you find (Function<String, String> & Serializable) ugly, you can always create a new interface
    Code (Text):
    interface SerializableFunction<V, K> extends Function<V, K>, Serializable
     
  2. Not sure how exactly this would be useful. If the idea is that you have to write Java code to store it in the first place, might as well just write an API that accepts the lambda rather than you know... Load it from a file.
     
    • Agree Agree x 2
    • Funny Funny x 1
  3. FrostedSnowman

    Resource Staff

    if you're really following an approach to this in a project, you're going about it wrong. i realized this when i was doing the same thing with runnables. there are almost no cases where this is needed
     
  4. joehot200

    Supporter

    Despite people talking about it not being needed, it's still cool to see.
     
    • Like Like x 1
    • Agree Agree x 1
  5. I'm going to try transfer a data point for each player (say how many times they have voted), and how those values should be used to visualize something about all of the numbers (say total times voted on a server) from a Bukkit server (Where the plugin with the data exists), to a BungeeCord server (Where the data isn't accessible via java methods, but can be in the database).

    So
    Code (Text):
    Function<List<Integer>, String> function; // How to display total votes

    SELECT * FROM data_table; -> List<Integer> votes

    displayOnPage(function.apply(votes))
    Of course it's going to be different than this, but just as an example. It might not even work, I don't know yet.
     
  6. Will I use this? Honestly, no clue.

    Am I happy I know this? Yes, very.

    Good day to you sir.
     
    • Friendly Friendly x 1
    • Useful Useful x 1
  7. You still need to be able to serialise all data the lambda captures.
     
  8. Tux

    Tux

    While this is a valid approach, I should note that the Java serialization interface is likely to be gutted because it is very insecure.

    A far better approach is to use a shared, platform-independent module with the function in it, or use Nashorn or similar if you really need to execute arbitrary code.
     
    • Useful Useful x 1
  9. i'm surprised that this actually works to be honest, ObjectOutputStream only writes out class signature and object state so im guessing it must be to do with how lambda notation is internally implemented, because if you were to do the same thing with a concrete outer class implementing Function, Serializable, im sure you wouldnt see the same result.

    otherwise a pretty noteworthy finding in my opinion, but obviously shouldnt be relied upon for anything important. could be quite useful for smaller for-fun projects though personally.

    I know that ObjectOutputStream will serialize class state, assuming its able to serialize the lambda in a way that captures the Function, does it not capture the state referenced by the Function in this case? Interesting if so, wonder if there's a way to make that work.