Shorter way to assert boolean set in for loop - java

Is there a way to make the code below simpler and shorter?
boolean clicked = false;
for (WebElement anchor : anchorLinksForProducts) {
if (anchor.getAttribute("href").contains(id)) {
anchor.click();
clicked = true;
break;
}
}
Assert.assertTrue(clicked, "Could not find a valid product link with id : " + id);

A refinement to #Mureinik's answer.
anchorLinksForProducts.stream()
.filter(a -> a.getAttribute("href").contains(id))
.findFirst()
.ifPresentOrElse​(
WebElement::click,
() -> fail("Could not find a valid product link with id : " + id)
);
There's a little more overhead in this code, but that is always the case with streams and not a problem if it is test code.

A stream should make the code shorter:
Optional<WebElement> anchor =
anchorLinksForProducts.stream()
.filter(a -> a.getAttribute("href").contains(id))
.findFirst();
if (anchor.isPresent()) {
anchor.get().click();
} else {
fail("Could not find a valid product link with id : " + id);
}

Related

Comparing the contents of two Treemaps

I have two TreeMaps that I want to compare.
I currently have it written down like below but I feel like this could be written more efficiently. I tried looking in to comparators, but I don't think that's something I can use for my use-case.
The maps are Treemaps because the key must be case-insensitive.
public void theseRulesAreTheSame() {
List<String> failures = new ArrayList<>();
TreeMap<String, NSG> configNsgs = platformConfiguration.getAzure().nsgs();
configNsgs.forEach((name, nsg) -> {
assertThat(azureAdapter.doesNsgExistInAzure(name))
.as("Unable to find network security group " + name + " in Azure.").isTrue();
List<SecurityRulesItem> configSecurityRules = nsg.getSecurityRules();
TreeMap<String, Object> azureSecurityRules = azureAdapter
.getSecurityRulesForNsg(name);
assertThat(configSecurityRules.size())
.as("The nymber of security rules in Azure does not correspond to the number of security rules in the configuration!")
.isEqualTo(azureSecurityRules.size());
configSecurityRules.forEach(configSecurityRule -> {
SecurityRuleInner azureSecurityRule = (SecurityRuleInner) azureSecurityRules
.get(configSecurityRule.getRuleName());
logger.info(
"Checking security rule " + configSecurityRule.getRuleName()
+ " in network security group "
+ nsg.getName());
if (null == azureSecurityRule) {
logFailure(failures, null, configSecurityRule.getRuleName());
} else {
if (!azureSecurityRule.access().toString().equalsIgnoreCase(configSecurityRule.getAccess())) {
logFailure(failures, configSecurityRule.getAccess(), azureSecurityRule.access());
}
if (!azureSecurityRule.destinationAddressPrefix().equalsIgnoreCase(configSecurityRule.getDestinationAddressPrefix())) {
logFailure(failures, configSecurityRule.getDestinationAddressPrefix(), azureSecurityRule.destinationAddressPrefix());
}
if (!azureSecurityRule.destinationPortRange().equalsIgnoreCase(configSecurityRule.getDestinationPortRange())) {
logFailure(failures, configSecurityRule.getDestinationPortRange(), azureSecurityRule.destinationPortRange());
}
if (!azureSecurityRule.sourceAddressPrefix().equalsIgnoreCase(configSecurityRule.getSourceAddressPrefix())) {
logFailure(failures, configSecurityRule.getSourceAddressPrefix(), azureSecurityRule.sourceAddressPrefix());
}
if (!azureSecurityRule.sourcePortRange().equalsIgnoreCase(configSecurityRule.getSourcePortRange())) {
logFailure(failures, configSecurityRule.getSourcePortRange(), azureSecurityRule.sourcePortRange());
}
if (!azureSecurityRule.protocol().toString().equalsIgnoreCase(configSecurityRule.getProtocol())) {
logFailure(failures, configSecurityRule.getProtocol(), azureSecurityRule.protocol());
}
if (!azureSecurityRule.direction().toString().equalsIgnoreCase(configSecurityRule.getDirection())) {
logFailure(failures, configSecurityRule.getDirection(), azureSecurityRule.direction());
}
}
});
});
if (!failures.isEmpty()) {
Assertions.fail(
"Error(s) detected while comparing the network security groups between Azure and the config. Failures: "
+ failures);
}
}
Thanks in advance
If we have the two types AzureSecurityRule and ConfigSecurityRule we could make the comparison less verbose like this:
BiConsumer<AzureSecurityRule, ConfigSecurityRule> compareField(Function<AzureSecurityRule,String> f1, Function<ConfigSecurityRule> f2) {
return (az, cf) -> {
if !f1.apply(az).equalsIgnoreCase(f2.apply(cf)) {
logFailure(failure, f2.apply(cf), f1.apply(az));
}
}
}
...
List.of(
compareField(az -> az.access().toString(), cf -> cf.getAccess()),
compareField(az -> az.destinationAddressPrefix(), cf -> cf.getDestinationAddressPrefix()),
...
).forEach(cf -> cf.accept(azureSecurityRule, configSecurityRule));

