Reputation: 605
I have problem, which I think can be easly solved, but I can't do it.
I have a class A and B and class A is stored in postgres db:
public class A() {
private B b;
...
}
public class B() {
private String firstName;
private String lastName;
private String personId;
private String userName;
}
In database, object of class b is stored as string userName in A entity. So to have object of class A from db in app, I have to read A record and create object of class B. I want to create query with jooq, but jooq does not know how to convert this string username to instance of class B. How to tell jooq how it should map database A object to object of class A.
A class is equivalent to Person and B class is equivalent to Executor.
My query
return jooq.select()
.from(PERSON)
.where(PERSON.ID.eq(id))
.fetchOneInto(Person.class);
This is the exception thrown by my query
Caused by: org.jooq.exception.DataTypeException: Cannot convert from superadmin (class java.lang.String) to class fi.ssm.oksa.domain.person.Executor
at org.jooq.tools.Convert$ConvertAll.fail(Convert.java:1118) ~[jooq-3.8.5.jar:na]
...
I think I should use this http://www.jooq.org/doc/3.8/manual/code-generation/custom-data-type-bindings/ but I can't implement it.
Upvotes: 4
Views: 2424
Reputation: 220762
There are different ways to solve this:
jOOQ has an undocumented feature in its DefaultRecordMapper
that allows you to nest result records when you use any of the into(Class)
methods. You have to manually specify the "path" of the nested record as if you were actually using ORDBMS nested records, as such:
jooq.select(
PERSON.FIRST_NAME.as("executor.first_name"),
PERSON.LAST_NAME.as("executor.last_name"),
PERSON.PERSON_ID.as("executor.person_id"),
PERSON.USER_NAME.as("executor.user_name"))
.from(PERSON)
.where(PERSON.ID.eq(id))
.fetchOneInto(Person.class);
When you alias your columns this way, then the DefaultRecordMapper
will search for the executor
property in the Person
class, and put the trailing sub-path into a nested object.
In this example, I'm going to assume the slightly modified versions of your classes:
// instead of A
public class Person {
private Executor executor;
...
}
// instead of B
public class Executor {
private String firstName;
private String lastName;
private String personId;
private String userName;
}
DefaultRecordMapper
You can implement your own algorithms for mapping when using the into(Class)
methods as documented here:
http://www.jooq.org/doc/latest/manual/sql-execution/fetching/pojos-with-recordmapper-provider
Of course, nothing forces you to rely on jOOQ's built-in automatic mapping features. You could write your own algorithm like this, for instance:
jooq.select()
.from(PERSON)
.where(PERSON.ID.eq(id))
.fetchOne(r -> new Person(new Executor(r.get(PERSON.FIRST_NAME), ...));
Upvotes: 2