my2iu / Jinq

LINQ-style queries for Java 8
Other
660 stars 71 forks source link

Could not extract code from lambda. This error sometimes occurs because your lambda references objects that aren't Serializable. #58

Closed georgemoralis closed 7 years ago

georgemoralis commented 7 years ago

it is kinda weird issue with a @ManyToOne using latest 1.8.19 jinq and hibernate 5.2.9

use case

@Entity @Table(name = "taxis_history") public class xreihistoryEntity implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Getter
@Setter
private Integer id;
@Getter
@Setter
@ManyToOne(optional = false)
@JoinColumn(name = "CLIENT_ID")
private clientsEntity client;

}

@Entity @Table(name = "clients") public class clientsEntity implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Getter
@Setter
private Integer id;

.... @OneToMany(mappedBy = "client") private List history; }

running the following query throws the above error

protected List getHistoryQuery(clientsEntity client) { JinqJPAStreamProvider streams = new JinqJPAStreamProvider(MainApp.getEmf()); streams.registerAttributeConverterType((LocalDateTimePersistenceConverter.class)); EntityManager em = MainApp.getEmf().createEntityManager(); List results = streams .streamAll(em, xreihistoryEntity.class) .where(c -> c.getClient().equals(client)) .sortedDescendingBy(c -> c.getSearchdate()) .toList(); em.close(); return result; }

Removing where case works fine , else i get the above error

i made an ugly workaround by transforming the result to stream and filter from there but hmm it's ugly

protected ObservableList getHistoryQuery(clientsEntity client) { JinqJPAStreamProvider streams = new JinqJPAStreamProvider(MainApp.getEmf()); streams.registerAttributeConverterType((LocalDateTimePersistenceConverter.class)); EntityManager em = MainApp.getEmf().createEntityManager(); List results = streams .streamAll(em, xreihistoryEntity.class) //.where(c -> c.getClient().equals(client)) .sortedDescendingBy(c -> c.getSearchdate()) .toList(); ObservableList result2 = results.stream().filter(c->c.getClient().getId().intValue()==client.getId().intValue()).collect(toCollection(FXCollections::observableArrayList)); em.close(); return result2; }

any ideas?

my2iu commented 7 years ago

.where(c -> c.getClient().equals(client)) accesses the client variable, so Java will include a reference to client in the lambda. When the lambda is serialized, client will be serialized as well. So clientsEntity will need to be serializable for the lambda to be serializable.

I imagine Hibernate adds some extra stuff to clientsEntity behind the scenes that makes it non-serializable. Can you compare id instead of comparing clientsEntity?

int clientId = client.getId();
streams.streamAll(em, xreihistoryEntity.class)
   .where(c -> c.getClient().getId().equals(clientId))
   ....
georgemoralis commented 7 years ago

yah that seems to do the trick :)

i have done similar queries like this where(c -> c.getClient().equals(client)) but with hibernate 4 . I wonder if it is some incompatibility with hibernate 5...

my2iu commented 7 years ago

They maybe introduced a bug as they start preparations for Hibernate 6.

You should try serializing your Hibernate clientsEntity entity to see if it actually serializes and deserializes properly. If it doesn't, then maybe Hibernate is altering it in a way that prevents your @Serializable annotation from working.