Replace SQL Exception with empty object

I use this SQL query to get simple object:
#Override
public Optional<PaymentTransactions> paymentTransactionByWpfPaymentId(Integer id) {
String hql = "SELECT t FROM " + PaymentTransactions.class.getName() + " t "
+ " WHERE wppt.wpf_payment_id = :id ";
TypedQuery<PaymentTransactions> query = entityManager.createQuery(hql, PaymentTransactions.class).setParameter("id", id);
List<PaymentTransactions> wpfPayments = query.getResultList();
return wpfPayments.isEmpty() ? Optional.empty() : Optional.of(wpfPayments.get(0));
}
I use this End point
#GetMapping("/{id}")
public ResponseEntity<List<PaymentTransactionsDTO>> getWpf_reference_transactions(#PathVariable String id) throws NumberFormatException, Exception {
Optional<PaymentTransactions> tnx = wpfPaymentsService.paymentTransactionByWpfPaymentId(Integer.parseInt(id));
if(tnx.get().getId() != 0) {
return ResponseEntity.ok(transactionService
.get(Integer.valueOf(tnx.get().getId())).stream()
.collect(Collectors.toList()));
}
return ResponseEntity.notFound().build();
}
But when the database is empty I get java.util.NoSuchElementException: No value present. Is there a way to return just empty object without this exception?
You can simplify your return statement using
return tnx.map(PaymentTransactions::getId)
.filter(id -> id != 0)
.map(id -> transactionService.get(id)
.stream()
.collect(Collectors.toList()))
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
For a cleaner approach.
Also, this
id -> transactionService.get(id)
.stream()
.collect(Collectors.toList()
can become
id -> new ArrayList<>(transactionService.get(id)))
and so you have
tnx.map(Transaction::getId)
.filter(id -> id != 0)
.map(id -> new ArrayList<>(transactionService.get(id)))
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
I also doubt you need
id -> new ArrayList<>(transactionService.get(id))
Instead, this is sufficient
id -> transactionService.get(id)
Because you cannot touch that List at all.
Optional.get() will throw NoSuchElementException - if there is no value present, so use isPresent to know the value is present in optional or not
if(tnx.isPresent() && tnx.get().getId() != 0) {
return ResponseEntity.ok(transactionService
.get(Integer.valueOf(tnx.get().getId())).stream()
.collect(Collectors.toList()));
}
return ResponseEntity.notFound().build();
Yes. Wherever your exception originates from, wrap it in a try/catch block, as follows:
try {
<code that throws exception>
} catch (NoSuchElementException e) {
return new MyObject();
}

How to find values of a string array in a stream

I am trying to get a solution to the following problem.
How can I find values from "conditions" in "stream"?
At the moment I can only filter with the "line.contains method". But I want that the user can give a number of conditions which would be saved in the Array "conditions". I tried to build a for-loop in the stream.filter but I failed.^^ Maybe you know an efficient way. :)
Thanks.
private static void streamSelectedFile(String p, String[] conditions) {
try (
Stream<String> stream = Files.lines(Paths.get(p), StandardCharsets.ISO_8859_1)) {
Stream<String> filteredStream =
stream.filter(line -> line.contains("conditionValue"));
filteredStream.forEach(elem -> {
System.out.println(elem + " Path: " + p);
});
} catch (IOException e) {
...
}
}
Use allMatch
stream.filter(line -> Stream.of(conditions).allMatch(line::contains))

replacing a couple of Java loops, to a simple lambda but it looks like over complicated

