Reputation: 17
I am extremely sorry for posting this large question but I have been struggling with the argument factory and column mapper for too long.
MAIN QUESTION: I would like the Argument Factory and Column Mapper are generic so that I do not have to register it for every column explicitly.
I have a table in MySQL with schema:
create table employee {
id int not null primary key,
name varchar(255),
job_details json,
metadata json
}
I have the DAO layer interface that looks like
@UseClasspathSqlLocator
public interface EmployeeDao {
@SqlQuery
@RegisterBeanMapper(EmployeeDB.class)
EmployeeDB fetchEmployee(@Bind("id") int id);
@SqlUpdate
void insertEmployee(@BindBean EmployeeDB employeeDB);
}
The SQL script files are available in resources which look like
fetchEmployee.sql
SELECT *
FROM employee
WHERE id = :id
LIMIT 1
insertEmployee.sql
INSERT INTO employee (id, name, job_details, metadata)
VALUES (:id, :name, :jobDetails, :metadata)
I also have repository class that looks like
public class EmployeeRepository {
private final CommonJdbiProvider commonJdbiProvider;
public EmployeeRepository(CommonJdbiProvider commonJdbiProvider) {
this.commonJdbiProvider = commonJdbiProvider;
}
@Nullable
public EmployeeDB getEmployee(int id) {
EmployeeDB employeeDB = null;
try {
employeeDB =
commonJdbiProvider
.readOnlyJdbi()
.withHandle(
handle -> {
EmployeeDao dao = handle.attach(EmployeeDao.class);
return dao.fetchEmployee(id);
});
} catch (Exception ex) {
log.error("Error while getting employee: {}", id, ex);
}
return employeeDB;
}
public void saveEmployee(EmployeeDB employee) {
try {
commonJdbiProvider
.readWriteJdbi()
.useTransaction(
TransactionIsolationLevel.READ_COMMITTED,
handle -> {
EmployeeDao dao = handle.attach(EmployeeDao.class);
dao.insertEmployee(employee);
});
} catch (Exception ex) {
log.error("Error while saving employee: {}", employee, ex);
}
}
}
The CommonJdbiProvider class looks like
public class CommonJdbiProvider {
private final JdbiProvider jdbiProvider;
public CommonJdbiProvider(JdbiProvider jdbiProvider) {
this.jdbiProvider = jdbiProvider;
}
public Jdbi readOnlyJdbi() {
Jdbi jdbi = jdbiProvider.readOnly();
if (Objects.isNull(jdbi)) {
throw new IllegalStateException("Unable to initialize read-only Jdbi via JdbiProvider");
}
plugins().forEach(jdbi::installPlugin);
return jdbi;
}
public Jdbi readWriteJdbi() {
Jdbi jdbi = jdbiProvider.readWrite();
if (Objects.isNull(jdbi)) {
throw new IllegalStateException("Unable to initialize read-write Jdbi via JdbiProvider");
}
plugins().forEach(jdbi::installPlugin);
registerGenericMappers(jdbi);
return jdbi;
}
private List<JdbiPlugin> plugins() {
List<JdbiPlugin> jdbiPlugins = new ArrayList<>();
jdbiPlugins.add(new SqlObjectPlugin());
jdbiPlugins.add(new Jackson2Plugin());
return jdbiPlugins;
}
private void registerGenericMappers(Jdbi jdbi) {
jdbi.registerArgument(new GenericJsonArgumentFactory());
jdbi.registerColumnMapper(new GenericJsonColumnMapperFactory());
}
}
Now I also have the POJO classes for Employee, JobDetailsType and MetadataType UDT:
public class EmployeeDB {
@JsonProperty("id")
private int id;
@JsonProperty("name")
private String name;
@JsonProperty("job_details")
private JobDetailsType jobDetails;
@JsonProperty("metadata")
private MetadataType metadata;
}
public class JobDetailsType {
@JsonProperty("role")
private String role;
@JsonProperty("salary")
private int salary;
}
public class MetadataType {
@JsonProperty("joining_date")
private Date joiningDate;
@JsonProperty("random_field")
private String randomField;
}
Please help me write an appropriate ArgumentFactory class and ColumnMapper class that can be used to serialize a class object to Json if needed and deserialize json to a class object as per the column name.
Thank you so much in advance
I tried using some way to write a generic mappers and factories but they all seem to be failing. Tried using ChatGPT but its of no help.
Upvotes: 0
Views: 167