In few classes I have similar else if statements that I wanted to replace using the command pattern. The idea was to externalize the else if bodies and depending on what service calls it use its repositories. Problem is that I can't seem to find a way to get the repositories injected into my class. Ill explain better in the example:
part of code that should use command pattern:
private HashMap<String, BnResponseHandler> commandMap = new HashMap<>();
for (CustomerDelivery customerDelivery : list) {
commandMap.put("true", new SuccessfulResponse(customerDelivery));
commandMap.put("1", new ResponseCodeOne(customerDelivery));
commandMap.put("2", new ResponseCodeTwo(customerDelivery));
commandMap.put("3", new ResponseCodeThree(customerDelivery));
BnResponseHandler bnResponseHandler = new DefaultHandler(customerDelivery);
if(response.isSuccessful()){
commandMap.get(String.valueOf(response.isSuccessful())).handle();
} else if (response.getResponseCode() != null
&& !response.getResponseCode().equals("")){
commandMap.get(response.getResponseCode()).handle();
} else {
bnResponseHandler.handle();
}
}
the interface:
public interface BnResponseHandler {
void handle();
}
and the interface implementation:
#Component
public class ResponseCodeOne implements BnResponseHandler {
#Autowired
private FabricationRepository fabricationRepo;
private Fabrication fabrication;
#Autowired
private MovementsRepository movementsRepository;
private StockMovements stockMovements;
#Autowired
private CustomerDeliveryRepository customerDeliveryRepo;
private CustomerDelivery customerDelivery;
public ResponseCodeOne() {
}
public ResponseCodeOne(Fabrication fabrication) {
this.fabrication = fabrication;
}
public ResponseCodeOne(StockMovements stockMovements) {
this.stockMovements = stockMovements;
}
public ResponseCodeOne(CustomerDelivery customerDelivery) {
this.customerDelivery = customerDelivery;
}
#Override
public void handle() {
if (fabrication != null) {
fabrication.setFG_ETAT("D");
fabrication.setLB_ETAT("");
fabricationRepo.save(fabrication);
} else if (stockMovements != null) {
stockMovements.setFG_ETAT("D");
stockMovements.setLB_ETAT("");
movementsRepository.save(stockMovements);
} else if (customerDelivery != null) {
customerDelivery.setFG_ETAT("D");
customerDelivery.setLB_ETAT("");
customerDeliveryRepo.save(customerDelivery);
}
}
}
So the big picture was to set ResponseCode classes for every possible response code I could get (in this case 1) and inside of those classes do some business logic that depends on the repository beans. It should also be flexible so that I can use the ResponseCodeOne class for multiple different cases(meaning fabrication, stockMovements and customerDelivery). The problem I am having is that my repositories don't get injected this way and I keep on getting an null pointer exception. Is there a way to cleanly inject my repository beans?
The main issue I see is that you are creating your own instances of your response code classes using the new keyword, which means that Spring will not autowire them. To get them successfully autowired you will need to inject instances of them into the class where your for loop is located. However, this introduces a secondary issue where you can no longer provide an object from your for loop to the constructor of your response code instances. To solve this problem you can pass the Fabrication/StockMovements/CustomerDelivery instance as an argument to handle().
Related
I am somewhat new to Spring and have recently generated a JHipster monolith application with the WebFlux option. My current aim is to make it compatible with Firestore and implement some missing features like inserting document references. To do so, I am currently having the following structure:
A domain object class "Device" which holds a field String firmwareType;
A domain object class "FirmwareType"
A DTO object DeviceDTO which holds a field FirmwareType firmwareType;
Correspondingly, I also have the corresponding Repository (extending FirestoreReactiveRepository which extends ReactiveCrudRepository) and Controller implementations, which all work fine. To perform the conversion from a "full object" of FirmwareType in the DTO-object to a String firmwareTypeId; in the Device-object, I implemented a MapStruct Mapper:
#Mapper(unmappedTargetPolicy = org.mapstruct.ReportingPolicy.IGNORE, componentModel = "spring")
public abstract class DeviceMapper {
private final Logger logger = LoggerFactory.getLogger(DeviceMapper.class);
#Autowired
protected FirmwareTypeRepository fwTypeRepo;
public abstract Device dtoToDevice(DeviceDTO deviceDTO);
public abstract DeviceDTO deviceToDto(Device device);
public abstract List<DeviceDTO> devicesToDTOs(List<Device> devices);
public abstract List<Device> dtosToDevices(List<DeviceDTO> dtos);
public String map(FirmwareType value) {
if (value == null || value.getId() == null || value.getId().isEmpty()) {
return null;
}
return value.getId();
}
public FirmwareType map(String value) {
if (value == null || value.isEmpty()) {
return null;
}
return fwTypeRepo.findById(value).block(); // <<-- this gets stuck!
}
}
The FirmwareTypeRepository which is autowired as fwTypeRepo field:
#Repository
public interface FirmwareTypeRepository extends FirestoreReactiveRepository<FirmwareType> {
Mono<FirmwareType> findById(String id);
}
The corresponding map functions get called perfectly fine, but the fwTypeRepo.findById(..) call in the marked line (third-last line) seems to get stuck somewhere and never returns or throws an error. When the "fwTypeRepo" via its Controller-endpoint is called, it works without any issues.
I suppose it must be some kind of calling context issue or something? Is there another way to force a result by Mono synchronously than block?
Thanks for your help in advance, everyone!
Edit: At this point, I am sure it has something to do with Autowiring the Repository. It seems to not correctly do so / use the correct instance. While a customized Interface+Impl is called correctly, the underlying logic (from FirestoreReactive/ReactiveCrudRepository) doesn't seem to supply data correctly (also when #Autowire is used in other components!). I found some hints pointing at the package-structure but (i.e. Application class needs to be in a root package) but that isn't an issue.
Mapstruct is not reactive as i know so this approach won't work, you'll need mapstruct to return a mono that builds the object itself but that wouldn't make sense as it's a mapping lib which is only for doing blocking things.
Could try use 2 Mono/Mappers, 1 for each DB call and then just Mono.zip(dbCall1, dbCall2) and set the the mapped db call output into the other objects field.
var call1 = Mono.fromFuture(() -> db.loadObject1()).map(o -> mapper1.map(o));
var call2 = Mono.fromFuture(() -> db.loadObject2()).map(o -> mapper2.map(o));
Mono.zip(call1, call2)
.map(t -> {
var o1 = t.getT1();
var o2 = t.getT2();
o1.setField(o2);
});
I have the following Java method:
public Appointment addAppointment(String client, Appointment appointment) {
String esbUrl = new ESBUrlHelper().getEsbUrl();
AppointmentClient appointmentClient = AppointmentClientFactory.getUnsecuredClient(esbUrl);
if (appointment.getId() == null) {
outputAppointment = appointmentClient.addAppointment(client, appointment);
}
return outputAppointment;
}
The method above makes a call to a third party REST client called appointmentClient.
The issue that I am having is that this is causing my test to fail.
How can I mock the appointmentClientobject within my unit tests?
Currently my test looks as follows:
#Test
public void shouldAddAppointment() {
// act
Appointment appointment = appointmentService.addAppointment(CLIENT_STRING, appointmentMock)
// assert
assertNotNull(appointment);
}
But I get the following error at line appointmentClient.addAppointment(client, appointment);:
org.jboss.resteasy.client.exception.ResteasyIOException: IOException
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
I want to mock something like as follows:
Mockito.when(appointmentClient.addAppointment(client, appointment)).thenReturn(appointmentMock);
You can try using PowerMockito for this.
First, you need to mock the static method call of AppointmentClientFactory class like below:
PowerMockito.mockStatic(AppointmentClientFactory.class);
PowerMockito.when(AppointmentClientFactory,"getUnsecuredClient",esbUrl).thenReturn(appointmentClient);
And also, when you use PowerMockito for mocking static methods, add the #PrepareForTest({AppointmentClientFactory.class}) annotation to the test class.
With your current code, the only way of mocking a call to AppointmentClientFactory#getUnsecuredClient would be using PowerMock, since the factory method is static. This is due to the hard coupling between your calling code addAppointment and the dependency here (i.e. the AppointmentClientFactory).
If I were you, I would avoid that as PowerMock is not the best way to do tests. Instead, what I would do, would be to inject the AppointmentClientFactory as a dependency thus allowing me to mock an instance of it during my tests.
This should be the best approach in twofold manner. Firstly, because you achieve less tightly coupled code and secondly because you do not need to use PowerMock for your unit-tests.
It's not impossible with Mockito. But your original problem is static method of AppointmentClientFactory. You definitely should change this method to the instance method (at least for better architecture) , for example:
public class AppointmentClientFactory {
public AppointmentClient getUnsecuredClient(String url) {
return new AppointmentClient(); //your implementation
}
}
Then your AppointmentService will look like (or close to it):
public class AppointmentService {
private final AppointmentClientFactory factory;
public AppointmentService() {
this(new AppointmentClientFactory());
}
public AppointmentService(AppointmentClientFactory factory) {
this.factory = factory;
}
public Appointment addAppointment(String client, Appointment appointment) {
String esbUrl = "";
Appointment outputAppointment = null;
AppointmentClient appointmentClient = new AppointmentClientFactory().getUnsecuredClient(esbUrl);
if (appointment.getId() == null) {
outputAppointment = appointmentClient.addAppointment(client, appointment);
}
return outputAppointment;
}
}
And then you will could write test like:
public class AppointmentTest {
private final String CLIENT_STRING = "";
#Test
public void shouldAddAppointment() {
AppointmentClientFactory clientFactory = Mockito.mock(AppointmentClientFactory.class);
AppointmentClient mockedClient = Mockito.mock(AppointmentClient.class);
AppointmentService service = new AppointmentService(clientFactory);
Appointment appointmentMock = new Appointment();
when(clientFactory.getUnsecuredClient(any())).thenReturn(mockedClient);
Appointment appointment = service.addAppointment(CLIENT_STRING, appointmentMock);
assertNotNull(appointment);
}
}
When I start the application, I need to load properties from different sources: war, file system, database, and JVM. I need to load properties once and use them within running my application. I do not need to refresh it. I don't have DI - it is a simple java application with singletons. I decide to create AppProperties singleton and load properties when starting the application. It is the best solution by the current time for me(I hope somebody makes the best solution). It is my Singleton:
import java.io.InputStream;
import java.util.Properties;
public class AppProperties {
private static AppProperties instance;
private Properties propertiesFromWar;
private Properties propertiesFromFile;
private Properties propertiesFromDB;
private AppProperties() {
propertiesFromWar = new Properties();
try {
propertiesFromWar.load(getPropertiesAsInputStreamFromWar());
propertiesFromFile.load(getPropertiesAsInputStreamFromFile());
propertiesFromDB.load(getPropertiesAsInputStreamFromDB());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private InputStream getPropertiesAsInputStreamFromDB() {
//some implementation
return null;
}
private InputStream getPropertiesAsInputStreamFromFile() {
//some implementation
return null;
}
private InputStream getPropertiesAsInputStreamFromWar() {
return getClass().getResourceAsStream("META-INF/application.properties");
}
public static AppProperties getInstance() {
if (instance == null) {
instance = new AppProperties();
}
return instance;
}
public String getProperty(String key) {
String value;
value = System.getProperty(key);
if (value == null) {
value = propertiesFromDB.getProperty(key);
if (value == null) {
value = propertiesFromFile.getProperty(key);
if (value == null) {
value = propertiesFromWar.getProperty(key);
}
}
}
return value;
}
}
But I do not understand, How can I use it in tests. Because I hardcode paths for aplication.properties files. And when I will create this instance in the tests, I will create AppProperties with real properties.
I tried to add a public method like load(filePath). But with this method, it will be not a singleton. If somebody will call this method in another place of application - my singleton will be reloaded with new data. Now I have 2 problems.
If I add load() method - it will be dangerous for reloading data. But I can use it in tests.
If I do not add this method - I can not test it.
P.S I read this article The Little Singleton
But I do not understand some moments. If I have singleton with private constructor, I can not extend it like in article.
In your test resources directory, create META-INF directory. Here create a file application.properties and add some properties for testing purposes in it.
Make sure the above directory is in the classpath when you will run the tests. This way, when getPropertiesAsInputStreamFromWar() is called, it will look for META-INF/application.properties in the classpath.
Being tests allow specifying JVM launch arguments, this can be "solved" pretty easily.
This also adds some flexibility.
java -DpropertiesPath="..." -jar yourJar.jar
And, adapting your code
private InputStream getPropertiesAsInputStreamFromWar() {
final String propertiesPath = Objects.requireNonNull(System.getProperty("propertiesPath"));
return getClass().getResourceAsStream(propertiesPath);
}
Instead of requireNonNull, you could use a default value, e.g.
META-INF/application.properties.
I have multiple classes which implement an interface and return an Object.
public interface DataFetcher {
Data getData(Info info);
}
public class Data {
private String name;
private String value;
}
#Component
public class DataPointA implements DataFetcher {
#Override
public Data getData(Info info) {
//..Do some processing
return new Data("SomeName", valueComputed);
}
}
Now I have about 20 data points which implement the DataFetcher class and returns the Data Object.
I autowire all the data points to a class and based on certain conditions I use certain data points.
#Component
public class DataComputer {
#Autowired
private DataPointA dataPointA;
#Autowired
private DataPointB dataPointB;
.
.
.
public void computeData(String inputType, Info info) {
List<DataFetcher> dataFecthers;
switch(inputType) {
case "typeA" : dataFecthers = ImmutableList.of(dataPointA, dataPointB);
break;
.
.
.
case "typeD" : dataFecthers = ImmutableList.of(dataPointE, dataPointF, dataPointG);
break;
}
dataFetcher.forEach(dataPoint -> {
//Do some processing with dataPoint.getData(info)
})
}
}
As can be seen DataComputer class will have a whole list of dependencies which can become unmanageable. Also the data point to be used based on the inputType is known before hand so this can be extracted out. This was my attempt at doing it:
#Component
public class DataComputationPointDecider {
#Autowired
private DataPointA dataPointA;
#Autowired
private DataPointB dataPointB;
.
.
.
#Bean
public Map<String, List<DataFetcher>> getDataComputationPoints() {
return new ImmutableMap.Builder<String, List<DataFetcher>>()
.put("typeA", ImmutableList.of(dataPointA, dataPointB))
.put("typeD", ImmutableList.of(dataPointE, dataPointF, dataPointG))
.build();
}
}
And then my DataComputer dependencies reduces:
#Component
public class DataComputer {
#Autowired
private Map<String, List<DataFetcher>> dataComputationPoints;
public void computeData(String inputType, Info info) {
List<DataFetcher> dataFecthers = dataComputationPoints.get(inputType);
dataFetcher.forEach(dataPoint -> {
//Do some processing with dataPoint.getData(info)
})
}
}
Is there a better way to design this?
I don't see anything majorly wrong in your approach. But I'm suggesting one more option.
Instead of maintaining a map that maps an inputType with a list of DataFetcher, you can make a DataFetcher decide or say what input type(s) it can handle.
But this needs changing the interface of DataFetcher as
public interface DataFetcher {
boolean canHandle(String inputType);
Data getData(Info info);
}
The implementations would look like
#Component
public class DataPointA implements DataFetcher {
#Override
boolean canHandle(String inputType) {
return "typeA".equals(inputType);
}
#Override
public Data getData(Info info) {
//..Do some processing
return new Data("SomeName", valueComputed);
}
}
Then you can just inject all DataFetcher as one single list (and need not add one #Autowired field for each one) and process it as
#Autowired
List<DataFetcher> dataFetchers;
...
dataFetchers.stream()
.filter(dataFetcher -> dataFetcher.canHandle(inputType))
.forEach(dataFetcher.getData(info));
Advantages:
In your current approach, if you add a new DataFetcher implementation, you need to add a #AutoWired field/member and modify the (getDataComputationPoints)map. But, with this, the inputTypes a DataFetcher can handle is specified with that itself and hence you just need to add new classes for new input types.
Reference
Autowire reference beans into list by type
UPDATE:
Disadvantages
The input types are specified inside the class means that you cannot easily find the list of DataFetchers (data points) for a given input type.
If you need to remove support for an inputType, then again you need to visit each implementation (to remove that inputType from canHandle). In your approach, it is about simply remove one map entry.
Have you considered using the Factory pattern? This allows you to submit a request for an object instance based on certain criteria.
I am writing endpoint unit tests and for most of those there is an external web service that should be mocked, or a couple of them.
At first, i was creating mocks within tests which was okay when an endpoint test used only one external service, the mock creation was basically one liner.
As use cases became more complex, i needed to mock couple of services and exceptions for a single endpoint test.
I have put these mocks creation behind factories that all extend single factory and used builder pattern.
Within that base factory there is an inner class which i used as a builder for MockWebServiceServer.
protected class MultiStepMockBuilder {
private List<Object> mockActions = new ArrayList<Object>();
private WebServiceGatewaySupport gatewaySupport;
protected MultiStepMockBuilder(WebServiceGatewaySupport gatewaySupport) {
this.gatewaySupport = gatewaySupport;
}
protected MultiStepMockBuilder exception(RuntimeException exception) {
mockActions.add(exception);
return this;
}
protected MultiStepMockBuilder resource(Resource resource) {
mockActions.add(resource);
return this;
}
protected MockWebServiceServer build() {
MockWebServiceServer server = MockWebServiceServer.createServer(gatewaySupport);
for(Object mock: mockActions) {
if (mock instanceof RuntimeException) {
server.expect(anything()).andRespond(withException((RuntimeException)mock));
}
else if (mock instanceof Resource)
{
try
{
server.expect(anything()).andRespond(withSoapEnvelope((Resource) mock));
} catch (IOException e) {e.printStackTrace();}
}
else
throw new RuntimeException("unusuported mock action");
}
return server;
}
}
}
So i can now do something like this to create mock:
return new MultiStepMockBuilder(gatewaySupport).resource(success).exception(new WebServiceIOException("reserve timeout"))
.resource(invalidMsisdn)
.build();
The issue i have with this implementation is dependence on instanceof operator which i never use outside of equals.
Is there an alternative way to instanceof operator in this scenario ? From the questions on topic of instanceof everybody argues it should only be used within equals and therefore i have feeling that this is 'dirty' solution.
Is there an alternative to instanceof operator, within Spring or as a different design, while keeping fluent interface for mocks creation ?
I don't know Spring well enough to comment specifically on this particular area, but to me, this just seems like a design thing. Generally, when you are faced with using instanceof, it means that you need to know the type, but you don't have the type. It is generally the case that we might need to refactor in order to achieve a more cohesive design that avoids this kind of problem.
The root of where the type information is being lost, is in the List of mock actions, which are currently just being stored as a List of Objects. One way to help with this then, is to look at the type of the List and consider if there is a better type that could be stored in the List that might help us later. So we might end up with a refactoring something like this.
private List<MockAction> mockActions = new ArrayList<MockAction>();
Of course, then we have to decide what a MockAction actually is, as we've just made it up. Maybe something like this:
interface MockAction {
void performAction(MockWebServiceServer server);
}
So, we've just created this MockAction interface, and we've decided that instead of the caller performing the action - we're going to pass the server into it and ask the MockAction to perform itself. If we do this, then there will be no need for instanceof - because particular types of MockActions will know what they contain.
So, what types of MockActions do we need?
class ExceptionAction implements MockAction {
private final Exception exception;
private ExceptionAction(final Exception exception) {
this.exception = exception;
}
public void performAction(final MockWebServiceServer server) {
server.expect(anything()).andRespond(withException(exception);
}
}
class ResourceAction implements MockAction {
private final Resource resource;
private ResourceAction(final Resource resource) {
this.resource = resource;
}
public void performAction(final MockWebServiceServer server) {
/* I've left out the exception handling */
server.expect(anything()).andRespond(withSoapEnvelope(resource));
}
}
Ok, so now we've gotten to this point, there are a couple of loose ends.
We're still adding exceptions to the list of MockActions - but we need to change the add methods to make sure we put the right thing in the list. The new versions of these methods might look something like this:
protected MultiStepMockBuilder exception(RuntimeException exception) {
mockActions.add(new ExceptionAction(exception));
return this;
}
protected MultiStepMockBuilder resource(Resource resource) {
mockActions.add(new ResourceAction(resource));
return this;
}
So, now we've left our interface the same, but we're wrapping the resource or exception as they're added to the list so that we have the type specificity we need later on.
And then finally, we need to refactor our method that actually makes the calls, which now looks something like this - which is much simpler and cleaner.
protected MockWebServiceServer build() {
MockWebServiceServer server = MockWebServiceServer.createServer(gatewaySupport);
for(MockAction action: mockActions) {
action.performAction(server);
}
return server;
}