2

I am working on an abstract model to represent a variety of complex business processes based on event registration. For that purpose, I want to be able to persist Java8 Function objects using the newest version of Hibernate, such as

@Entity
public class Foo {
    private Runnable onUpdate = () -> System.out.println("worked");
    private java.util.function.Function<String, String> identity = s -> s;
    // imagine bean-compliant getter and setter
}

Persisting method references is not an option, since partial method application during runtime before setting a callback is a requirement.

Just trying above code leads to the following exception:
org.hibernate.MappingException: Could not determine type for: java.lang.Runnable ...

Is there any way to persist function objects that match a fixed functional interface such as Runnable? And if not, what alternative strategies are available?

EDIT concerning the XY-problem:

I want to be able to associate methods in an object with some hibernate entity's PostUpdate callback during runtime, while letting the user supply all arguments which the hibernate callback can not supply. For example, I have an entity @Entity public class Bar and another controller class with a method void foo(Bar new, int i). Now, every time a specific instance of Bar is updated in the database, I want it to call foo with the updated object and a parameter i, which is specified by the user during current or some previous runtime while associating the foo-Event with the Bar instance.

Most importantly, I want to persist this runtime association using Hibernate, keeping a reference to the method, the object the method belongs to and all parameters supplied during association. Then, on server startup, as soon as the controller object is loaded it listens to changes made to the entity instance.

Dracam
  • 149
  • 2
  • 11
  • So you want to store the Java code of the functional interface in your DB? I doubt this is possible out-of-the-box. But you could implement your own abstraction for functions and serialize them. – Steffen Harbich Dec 08 '17 at 13:32
  • 1
    What do you want to do with it after ? It seems to by a [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)... – AxelH Dec 08 '17 at 13:36
  • I want to register a set of process-specific callbacks with [hibernate events](https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/events/Events.html) so that when an entity gets updated from somewhere, code is executed to automatically resolve invalid entity states – Dracam Dec 08 '17 at 13:42
  • 2
    Maybe you can't (or wouldn't want want to) persist a `Function`, but you can certainly persist a `String` that could be mapped to a function. – Kevin Anderson Dec 08 '17 at 14:05
  • Cant you persist its bytes via making it `Serializable`? – Eugene Dec 08 '17 at 14:34
  • Persisting the binary representation of a function won't work, since memory addresses of external references in closures would not be the same after application restart. – Dracam Dec 08 '17 at 15:02
  • I've been thinking about this for a while and I don't understand the requirements very exactly but it seems that hibernate-envers would be much better suited for this – Eugene Dec 10 '17 at 20:00
  • @Eugene as far as I understand, Envers are used for versioning of field contents. I don't see how that is related – Dracam Dec 13 '17 at 16:24
  • @Dracam as far as I understand u want simething to happen every time youy entity is "touched", that can be done with envers – Eugene Dec 13 '17 at 16:27
  • Is it possible to assign behaviour at runtime though? For hard-coded behaviour I can use hibernate callbacks – Dracam Dec 13 '17 at 16:44

1 Answers1

3

No

Unfortunately in current versions of Hibernate it is impossible to store Java 8 functions in a database. Lambdas do not implement Serializable and there is no way to make them do so.

Jonathan Coustick
  • 1,127
  • 9
  • 19
  • So if I built a serializable class containing a reference to the callback origin, a method name and a map with fieldname -> value, I should be able to use that instead. Right? – Dracam Dec 08 '17 at 14:40
  • That sounds about right. I can't confirm without doing the code myself, but that sounds like a reasonable strategy. – Jonathan Coustick Dec 08 '17 at 14:42
  • 3
    @JonathanCoustick you can make them serializable via `& Serializable` https://www.google.com/url?sa=t&source=web&rct=j&url=https://stackoverflow.com/questions/22807912/how-to-serialize-a-lambda&ved=0ahUKEwiO--S91_rXAhUJtBoKHXV8AOIQjjgIITAA&usg=AOvVaw00rojBF_0nCm07YqFf_TlJ – Eugene Dec 08 '17 at 15:01
  • @Eugene I can't have `Runnable & Serializable` as a valid Type of a `callback` field in an entity. I could store a string and provide a setter, serializing the passed lambda, but I doubt that would work for non-pure functions or closures. – Dracam Dec 08 '17 at 15:12
  • @Eugene apparently your solution causes the lambda to evaluate all references (such as an `AtomicInteger::get` in an outer scope) during serialization, thereby losing all closure capabilities. One could still make this work by supplying database IDs instead, but I think I'd prefer the serializable-class-solution. However, your idea is still worth an answer. – Dracam Dec 08 '17 at 15:26
  • Is this `Serializable` thing `Hibernate` specific? I mean that that my Entities persist ok without implementing `Serializable` using OpenJPA. – pirho Dec 08 '17 at 16:38
  • @pirho Stored fields must be `Serializable`, `String`, a primitive, collection or made up of the above. See http://www.logicbig.com/tutorials/java-ee-tutorial/jpa/persistable-basic-types/ for details. – Jonathan Coustick Dec 08 '17 at 16:55
  • @JonathanCoustick Thanks, seems that I mixed things a bit. – pirho Dec 08 '17 at 17:41