I follow one example with small modifications: https://dzone.com/articles/spring-webflux-first-steps
My ServiceImpl looks like:
private final HotelRepository hotelRepository;
private final HotelByLetterRepository hotelByLetterRepository;
public HotelServiceImpl(HotelRepository hotelRepository, HotelByLetterRepository hotelByLetterRepository) {
this.hotelRepository = hotelRepository;
this.hotelByLetterRepository = hotelByLetterRepository;
}
#Override
public Mono<Hotel> save(Hotel hotel) {
if (hotel.getId() == null) {
hotel.setId(UUID.randomUUID());
}
Mono<Hotel> saved = hotelRepository.save(hotel);
saved.then(hotelByLetterRepository.save(new HotelByLetter(hotel)));
return saved;
}
After Hotel entity is saved logic try to save HottelByLetter.
In repository I inject ReactiveCassandraOperations and for a save method I just call insert method.
#Repository
public class CassandraHotelRepository implements HotelRepository {
private final ReactiveCassandraOperations cassandraTemplate;
public CassandraHotelRepository(ReactiveCassandraOperations cassandraTemplate) {
this.cassandraTemplate = cassandraTemplate;
}
#Override
public Mono<Hotel> save(Hotel hotel) {
return cassandraTemplate.insert(hotel);
}
}
After service call only Hotel is saved, HotelByLetter is not saved.
After debug I found that:
In ReactiveCqlTemplate method createFlux is called properly two times with correct ReactiveSessionCallback.
protected <T> Flux<T> createFlux(ReactiveSessionCallback<T> callback) {
Assert.notNull(callback, "ReactiveStatementCallback must not be null");
ReactiveSession session = getSession();
return Flux.defer(() -> callback.doInSession(session));
}
But, callback.doInSession(session) is executed only once for insert new hotel.
I try also to extend ReactiveCrudRepository, but same issue.
I'm using: org.springframework.data/spring-data-cassandra/2.0.0.RELEASE
TL;DR;
You need to work with the results of each publisher operator to apply the actual operation which created the Publisher.
Explanation
Project Reactor's fundamental concept is to never mutate a Publisher through operators but rather returning a new instance. That's different in contrast to say a Future like CompletableFuture where you're able to register callbacks, and you're not obliged to reuse the result of the callback registration method to make it work.
The code of your HotelServiceImpl should look like the following:
class HotelServiceImpl implements HotelService {
// …
#Override
public Mono<Hotel> save(Hotel hotel) {
if (hotel.getId() == null) {
hotel.setId(UUID.randomUUID());
}
Mono<Hotel> saved = hotelRepository.save(hotel);
return saved.then(hotelByLetterRepository.save(new HotelByLetter(hotel)));
}
}
Calling saved.then(…) creates a new Mono. Dropping (not using) that Mono will result in not executing the .then(…) operator. Instead, returning the result of saved.then(…) will do also save HotelByLetter.
Related
the usage of method references as listeners in an observer pattern does not work.
Example:
public class ObserverWithMethodReferenceAsListenerTest {
class ListenerCurator {
private final Set<Consumer<String>> listeners = new HashSet<>();
public boolean register(final Consumer<String> consumer) {
return this.listeners.add(consumer);
}
public boolean unregister(final Consumer<String> consumer) {
return this.listeners.remove(consumer);
}
public int getListenersCount() {
return this.listeners.size();
}
}
class MyListenerLeaks {
public void theListener(final String someString) {
// the listener
}
}
class MyListenerWorks {
public Consumer<String> consumer = str -> {
theListener(str);
};
public void theListener(final String someString) {
// the listener
}
}
#Test
public void testListenerLeak() {
ListenerCurator lc = new ListenerCurator();
MyListenerLeaks ml = new MyListenerLeaks();
lc.register(ml::theListener);
Assert.assertEquals(1, lc.getListenersCount());
lc.register(ml::theListener);
// expected 1 but there are 2 listeners
lc.unregister(ml::theListener);
// there are 2 listeners registered here
}
#Test
public void testListenerWorks() {
ListenerCurator lc = new ListenerCurator();
MyListenerWorks ml = new MyListenerWorks();
lc.register(ml.consumer);
Assert.assertEquals(1, lc.getListenersCount());
lc.register(ml.consumer);
Assert.assertEquals(1, lc.getListenersCount());
lc.unregister(ml.consumer);
Assert.assertEquals(0, lc.getListenersCount());
}
}
Conclusion: each referencing of the listener method with ml::theListener generates a new object id for the reference? Right? Therefore there a multiple listeners registered and cannot be removed individually?
The MyListenerWorks class uses a member with a "constant" object id and works. Is there another workaround for this? Are my assumptions correct?
After I added some breakpoints to the HashSet#add and remove function.
I got some results for your questions in the images below:
1. each referencing of the listener method with ml::theListener generates a new object id for the reference? Right?
Ans: No. It would generate a new memory address into the HashSet. There would not be an object id. So in the test function:testListenerLeak, you cannot remove the listener correspondingly. Since you didn't get the listeners from the set before you remove it.
2. The MyListenerWorks class uses a member with a "constant" object id and works. Is there another workaround for this? Are my assumptions correct?
You could take a look of the Observer pattern in Spring, Vue, or some other famous project. they have something similar to what you want. But mostly I have ever read about this pattern is in the Event-driven model. They use the "instanceOf" to check the subclasses and their superclass.
From the Oracle documentation on Method References:
Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.
A method reference is not a constant.
I have entity in database, say, MonthPlan:
class MonthPlan {
private boolean approved;
// other fields
}
There is also REST interface, which accepts external requests based on which program changes entity instances. For example, request
class EditMonthPlanRequest {
private long amount;
// other fields
}
is used to change month plan amount.
What I need is to execute different actions on MonthPlan entity based on value of approved field. For example, code for mentioned request could be as following
MonthPlan plan = getPlan(...);
if (plan.isApproved()) {
// actions using data from EditMonthPlanRequest
} else {
// other actions using data from EditMonthPlanRequest
}
There would be 5-6 different requests each with exactly two variants of actions based on value of approved field of edited entity. What OOP design pattern can I use for such use case to write more concise code?
I do not think you need a design pattern in such a simple case. Each request will be processed by the corresponding method at Service layer.
In this scenario, the state pattern is more suitable.
State design pattern is used when an Object changes its behavior based on its internal state.
If we have to change behavior of an object based on its state, we can have a state variable in the Object and use if-else condition block to perform different actions based on the state. State pattern is used to provide a systematic and lose-coupled way to achieve this through Context and State implementations.
Try to implement based on your description:
public class StatePattern {
public static void main(String[] args) {
MonthPlan monthPlan = null; //= new MonthPlan(...)
StateContext stateContext = new StateContext();
if(monthPlan.isApproved()) {
stateContext.setState(new Approved());
}else {
stateContext.setState(new NotApproved());
}
}
}
class MonthPlan {
private boolean approved;
public boolean isApproved() {
return approved;
}
// other fields
}
interface State{
public void doAction(StateContext ctx);
}
class StateContext{
private State currentState;
public StateContext() {
//default Approved state, you can change if you want
currentState = new Approved();
}
public void setState(State state) {
currentState = state;
}
public void doAction() {
currentState.doAction(this);
}
}
class Approved implements State{
#Override
public void doAction(StateContext ctx) {
//actions using data from EditMonthPlanRequest
}
}
class NotApproved implements State{
#Override
public void doAction(StateContext ctx) {
//other actions using data from EditMonthPlanRequest
}
}
For this simple case, the Template Method pattern may apply:
abstract class AbstractRequest {
public void execute(...){
MonthPlan plan = getPlan(...);
if (plan.isApproved()) {
executeForApproved(plan);
} else {
executeForNonApproved(plan);
}
}
protected abstract void executeForApproved(MonthPlan plan);
protected abstract void executeForNonApproved(MonthPlan plan);
}
This way, you don't need to repeat the if statement and the getPlan(...) in each subclass:
class EditMonthPlanRequest extends AbstractRequest {
private long amount;
// other fields
protected void executeForApproved(MonthPlan plan){
...
}
protected void executeForNonApproved(MonthPlan plan){
...
}
}
If you want to do OOP, then replace conditionals with polymorphism.
In this example, it means splitting MonthPlan in two.
class ApprovedMonthPlan extends MonthPlan
class UnapprovedMonthPlan extends MonthPlan
Each class handles EditMonthPlanRequest in its own way.
I've a class which calls a service which returns makes different types of predictions. The API returns the confidence score for each label for each prediction type. Currently I call the service and then store all the scores returned by the service. However after doing some investigation, I've found that in my use case I'll need to change the thresholds for the labels returned by the service for one prediction type.
So for example: I called the service for predicting whether an image is of an animal or not and the service has two labels True or false.
{
predictedValue: True,
details: {
True: 0.65,
False: 0.35
}
}
The predictedValue field is what the prediction service owner thinks the image is based on it's thresholds. But my results from the API indicates that unless the True confidence is greater than 0.70 it never is an animal.
public class PredictionResults {
String prediction;
Map<String, Double> details;
}
public class PredictionServiceDataLoader {
public void getAndStorePredictionResults(String predictionType, String id) {
PredictionResults predictionResults = getPredictionByCallingPredictionService(predictionType);
saveResults(predictionResults, id);
}
}
Now since I want to override the results returned by the service and one way of doing that is:
public void getAndStorePredictionResults(String predictionType, String id) {
PredictionResults predictionResults = getPredictionByCallingPredictionService(predictionType);
if(predictionType.equals("detectAnimal")) {
//Override value based on threshold
if(predictionResults.getDetails().get("True") < 0.70) {
predictionResults.setPrediction("False");
}
}
saveResults(predictionResults, id);
}
Now if I want to remove the responsibility of changing the results based on threshold outside PredictionServiceDataLoader then I was thinking of implementing in the following way:
public interface PredictionResultsOverride {
public String getPreditionType();
public String getPredictionResults(PredictionResults predictionResults);
}
public class AnimalPredictionResultOverride implements PredictionResultsOverride {
#Override
public String getPreditionType() {
return "detectAnimal";
}
#Override
public String getPredictionResults(PredictionResults predictionResults) {
if(predictionResults.getDetails().get("True") < 0.70) {
predictionResults.setPrediction("False");
}
}
}
Then my PredictionServiceDataLoader will do delegate the responsibility of modifying the results to a different class in the following way:
public class PredictionServiceDataLoader {
#Autowired
private List<PredictionResultsOverride> predictionResultsImpl;
public void getAndStorePredictionResults(String predictionType, String id) {
PredictionResults predictionResults = getPredictionByCallingPredictionService(predictionType);
Optional<PredictionResultsOverride> predictionResultsOverrideImpl =
predictionResultsImpl.stream()
.filter(x -> x.getType().equals(predictionType))
.findFirst();
predictionResults = predictionResultsOverrideImpl.map(x -> x.getPredictionResults(predictionResults)).orElse(predictionResults);
saveResults(predictionResults, id);
}
}
Is this the best way to delegate the responsibility of overriding thresholds to a different class? Is there a different approach I can take? In my opinion the responsibility of PredictionServiceDataLoader class should be just to call the prediction service and store the results.
"In my opinion the responsibility of PredictionServiceDataLoader class should be just to call the prediction service and store the results."
You are correct, PredictionServiceDataLoader, ideally, should retrieve the results and store it.
Your requirement is to override the results based on some criteria. This can be taken care just before showing it to end-users (or before using it for further processing). This way, you will have raw results stored and can be referred in case of modified overridden criteria (for ex. true should be >=80%). If you store the results after overriding it then you will have to keep additinal details (like isOverridden, criteria etc ) along with the result.
I have two ways of saving data in my application: save to database and save to file. Since I don't want client code dealing with construction of objects I created a class that (to my understanding) is simple factory with a factory method. Code below:
public static DataPersister createDataPersister(Boolean saveToDb, Session session, String filename) {
if (saveToDb) {
return new DatabaseDataPersister(session);
} else {
return new FileDataPersister(filename);
}
}
With this setup client code doesn't have to deal with constructing anything or deciding whether to save to DB or file - it can just call a save() method on an object returned by the factory like so:
DataPersister dataPersister = DataPersisterSimpleFactory.createDataPersister(this.savetoDb, this.session, this.filename);
dataPersister.save(this.data);
My question is - is this solution breaking SOLID principles? In order to create e.g. a DatabaseDataPersister client code needs to pass on a filename parameter, and this implementation of DataPersister won't have any use of it. I feel like it doesn't sit right with something similar to Interface-segregation principle but not quite that.
And if the solution is indeed a code smell - how do I go about cleaning it?
The SOLID principle I think is in violation is DIP.
Your client classes, by having to depend on the static factory directly, have a compile-time dependency on actual implementations, DatabaseDataPersister and FileDataPersister, rather than just the abstraction DataPersister.
To solve, supply to the client the DataPersister you want them to use. The constructor is usually a good place for this:
public class ExampleClient {
private final DataPersister dataPersister;
public ExampleClient(DataPersister dataPersister) {
this.dataPersister = dataPersister;
}
public void methodThatUsesSave(){
dataPersister.save(data);
}
}
This code compiles without the concrete implementations, i.e. it has no dependency on them. The client also doesn't need to know the filename or session so it solves that code smell too.
We can decide which concrete implementation to give it at construction time, here I use your existing method:
DataPersister dataPersister = DataPersisterSimpleFactory.createDataPersister(this.savetoDb, this.session, this.filename);
ExampleClient example = new ExampleClient(dataPersister);
This is a perfect opportunity to use the factory pattern
interface DataPersister {
void persist(String s);
}
private class DatabasePersister implements DataPersister {
final Session session;
public DatabasePersister(Session session) {
this.session = session;
}
#Override
public void persist(String s) {
System.out.println("Persist to database: " + s);
}
}
private class FilePersister implements DataPersister {
final String filename;
public FilePersister(String filename) {
this.filename = filename;
}
#Override
public void persist(String s) {
System.out.println("Persist to file: " + s);
}
}
class PersisterFactory {
public DataPersister createDatabasePersister(Session session) {
return new DatabasePersister(session);
}
public DataPersister createFilePersister(String filename) {
return new FilePersister(filename);
}
}
public void test(String[] args) {
DataPersister databasePersister = new PersisterFactory().createDatabasePersister(new Session());
databasePersister.persist("Hello");
DataPersister filePersister = new PersisterFactory().createFilePersister("Hello");
filePersister.persist("Hello");
}
You already pass a bunch of stuff irrelevant to various persisters.
As it stands you need a method that takes a Session and one that takes a String and you're done. No need for a boolean, no need for useless params. That handles your decision making with no cruft.
Whether or not that's a good idea... I'm ambivalent. You're not saving much; might as well just have a static factory in each type so it's explicit in the code what type you're creating.
Consider what happens when you add a new persister, like a REST endpoint, that would take a URL (could be a string, could be an actual URL). You now need even more useless parameters etc. Or you could pass in a URI from the beginning, e.g., file:// or http:// and get around that problem.
There are any number of ways this could be done–I'm not convinced there's a "clearly correct" answer, and it may boil down to opinion.
Well the right solution here is combining the dependency injection from weston and the factory pattern from OldCurmudgeon.
public class ExampleClient {
private final DataPersister dataPersister;
public ExampleClient(DataPersister dataPersister) {
this.dataPersister = dataPersister;
}
public void methodThatUsesSave(){
dataPersister.save(data);
}
}
class PersisterFactory {
public DataPersister createDatabasePersister(Session session) {
return new DatabasePersister(session);
}
public DataPersister createFilePersister(String filename) {
return new FilePersister(filename);
}
}
The upper level code:
PersisterFactory = new PersisterFactory();
DataPersister dataPersister;
if (saveToDb)
dataPersister = PersisterFactory.createDatabasePersister(new Session());
else
dataPersister = PersisterFactory.createFilePersister("Hello");
ExampleClient example = new ExampleClient(dataPersister);
Usually the dataPersister comes from the DI container and the saveToDb comes from the config, but of course testing can be an exception.
In my Android application I have a class which gives me static string values; something like this:
public class VehicleInfo {
public static String getVehicleEnginePower(boolean isNew) {
return isNew ? "1800CC" : "1600CC";
}
}
Now I have another category, so I will have to pass another Boolean, and I will get the value I need. However, these categories will keep on increasing. So I looked into the Open/Closed principle which looks promising for quick enhancement. To ensure this I will make the VehicleInfo class as an Interface and then I will have other classes implement VehicleInfo.
public interface VehicleInfo {
String getVehicleEnginePower();
}
public class NewVehicle implements VehicleInfo {
#Override
public String getVehicleEnginePower() {
return "1800CC";
}
}
and the other category classes will also be something like this. In this way I will have to add another class for all the new categories.
The question I wanted to ask is: is there a way that I can have single instance of this interface? Because in the whole application flow, a user will only be able to see one category until he switches to another category.
I don't want to instantiate these classes at multiple points. To clarify my question, I want to do something like this at the start of my application:
if (isNew) {
VehicleInfo vehicleInfor = new NewVehicle();
}
And in the whole application, whenever I call VehicleInfo.getVehicleEnginePower, it should always return engine power from the NewVehicle class.
Is something like this possible? Or am I just being silly and I will have to instantiate this interface on multiple points?
Maybe you need a singleton here
public class VehicleInfoManager {
private static VehicleInfoManager INSTANCE = new VehicleInfoManager();
private VehicleInfo currentVehicleInfo;
public static VehicleInfoManager getInstance() {
return INSTANCE;
}
public void setCurrentVehicleInfo(VehicleInfo info) {
this.currentVehicleInfo = info;
}
public String getVehicleEnginePower() {
return this.currentVehicleInfo.getVehicleEnginePower();
}
private VehicleInfoManager() {
// Constructor private by default
}
}
Then you can call it from everywhere like this
VehicleInfoManager.getInstance().getVehicleEnginePower()
//Or set current info like this
VehicleInfoManager.getInstance().setCurrentVehicleInfo(new NewVehicle())
Just be careful as currentVehicleInfo is null by default so you need to handle null pointer cases.
If I understand your question correctly.
My solution to this would be Enum
public enum VehicleEnginePower {
NEW ("1800CC"),
OLD ("1600CC"),
private final String name;
private Modes(String s) {
name = s;
}
public String toString() {
return this.name;
}
}
Then you can do
if (isNew) {
String powerOfEngine = VehicleEnginePower.NEW.toString();
}