I'm trying to use the jOOQ fetchInto()
method to map to an existing Hibernate model Organization
(class and its inheritances are below).
Organization organization = jooq().select().from(ORGANIZATION).fetchOne().into(Organization.class);
The problem I have is that I can't really understand what happens in DefaultRecordMapper as I feel I'm not entirely familiar with all the terms that are used. I'm trying to figure out how it applies to the Hibernate classes that are in my codebase.
So far what I've tried:
Organization
Hibernate model.@Column
annotation to name
in the Organization
Hibernate model.What works:
id
field gets mapped correctly.What doesn't work:
name
field doesn't get mapped (null
).createdAt
and modifiedAt
fields do not get mapped (null
).My question is: Is there something I am overlooking with the mapping and what are the things I should look at concerning the classes, fields, constructors and annotations with Hibernate models? I want to eventually map all the Hibernate models in the codebase and use fetchInto
to do that.
Thanks! :)
@Entity
public class Organization extends BaseModel {
@Required public String name;
//... a lot of other code
}
@MappedSuperclass
public class BaseModel extends Model {
/** The datetime this entity was first saved. Automatically set by a JPA prePersist */
@NoBinding
@Column
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
public DateTime createdAt;
/** The datetime this entity was last modified. Automatically set by a JPA preUpdate */
@NoBinding
@Column
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
public DateTime modifiedAt;
//...
}
@MappedSuperclass
public class Model extends GenericModel { // Both Model and GenericModel are from the Play Framework
@Id
@GeneratedValue
public Long id;
public Model() {
}
public Long getId() {
return this.id;
}
public Object _key() {
return this.getId();
}
}
jOOQ doesn't support all the many JPA and Hibernate specific annotations. Historically, it supported a few JPA annotations (because why not), but full interop would be excessive and investing product development time in the wrong places. jOOQ is by no means a JPA implementation.
As of jOOQ 3.20, the JPA annotation mapping functionality has been extracted to a separate module, in parts to stress the fact that future jOOQ versions will not deepen their integration with these annotations:
So, you shouldn't have too high expectations about annotations to "work"
As mentioned before, not all JPA specification is implemented. For example, a known difference is that @Column
annotations are mandatory in jOOQ:
https://github.com/jOOQ/jOOQ/issues/4586. This will not change!
Even more so, things like @MappedSuperclass
or @Type
are never going to be supported by jOOQ.
You've decided to create and run your query with jOOQ. I imagine your actual query is much more complex than what you're showing, because for that particular query, you don't need jOOQ.
Do you really need to map to Hibernate entities? Because even when you use Hibernate, the recommended approach is to use entities only when you're going to modify them and store the delta back to the database. If that's the case, see step 2 below. If it's not the case, why not use jOOQ's own mapping functionality to work with any style of jOOQ supported POJO?
In particular, starting from jOOQ 3.15, the MULTISET
and ROW
operators along with ad-hoc conversion have changed quite a bit how people interact with jOOQ and SQL as shown in this blog post. These approaches seem much more safe and convenient than the automatic mapping using reflection (with or without JPA annotations).
If you're using jOOQ only to build a rather complex SQL query and you need Hibernate entities as a result, then use Hibernate to execute the jOOQ query as documented here. A small utility should be enough:
public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query, Class<E> type) {
Query result = em.createNativeQuery(query.getSQL(), type);
List<Object> values = query.getBindValues();
for (int i = 0; i < values.size(); i++)
result.setParameter(i + 1, values.get(i));
return result.getResultList();
}
Though, be aware that you'll be missing out on a ton of jOOQ functionality this way.