Is it able to write this code embedded into Optional method chain:
Optional<Application> appOpt = this.applicationDao.findById(application.getCode());
Application app = appOpt.orElse(Application::new);
if (!appOpt.isPresent()) {
app.get().setUserCreation("user");
app.get().setTimestampCreation(new Date());
}
I'd like to avoud using again the previous appOpt object. I would like to embed all this logic inside an Optional method chain.
I guess there should be another more elegant way to get it.
I've tried to play with ifPresent but it returns void and so I'm not able to chain orElse method:
appOpt.ifPresent(a -> {
a.setUserCreation("userCreation"));
app.setTimestampCreation(new Date());
})
.orElse(Application::new);
I hope I've explained so well.
Any ideas?
After looking again at your original code, it looks like the logic should run if the Optional is empty:
Application application = appOpt.orElseGet(() -> {
Application app = new Application();
app.setUserCreation("userCreation"));
app.setTimestampCreation(new Date());
return app;
});
Related
I'm making a test for a service with a mock.
The problem is to create and inject instance directly from the class to test.
The source is shown below.
public OrderOutDTO createOrder(OrderSessionDTO orderSessionDTO) {
Order order = orderRepository.save(new Order(orderSessionDTO));
CreateOrderResDTO callServiceOrder = callService.createOrder(new CreateOrderReqDTO(order));
CreateOrderReqDTO createOrderReqDTO = mock(CreateOrderReqDTO.class);
createTrace(order, callServiceOrder.getData().getReceipt().getTransactionHash(), Trace.PUBLIC);
return new OrderOutDTO(order, null);
}
and test source is shown below.
#Test
public void createOrder() {
// given
CallService callService = mock(CallService.class);
CreateOrderResDataDTO createOrderResDataDTO = mock(CreateOrderResDataDTO.class);
// when
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
OrderOutDTO order = orderService.createOrder(orderSessionDTO);
// then
assertThat(order, is(Matchers.notNullValue()));
assertThat(order.getOrder(), is(Matchers.notNullValue()));
assertThat(order.getOrder().getReceiver().getName(), is("test"));
}
I thought this test would finish well. But in the code below, it returned null and failed.
// callService.createOrder(new CreateOrderReqDTO(order)) return null
CreateOrderResDTO callServiceOrder = callService.createOrder(new CreateOrderReqDTO(order));
It doesn't seem to recognize it because the service injects a new instance. I want the mock data returned. What should I do?
In the following line you're mocking behavior on createOrderReqDTO as param:
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
whereas further, you're passing some other object:
OrderOutDTO order = orderService.createOrder(orderSessionDTO);
This behavior is not recognized, you would have to pass the same thing you mocked before.
I found it myself!
I use argumentMatchers.
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
to
when(callService.createOrder(any())).thenReturn(createOrderResDTO);
thank you.
I have some problems with using Optional.ifPresent statement. I would like to reduce number of NullPointerExceptions, so I decided to use Optional values.
Also I am trying to avoid a ladder of if statements anti-pattern.
So I implemented Optional.isPresent statement. But it's not really that what I expected.
Please look at these listings:
This is a part of my service:
if (getAllComputerProducers().isPresent()) {
if (isComputerProducerAlreadyExist(computerProducer))
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
computerProducerRepository.save(computerProducer);
return new ResponseEntity<>(HttpStatus.CREATED);
getAllComputerProducers function looks like that:
private Optional<List<ComputerProducer>> getAllComputerProducers() {
return Optional.ofNullable(computerProducerRepository.findAll());
}
As you can see, this function returns Optional of List.
The isComputerProducerAlreadyExist function is implemented like that:
private boolean isComputerProducerAlreadyExist(ComputerProducer computerProducer) {
return getAllComputerProducers()
.get()
.stream()
.anyMatch(producer -> producer.getProducerName()
.equalsIgnoreCase(computerProducer.getProducerName()));
}
It's so much code and I believe that it could be made simpler.
My target is to reduce code to one line command like:
getAllCimputerProducers().ifPresent(***and-here-some-anyMatch-boolean-function***)
but I can't insert there a function which returns something. How can I do it?
Regards to everyone :)
You could try something like
private boolean isComputerProducerAlreadyExist(ComputerProducer computerProducer){
return this.getAllComputerProducers()
.map((List<ComputerProducer> computerProducers) -> computerProducers.stream()
.anyMatch(producer -> producer.getProducerName().equalsIgnoreCase(computerProducer.getProducerName())))
.orElse(Boolean.FALSE);
}
Or instead of loading all computer producers load only the ones using its name.
private boolean isComputerProducerAlreadyExist(ComputerProducer computerProducer){
return computerProducerRepository.findByName(computerProducer.getProducerName()).isEmpty();
}
And as far as I know Spring supports also "exist" methods for repositories without even the need to load the Entity.
The following should work
Predicate<ComputerProducer> cpPredicate = producer -> producer.getProducerName()
.equalsIgnoreCase(computerProducer.getProducerName());
boolean compProdExists = getAllCimputerProducers()
.map(list -> list.stream()
.filter(cpPredicate)
.findFirst()))
.isPresent();
You can pass the computerProducer.getProducerName() to repository to get the existing record. Method name will be 'findByProducerName(String producerName)', if producerName has unique constraint, return type will be Optional<ComputerProducer>, else Optional<List<ComputerProducer>>. However, JPA returns empty list instead of null, so optional on list is not required.
I want to implement a typical rest POST call in Lagom. The POST creates an object, and returns it, with a status code of 201.
However, the default return code is 200. It is possible to set a status code, as shown here (https://www.lagomframework.com/documentation/1.3.x/java/ServiceImplementation.html#Handling-headers).
However, I cannot figure out how to do it for a more complicated case. My create is asynchronious, and I return an object instead of a String.
This is the code I have:
#Override
public HeaderServiceCall<OrderRequest.CreateOrderRequest, Order> createOrder() {
UUID orderId = UUID.randomUUID();
ResponseHeader responseHeader = ResponseHeader.OK.withStatus(201);
return (requestHeader, request) -> {
CompletionStage<Order> stage = registry.refFor(OrderEntity.class, orderId.toString())
.ask(buildCreateOrder(orderId, request))
.thenApply(reply -> toApi(reply));
return CompletableFuture.completedFuture(Pair.create(responseHeader, stage.toCompletableFuture()));
};
}
However, the return value should be Pair<ResponseHeader, Order>, not Pair<ResponseHeader, CompletionStage<Order>> which I have now, so it does not compile.
I could of course extract the Order myself, by putting the completionStage into an CompletableFuture and getting that, but that would make the call synchronous and force me to deal with InterruptExceptions etc, which seems a bit complex for something that should be trivial.
What is the correct way to set a status code in Lagom?
You almost have it solved. Instead of creating a new completedFuture you could compose stage with a lambda that builds the final Pair like this:
return stage.thenApply( order -> Pair.create(responseHeader, order));
And putting all the pieces together:
registry.refFor(OrderEntity.class, orderId.toString())
.ask(buildCreateOrder(orderId, request))
.thenApply( reply -> toApi(reply));
.thenApply( order -> Pair.create(responseHeader, order));
Is there any good documentation how to invoke a lambda function from a lambda function written in java?
Is there a difference between invoking a lambda function from a lambda function or invoke from a normal java application?
The only thing that I found is the normal AWS Java SDK doc.
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html
Would be happy if someone could help me.
Yes, you can call lambdas normally from lambdas, just as you would if your code was executing on a host somewhere.
You'll have an additional step of ensuring that the lambda executing the call to another lambda has permissions to execute other lambda functions (the permission is called "lambda:InvokeFunction").
The rest of the steps are the same as regular java using the AWS SDK, you instantiate an AWSLambdaClient object, set your credentials and settings (region, etc.) and then create an InvokeRequest object which is the sub-lambda to be called with the appropriate payload.
Here's some sample java code which does exactly this, but it's also part of the standard sdk docs.
And also keep in mind that you'll still be subject to the original timeout for the first lambda, otherwise execution will be stopped.
Here's the relevant code snippets that you should be able to work from, I've made a change to how the second lamdba is called in terms of credentials - your can pass the credentials used to invoke the first lambda implicitly into the second one, which is probably a bit easier and more maintainable - you just need to ensure that the first lambda call gets the credentials and the rest will inherit them.
Region region;
AWSLambdaClient lambdaClient;
lambdaClient = new AWSLambdaClient(new DefaultAWSCredentialsProviderChain());
region = Region.getRegion(Regions.fromName(regionName));
lambdaClient.setRegion(region);
InvokeRequest invokeRequest = new InvokeRequest();
invokeRequest.setFunctionName(FunctionName);
invokeRequest.setPayload(ipInput);
returnDetails = byteBufferToString(
lambdaClient.invoke(invokeRequest).getPayload(),
Charset.forName("UTF-8"),logger);
edit: I should also point out that depending on your architecture, there's probably much cleaner options like using SQS, or depending on how simple your nested lambdas are, inlining them directly inside each other to avoid the extra call.
A lot of the used API functions are deprecated and the AWS docu is ... I share a new implemented example. The Lambda function "updateS3Chart" calls another Lambda function "AsyncUpdate" asynchronous:
public class LambdaInvoker {
static final Logger logger = LogManager.getLogger(LambdaInvoker.class);
static final String LambdaFunctionName = "AsyncUpdate";
private class AsyncLambdaHandler implements AsyncHandler<InvokeRequest, InvokeResult>
{
public void onSuccess(InvokeRequest req, InvokeResult res) {
logger.debug("\nLambda function returned:");
ByteBuffer response_payload = res.getPayload();
logger.debug(new String(response_payload.array()));
}
public void onError(Exception e) {
logger.debug(e.getMessage());
}
}
public void updateS3Chart(UpdateS3ChartRequest updateS3ChartRequest) {
Gson gson = new Gson();
try {
//issue: aws region is not set to debug-time. solution for eclipse:
//environment variable is set by lambda container or eclipse ide environment variables
//use instead for eclipse debugging: project -> Run as -> Run Configurations -> Environment -> Add variable: "AWS_REGION": "eu-central-1"
AWSLambdaAsync lambda = AWSLambdaAsyncClientBuilder.defaultClient(); //Default async client using the DefaultAWSCredentialsProviderChain and DefaultAwsRegionProviderChain chain
InvokeRequest req = new InvokeRequest()
.withFunctionName(LambdaFunctionName)
.withPayload(gson.toJson(updateS3ChartRequest));
Future<InvokeResult> future_res = lambda.invokeAsync(req, new AsyncLambdaHandler());
logger.debug("Waiting for async callback");
while (!future_res.isDone() && !future_res.isCancelled()) {
// perform some other tasks...
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
logger.debug("Thread.sleep() was interrupted!");
}
System.out.print(".");
}
} catch (Exception e) {
logger.fatal("Execute async lambda function: " + LambdaFunctionName + " failed: " + e.getMessage());
}
}
}
You have to set your AWS region as system property in your IDE for debugging (see comment in source code for Eclipse). UpdateS3ChartRequest is simple POJO with property set/get.
I set up ext direct for my Spring MVC app using extdirectspring. I am able to retrieve primitives and Strings and use them in ext.js. When I try to retrieve a list of objects, I am getting "undefined" on the javascript side. Is there anything special that I need to do to the Person class to get it to work?
I annotated the following code:
#ExtDirectMethod(ExtDirectMethodType.STORE_READ)
#Override
public Collection<Person> getPeople(String groupId) {
Group group = GroupManager.getGroup(groupId);
return group.getPeopleList();
}
This is what I am using on the client side:
directory.getPeople(id, function(result) {
console.log(result);
});
Here is what app.js looks like:
Ext.ns('Ext.app');
Ext.app.REMOTING_API = {
"actions":{
"directory":[{
"name":"getID","len":0
},{
"name":"getPeople","len":1
}
]},
"type":"remoting",
"url":"/test/action/router"
};
Have you tried using the ExtDirectStoreResponse class? It does use a collection but also manages some useful values for use in the store.
#ExtDirectMethod(ExtDirectMethodType.STORE_READ)
public ExtDirectStoreResponse<Person> load()
{
Group group = GroupManager.getGroup(groupId);
Collection<Person> people = group.getPeopleList();
return new ExtDirectStoreResponse<Person>(people.size(), people);
}
This is the approach to use when using the STORE_READ. That method annotation is expecting the request to come in matching values in the ExtDirectStoreReadRequest class. This is the reference to use when doing a store read. https://github.com/ralscha/extdirectspring/wiki/Store-Read-Method
Also, instead of calling the method directly, you would set up an ExtJs store and call
store.load();