I am working on a Java Spring Boot project. I have an entity that has 20 fields. I currently have an put method that takes these 20 fields, all of them are non-nulls and I validate them using validators including my custom validators. But it is costly. Even if I want to change a single field in my db, I completely fetch the row, update all fields using custom mapper and save into db. In this implementation, even if only one field changes, I have to send all fields in request and also I overwrite 19 unchanged field into db which is costly. I am looking for solutions to:
- I should be able to send only fields that is supposed to change and I should be able to validate them in DTO level using validator (for example: I should be able to check if a values between 0 and 100. In current implementation I have a custom validator for this)
- I should be able to overwrite only changed fields into db. I shouldnt overwrite values that should remain same.
- (kind of optional) It would be better if it can be generic. I can easily adapt for my different controllers.
I have been searching Java Reflections and found this implementation:
@PatchMapping("/{id}")
public Product updateProductFields(@PathVariable int id,@RequestBody Map<String, Object> fields){
return service.updateProductByFields(id,fields);
}
public Product updateProductByFields(int id, Map<String, Object> fields) {
Optional<Product> existingProduct = repository.findById(id);
if (existingProduct.isPresent()) {
fields.forEach((key, value) -> {
Field field = ReflectionUtils.findField(Product.class, key);
field.setAccessible(true);
ReflectionUtils.setField(field, existingProduct.get(), value);
});
return repository.save(existingProduct.get());
}
return null;
}
public interface ProductRepository extends
JpaRepository<Product, Integer> {
}
But I am not sure if this satisfies my desires. Do you have any suggestions?
Personally I prefer type safety so don't like dealing with
Map<String, Object>.You mentioned in a comment that you want to do this for many different DTO's, each with many fields. I think you should consider generating code using an annotation processor. This would allow you to generate an
XDeltaand anXMergerfor each of your model classes.eg You could annotate the
Productclass with a custom@DeltaannotationThe annotation processor would then generate
For generating code I usually use freemarker