I am working with some apache POI files, it is working, and I am doing some refactoring on that, but I am facing a doubt with this code:
for (XWPFTable tbl : doc.getTables()) {
for (XWPFTableRow row : tbl.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
for (XWPFParagraph paragraph : cell.getParagraphs()) {
for (XWPFRun xwpfRun : paragraph.getRuns()) {
String text = xwpfRun.getText(0);
if (text != null && text.contains(key)) {
text = text.replace(key, replaces.get(key) == null ? "" : replaces.get(key));
xwpfRun.setText(text, 0);
}
}
}
}
}
}
When I try to replace this to a lambda the code looks like this :
List<XWPFRun> collect = doc.getTables().stream().flatMap(xwpfTable -> xwpfTable.getRows().stream()
.flatMap(xwpfTableRow -> xwpfTableRow.getTableCells().stream().
flatMap(xwpfTableCell -> xwpfTableCell.getParagraphs().stream()
.flatMap(xwpfParagraph -> xwpfParagraph.getRuns().stream().filter(Objects::nonNull)))))
.collect(Collectors.toList());
And for me this code is really complicated, as it does not return anything I need to split one last for each:
for (XWPFRun xwpfRun : paragraph.getRuns()) {
String text = xwpfRun.getText(0);
if (text != null && text.contains(key)) {
text = text.replace(key, replaces.get(key) == null ? "" : replaces.get(key));
xwpfRun.setText(text, 0);
}
}
I am pretty sure there is a better and cleaner way to do this but I couldn't figure it out, do you have some ideas?
You're very close to a readable solution.
You can "flatten" your flatMap calls like so:
doc.getTables().stream()
.map(XWPFTable::getRows).flatMap(List::stream)
.map(XWPFTableRow::getTableCells).flatMap(List::stream)
.map(XWPFTableCell::getParagraphs).flatMap(List::stream)
.map(XWPFParagraph::getRuns).flatMap(List::stream)
.filter(Objects::nonNull)
.forEach(xwpfRun -> {
String text = xwpfRun.getText(0);
if (text != null && text.contains(key)) {
text = text.replace(key, replaces.get(key) == null ? "" : replaces.get(key));
xwpfRun.setText(text, 0);
}
});
Or you might prefer to replace each .map().flatMap() with a single .flatMap, which looks a bit more like your solution. For example:
.flatMap(table -> table.getRows().stream())
.flatMap(row -> row.getTableCells().stream())
...
You could also add a .filter instead of the if statement in the forEach, but that looked more complicated, in my opinion.
You can do the flatMap one by one
Simplify the code in the forEach at the end
remove the condition text.contains(key)
use getOrDefault instead of the ternary operation that will access twice the map in case of success
doc.getTables().stream()
.flatMap(xwpfTable -> xwpfTable.getRows().stream())
.flatMap(xwpfTableRow -> xwpfTableRow.getTableCells().stream())
.flatMap(xwpfTableCell -> xwpfTableCell.getParagraphs().stream())
.flatMap(xwpfParagraph -> xwpfParagraph.getRuns().stream())
.filter(Objects::nonNull)
.forEach(xwpfRun -> {
String text = xwpfRun.getText(0);
if (text != null) {
xwpfRun.setText(text.replace(key, replaces.getOrDefault(key, "")), 0);
}
});

Elastic Search : Highlighted field not always returned

Using Java API, I need to be able to retrieve the field/highlighted field associated with the query. So I'm adding the _all field (or else *) to the query and highlighted field to the response.
It works most of the time, but not always. Here is a snippet :
final BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
Arrays.asList(query.split(" "))
.stream()
.map(QueryParser::escape)
.map(x -> String.format("*%s*", x))
.forEach(x -> {
boolQueryBuilder.should(
QueryBuilders.queryStringQuery(x)
.field("_all")
.allowLeadingWildcard(true));
});
SearchResponse response = client
.prepareSearch()
.setSize(10)
.addHighlightedField("*")
.setHighlighterRequireFieldMatch(false)
.setQuery(boolQueryBuilder)
.setHighlighterFragmentSize(40)
.setHighlighterNumOfFragments(40)
.execute()
.actionGet();
Any idea on why the field field as well as the highlightedField is not always accessible in the response given that it is technically always queried?
Not sure but I think you might be looking for this :-
String aQueryWithPartialSerach = null;
final BoolQueryBuilder aBoolQueryBuilder = new BoolQueryBuilder();
// Enabling partial sarch
if (query.contains(" ")) {
List<String> aTokenList = Arrays.asList(query.split(" "));
aQueryWithPartialSerach = String.join(" ", aTokenList.stream().map(p -> "*" + p + "*").collect(Collectors.toList()));
} else {
aQueryWithPartialSerach = "*" + query + "*";
}
aBoolQueryBuilder.should(QueryBuilders.queryStringQuery(aQueryWithPartialSerach));

Categories