Small question on Spring Boot, and how to use a design pattern in order to select the appropriate @Repository please.
Setup: I have a springboot project which does nothing but save a pojo. The "difficulty" is that I need to choose where to save the pojo, based on some info from the payload request.
I started with a first version, which looks like this:
@RestController
public class ControllerVersionOne {
@Autowired private ElasticRepository elasticRepository;
@Autowired private MongoRepository mongoRepository;
@Autowired private RedisRepository redisRepository;
//many more other repositories
@PostMapping(path = "/save")
public Mono<String> save(@RequestBody MyRequest myRequest) {
String whereToSave = myRequest.getWhereToSave();
MyPojo myPojo = new MyPojo(UUID.randomUUID().toString(), myRequest.getValue());
if (whereToSave.equals("elastic")) {
return elasticRepository.save(myPojo).map(s -> "");
} else if (whereToSave.equals("mongo")) {
return mongoRepository.save(myPojo).map(s -> "");
} else if (whereToSave.equals("redis")) {
return redisRepository.save(myPojo).map(s -> "");
// many more if else
} else {
return Mono.just("unknown destination");
}
}
}
With the appropriate @Configuration and @Repository for each and every database (I am showing 3 here, but imagine many
@Configuration
public class ElasticConfiguration extends ReactiveElasticsearchConfiguration {
@Repository
public interface ElasticRepository extends ReactiveCrudRepository<MyPojo, String> {
@Configuration
public class MongoConfiguration extends AbstractReactiveMongoConfiguration {
@Repository
public interface MongoRepository extends ReactiveMongoRepository<MyPojo, String> {
@Configuration
public class RedisConfiguration {
@Repository
public class RedisRepository { //note redis does not extends Reactive___Repository
And this first version is working fine. Very happy, meaning I am able to save the pojo to where it should be saved, as I am getting the correct repository bean, using this ugly if else structure. This structure is not very elegant, especially, not flexible at all.
This is why I went to refactor and change to this second version:
@RestController
public class ControllerVersionTwo {
private ElasticRepository elasticRepository;
private MongoRepository mongoRepository;
private RedisRepository redisRepository;
private Map<String, Function<MyPojo, Mono<MyPojo>>> designPattern;
@Autowired
public ControllerVersionTwo(ElasticRepository elasticRepository, MongoRepository mongoRepository, RedisRepository redisRepository) {
this.elasticRepository = elasticRepository;
this.mongoRepository = mongoRepository;
this.redisRepository = redisRepository;
// many more repositories
designPattern = new HashMap<>();
designPattern.put("elastic", myPojo -> elasticRepository.save(myPojo));
designPattern.put("mongo", myPojo -> mongoRepository.save(myPojo));
designPattern.put("redis", myPojo -> redisRepository.save(myPojo));
//many more put
}
@PostMapping(path = "/save")
public Mono<String> save(@RequestBody MyRequest myRequest) {
String whereToSave = myRequest.getWhereToSave();
MyPojo myPojo = new MyPojo(UUID.randomUUID().toString(), myRequest.getValue());
return designPattern.get(whereToSave).apply(myPojo).map(s -> "");
}
}
As you can see, I am leveraging a design pattern refactoring the if-else into a hashmap. Then, just getting the correct repository based on the where to save. Working fine, but please note, the map is a Map<String, Function<MyPojo, Mono<MyPojo>>>
, as I cannot construct a map of Map<String, @Repository>
:
With this second version, it is more elegant, but unfortunately, still not very flexible.
This is why I am having the idea to build a third version, where I can configure the map itself, via a spring boot property @value for hashmap:
Here is what I tried:
@RestController
public class ControllerVersionThree {
@Value("#{${configuration.design.pattern.map}}")
Map<String, String> configurationDesignPatternMap;
private Map<String, Function<MyPojo, Mono<MyPojo>>> designPatternStrategy;
public ControllerVersionThree() {
convertConfigurationDesignPatternMapToDesignPatternStrategy(configurationDesignPatternMap, designPatternStrategy);
}
@PostMapping(path = "/save")
public Mono<String> save(@RequestBody MyRequest myRequest) {
String whereToSave = myRequest.getWhereToSave();
MyPojo myPojo = new MyPojo(UUID.randomUUID().toString(), myRequest.getValue());
return designPatternStrategy.get(whereToSave).apply(myPojo).map(s -> "successSavedAt " + myRequest.getWhereToSave() + s.getValue());
}
}
And I would configure in the property file:
configuration.design.pattern.map={elastic:ElasticRepository, mongo:MongoRepository , redis:RedisRepository , ...}
Unfortunately, I am stuck. First of all, is this even possible? And if it is, (hopefully it is), how to achieve this conversion please?
Thank you for your help.
Aucun commentaire:
Enregistrer un commentaire