diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Model.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Model.java index c409dd4eeed..3c83fdfc658 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Model.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Model.java @@ -45,7 +45,7 @@ public interface Model extends Set, Serializable, NamespaceAware { */ default Namespace setNamespace(String prefix, String name) { Optional result = getNamespace(prefix); - if (!result.isPresent() || !result.get().getName().equals(name)) { + if (result.isEmpty() || !result.get().getName().equals(name)) { result = Optional.of(new ModelNamespace(prefix, name)); setNamespace(result.get()); } diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Configurations.java b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Configurations.java index b74e2f84ec4..7c9bb003ea2 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Configurations.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Configurations.java @@ -240,7 +240,7 @@ public static Optional getSubjectByType(Model model, IRI type, IRI leg private static void logDiscrepancyWarning(Optional preferred, Optional fallback) { - if (!fallback.isEmpty() && !preferred.equals(fallback)) { + if (fallback.isPresent() && !preferred.equals(fallback)) { var msg = "Discrepancy between use of the old and new config vocabulary."; // depending on whether preferred is set, we log on warn or debug if (preferred.isEmpty()) { diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/util/GraphComparisons.java b/core/model/src/main/java/org/eclipse/rdf4j/model/util/GraphComparisons.java index 0c5911ee00f..1f3ceb59c80 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/util/GraphComparisons.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/util/GraphComparisons.java @@ -169,7 +169,7 @@ private static boolean isomorphicSingleContext(Model model1, Model model2) { // Because we have previously already checked that the models are the same size, we don't have to check both // ways to establish model equality. - return !missingInModel2.isPresent(); + return missingInModel2.isEmpty(); } private static boolean mappingsIncompatible(Map mapping1, Map mapping2) { diff --git a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/function/string/Contains.java b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/function/string/Contains.java index df4b84dd32a..8e5c5191cdf 100644 --- a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/function/string/Contains.java +++ b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/function/string/Contains.java @@ -45,7 +45,7 @@ public Literal evaluate(ValueFactory valueFactory, Value... args) throws ValueEx Literal rightLit = (Literal) rightVal; if (leftLit.getLanguage().isPresent()) { - if (!rightLit.getLanguage().isPresent() || rightLit.getLanguage().equals(leftLit.getLanguage())) { + if (rightLit.getLanguage().isEmpty() || rightLit.getLanguage().equals(leftLit.getLanguage())) { String leftLexVal = leftLit.getLabel(); String rightLexVal = rightLit.getLabel(); diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelper.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelper.java index 3d9d0f5414e..fbb27d608ab 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelper.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelper.java @@ -190,7 +190,7 @@ public static Literal createLiteral(String label, String lang, IRI datatype, Par try { // Removes datatype for langString datatype with no language tag when VERIFY_DATATYPE_VALUES is False. if ((workingDatatype == null || RDF.LANGSTRING.equals(workingDatatype)) - && (!workingLang.isPresent() || workingLang.get().isEmpty()) + && (workingLang.isEmpty() || workingLang.get().isEmpty()) && !parserConfig.get(BasicParserSettings.VERIFY_DATATYPE_VALUES)) { workingLang = Optional.ofNullable(null); workingDatatype = null; diff --git a/core/rio/jsonld-legacy/src/main/java/org/eclipse/rdf4j/rio/jsonld/legacy/JSONLDInternalRDFParser.java b/core/rio/jsonld-legacy/src/main/java/org/eclipse/rdf4j/rio/jsonld/legacy/JSONLDInternalRDFParser.java index f61f310ef3a..2bb9232b2e2 100644 --- a/core/rio/jsonld-legacy/src/main/java/org/eclipse/rdf4j/rio/jsonld/legacy/JSONLDInternalRDFParser.java +++ b/core/rio/jsonld-legacy/src/main/java/org/eclipse/rdf4j/rio/jsonld/legacy/JSONLDInternalRDFParser.java @@ -64,7 +64,7 @@ public void handleStatement(RDFDataset result, Statement nextStatement) { // In RDF-1.1, RDF-1.0 Plain Literals are now Typed Literals with // type xsd:String - if (!literal.getLanguage().isPresent() && datatype == null) { + if (literal.getLanguage().isEmpty() && datatype == null) { datatype = XSD.STRING.stringValue(); } diff --git a/core/sail/elasticsearch/src/main/java/org/eclipse/rdf4j/sail/elasticsearch/ElasticsearchIndex.java b/core/sail/elasticsearch/src/main/java/org/eclipse/rdf4j/sail/elasticsearch/ElasticsearchIndex.java index 19846bfc827..6566a54010f 100644 --- a/core/sail/elasticsearch/src/main/java/org/eclipse/rdf4j/sail/elasticsearch/ElasticsearchIndex.java +++ b/core/sail/elasticsearch/src/main/java/org/eclipse/rdf4j/sail/elasticsearch/ElasticsearchIndex.java @@ -88,14 +88,13 @@ /** * Requires an Elasticsearch cluster with the DeleteByQuery plugin. - * + *

* Note that, while RDF4J is licensed under the EDL, several ElasticSearch dependencies are licensed under the Elastic * license or the SSPL, which may have implications for some projects. - * + *

* Please consult the ElasticSearch website and license FAQ for more information. * * @see Elastic License FAQ - * * @see LuceneSail */ public class ElasticsearchIndex extends AbstractSearchIndex { @@ -410,13 +409,8 @@ protected SearchDocument getDocument(String id) throws IOException { @Override protected Iterable getDocuments(String resourceId) throws IOException { SearchHits hits = getDocuments(QueryBuilders.termQuery(SearchFields.URI_FIELD_NAME, resourceId)); - return Iterables.transform(hits, new Function<>() { - - @Override - public SearchDocument apply(SearchHit hit) { - return new ElasticsearchDocument(hit, geoContextMapper); - } - }); + return Iterables.transform(hits, + (Function) hit -> new ElasticsearchDocument(hit, geoContextMapper)); } @Override @@ -579,18 +573,14 @@ protected Iterable query(Resource subject, QuerySpec sp SearchHits hits; int numDocs = Objects.requireNonNullElse(spec.getNumDocs(), -1); + if (subject != null) { hits = search(subject, request, qb, numDocs); } else { hits = search(request, qb, numDocs); } - return Iterables.transform(hits, new Function<>() { - - @Override - public DocumentScore apply(SearchHit hit) { - return new ElasticsearchDocumentScore(hit, geoContextMapper); - } - }); + return Iterables.transform(hits, + (Function) hit -> new ElasticsearchDocumentScore(hit, geoContextMapper)); } /** @@ -701,13 +691,8 @@ protected Iterable geoRelationQuery(String relation, I SearchRequestBuilder request = client.prepareSearch(); SearchHits hits = search(request, QueryBuilders.boolQuery().must(qb).filter(fb)); - return Iterables.transform(hits, new Function<>() { - - @Override - public DocumentResult apply(SearchHit hit) { - return new ElasticsearchDocumentResult(hit, geoContextMapper); - } - }); + return Iterables.transform(hits, + (Function) hit -> new ElasticsearchDocumentResult(hit, geoContextMapper)); } private ShapeRelation toSpatialOp(String relation) { @@ -735,30 +720,35 @@ public SearchHits search(SearchRequestBuilder request, QueryBuilder query) { */ public SearchHits search(SearchRequestBuilder request, QueryBuilder query, int numDocs) { String[] types = getTypes(); - int nDocs; - if (numDocs > 0) { - if (maxDocs > 0 && maxDocs < numDocs) { - nDocs = maxDocs; - } else { - nDocs = numDocs; - } - } else if (defaultNumDocs > 0) { - nDocs = defaultNumDocs; - } else { + + if (numDocs < -1) { + throw new IllegalArgumentException("numDocs should be 0 or greater if defined by the user"); + } + + int size = defaultNumDocs; + if (numDocs >= 0) { + // If the user has set numDocs we will use that. If it is 0 then the implementation may end up throwing an + // exception. + size = Math.min(maxDocs, numDocs); + } + + if (size < 0) { + // defaultNumDocs is not set long docCount = client.prepareSearch(indexName) .setTypes(types) .setSource(new SearchSourceBuilder().size(0).query(query)) .get() .getHits() .getTotalHits().value; - nDocs = Math.max((int) Math.min(docCount, Integer.MAX_VALUE), 1); + size = Math.max((int) Math.min(docCount, maxDocs), 1); } + SearchResponse response = request.setIndices(indexName) .setTypes(types) .setVersion(false) .seqNoAndPrimaryTerm(true) .setQuery(query) - .setSize(nDocs) + .setSize(size) .execute() .actionGet(); return response.getHits(); diff --git a/core/sail/lucene-api/src/main/java/org/eclipse/rdf4j/sail/lucene/AbstractSearchIndex.java b/core/sail/lucene-api/src/main/java/org/eclipse/rdf4j/sail/lucene/AbstractSearchIndex.java index e52fc63ab81..ba3a7f3d35c 100644 --- a/core/sail/lucene-api/src/main/java/org/eclipse/rdf4j/sail/lucene/AbstractSearchIndex.java +++ b/core/sail/lucene-api/src/main/java/org/eclipse/rdf4j/sail/lucene/AbstractSearchIndex.java @@ -41,6 +41,7 @@ import org.eclipse.rdf4j.query.MalformedQueryException; import org.eclipse.rdf4j.query.algebra.Var; import org.eclipse.rdf4j.query.algebra.evaluation.QueryBindingSet; +import org.eclipse.rdf4j.sail.Sail; import org.eclipse.rdf4j.sail.SailException; import org.eclipse.rdf4j.sail.lucene.util.MapOfListMaps; import org.locationtech.spatial4j.context.SpatialContext; @@ -65,8 +66,8 @@ public abstract class AbstractSearchIndex implements SearchIndex { REJECTED_DATATYPES.add("http://www.w3.org/2001/XMLSchema#float"); } - protected int defaultNumDocs; - protected int maxDocs; + protected int defaultNumDocs = -1; + protected int maxDocs = Integer.MAX_VALUE; protected Set wktFields = Collections.singleton(SearchFields.getPropertyField(GEO.AS_WKT)); @@ -77,9 +78,28 @@ public abstract class AbstractSearchIndex implements SearchIndex { @Override public void initialize(Properties parameters) throws Exception { String maxDocumentsParam = parameters.getProperty(LuceneSail.MAX_DOCUMENTS_KEY); - maxDocs = (maxDocumentsParam != null) ? Integer.parseInt(maxDocumentsParam) : -1; String defaultNumDocsParam = parameters.getProperty(LuceneSail.DEFAULT_NUM_DOCS_KEY); - defaultNumDocs = (defaultNumDocsParam != null) ? Integer.parseInt(defaultNumDocsParam) : defaultNumDocs; + + if ((maxDocumentsParam != null)) { + maxDocs = Integer.parseInt(maxDocumentsParam); + + // if maxDocs is set then defaultNumDocs is set to maxDocs if it is not set, because we now have a known + // upper limit + defaultNumDocs = (defaultNumDocsParam != null) ? Math.min(maxDocs, Integer.parseInt(defaultNumDocsParam)) + : maxDocs; + } else { + // we can never return more than Integer.MAX_VALUE documents + maxDocs = Integer.MAX_VALUE; + + // legacy behaviour is to return the number of documents that the query would return if there was no limit, + // so if the defaultNumDocs is not set, we set it to -1 to signal that there is no limit + defaultNumDocs = (defaultNumDocsParam != null) ? Integer.parseInt(defaultNumDocsParam) : -1; + } + + if (defaultNumDocs > maxDocs) { + throw new IllegalArgumentException(LuceneSail.DEFAULT_NUM_DOCS_KEY + " must be less than or equal to " + + LuceneSail.MAX_DOCUMENTS_KEY + " (" + defaultNumDocs + " > " + maxDocs + ")"); + } String wktFieldParam = parameters.getProperty(LuceneSail.WKT_FIELDS); if (wktFieldParam != null) { @@ -149,7 +169,7 @@ public boolean accept(Literal literal) { // we reject literals that aren't in the list of the indexed lang if (indexedLangs != null - && (!literal.getLanguage().isPresent() + && (literal.getLanguage().isEmpty() || !indexedLangs.contains(literal.getLanguage().get().toLowerCase() ))) { return false; @@ -356,11 +376,8 @@ public final synchronized void addRemoveStatements(Collection added, // remove value from both property field and the // corresponding text field String field = SearchFields.getPropertyField(r.getPredicate()); - Set removedValues = removedOfResource.get(field); - if (removedValues == null) { - removedValues = new HashSet<>(); - removedOfResource.put(field, removedValues); - } + Set removedValues = removedOfResource.computeIfAbsent(field, + k -> new HashSet<>()); removedValues.add(val); } } @@ -548,7 +565,8 @@ private Iterable evaluateQuery(QuerySpec query) { hits = query(query.getSubject(), query); } } catch (Exception e) { - logger.error("There was a problem evaluating query '" + query.getCatQuery() + "'!", e); + logger.error("There was a problem evaluating query '{}'!", query.getCatQuery(), e); + assert false : "There was a problem evaluating query '" + query.getCatQuery() + "'!"; } return hits; @@ -720,6 +738,8 @@ private Iterable evaluateQuery(DistanceQuerySpec que } catch (Exception e) { logger.error("There was a problem evaluating distance query 'within " + distance + getUnitSymbol(units) + " of " + from.getLabel() + "'!", e); + assert false : "There was a problem evaluating distance query 'within " + distance + getUnitSymbol(units) + + " of " + from.getLabel() + "'!"; } return hits; @@ -828,6 +848,8 @@ private Iterable evaluateQuery(GeoRelationQuerySpec qu } catch (Exception e) { logger.error("There was a problem evaluating spatial relation query '" + query.getRelation() + " " + qgeom.getLabel() + "'!", e); + assert false : "There was a problem evaluating spatial relation query '" + query.getRelation() + " " + + qgeom.getLabel() + "'!"; } return hits; diff --git a/core/sail/lucene/src/main/java/org/eclipse/rdf4j/sail/lucene/impl/LuceneIndex.java b/core/sail/lucene/src/main/java/org/eclipse/rdf4j/sail/lucene/impl/LuceneIndex.java index 5e17fa2b36d..d68bacaf9cb 100644 --- a/core/sail/lucene/src/main/java/org/eclipse/rdf4j/sail/lucene/impl/LuceneIndex.java +++ b/core/sail/lucene/src/main/java/org/eclipse/rdf4j/sail/lucene/impl/LuceneIndex.java @@ -1004,19 +1004,20 @@ public synchronized TopDocs search(Query query) throws IOException { * @throws IOException */ public synchronized TopDocs search(Query query, int numDocs) throws IOException { - int nDocs; - if (numDocs > 0) { - if (maxDocs > 0 && maxDocs < numDocs) { - nDocs = maxDocs; - } else { - nDocs = numDocs; - } - } else if (defaultNumDocs > 0) { - nDocs = defaultNumDocs; - } else { - nDocs = Math.max(getIndexReader().numDocs(), 1); + if (numDocs < -1) { + throw new IllegalArgumentException("numDocs should be 0 or greater if defined by the user"); + } + + int size = defaultNumDocs; + if (numDocs >= 0) { + // If the user has set numDocs we will use that. If it is 0 then the implementation may end up throwing an + // exception. + size = Math.min(maxDocs, numDocs); + } + if (size < 0) { + size = Math.max(getIndexReader().numDocs(), 1); } - return getIndexSearcher().search(query, nDocs); + return getIndexSearcher().search(query, size); } private QueryParser getQueryParser(IRI propertyURI) { diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/constraintcomponents/UniqueLangConstraintComponent.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/constraintcomponents/UniqueLangConstraintComponent.java index 453ff412372..e84386170d8 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/constraintcomponents/UniqueLangConstraintComponent.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/constraintcomponents/UniqueLangConstraintComponent.java @@ -120,7 +120,7 @@ public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connections connectionsGroup.getRdfsSubClassOfReasoner(), stableRandomVariableProvider); Optional path = getTargetChain().getPath(); - if (!path.isPresent() || scope != Scope.propertyShape) { + if (path.isEmpty() || scope != Scope.propertyShape) { throw new IllegalStateException("UniqueLang only operates on paths"); } diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/NonUniqueTargetLang.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/NonUniqueTargetLang.java index eab7562ecac..83a4424c156 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/NonUniqueTargetLang.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/NonUniqueTargetLang.java @@ -149,7 +149,7 @@ private void calculateNext() { if (value.isLiteral()) { Optional lang = ((Literal) value).getLanguage(); - if (!lang.isPresent()) { + if (lang.isEmpty()) { next = null; } else if (!seenLanguages.contains(lang.get())) { seenLanguages.add(lang.get()); diff --git a/core/sail/solr/src/main/java/org/eclipse/rdf4j/sail/solr/SolrIndex.java b/core/sail/solr/src/main/java/org/eclipse/rdf4j/sail/solr/SolrIndex.java index a7c54396cf2..f04e6cc9cb6 100644 --- a/core/sail/solr/src/main/java/org/eclipse/rdf4j/sail/solr/SolrIndex.java +++ b/core/sail/solr/src/main/java/org/eclipse/rdf4j/sail/solr/SolrIndex.java @@ -583,20 +583,22 @@ public QueryResponse search(SolrQuery query) throws SolrServerException, IOExcep * @throws IOException */ public QueryResponse search(SolrQuery query, int numDocs) throws SolrServerException, IOException { - int nDocs; - if (numDocs > 0) { - if (maxDocs > 0 && maxDocs < numDocs) { - nDocs = maxDocs; - } else { - nDocs = numDocs; - } - } else if (defaultNumDocs > 0) { - nDocs = defaultNumDocs; - } else { + if (numDocs < -1) { + throw new IllegalArgumentException("numDocs should be 0 or greater if defined by the user"); + } + + int size = defaultNumDocs; + if (numDocs >= 0) { + // If the user has set numDocs we will use that. If it is 0 then the implementation may end up throwing an + // exception. + size = Math.min(maxDocs, numDocs); + } + + if (size < 0) { long docCount = client.query(query.setRows(0)).getResults().getNumFound(); - nDocs = Math.max((int) Math.min(docCount, Integer.MAX_VALUE), 1); + size = Math.max((int) Math.min(docCount, maxDocs), 1); } - return client.query(query.setRows(nDocs)); + return client.query(query.setRows(size)); } private SolrQuery prepareQuery(IRI propertyURI, SolrQuery query) { diff --git a/testsuites/lucene/src/main/java/org/eclipse/testsuite/rdf4j/sail/lucene/AbstractLuceneSailTest.java b/testsuites/lucene/src/main/java/org/eclipse/testsuite/rdf4j/sail/lucene/AbstractLuceneSailTest.java index fa01c118a38..ab6595a2318 100644 --- a/testsuites/lucene/src/main/java/org/eclipse/testsuite/rdf4j/sail/lucene/AbstractLuceneSailTest.java +++ b/testsuites/lucene/src/main/java/org/eclipse/testsuite/rdf4j/sail/lucene/AbstractLuceneSailTest.java @@ -19,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -1179,6 +1180,24 @@ public void testNumDocsResult(int numDoc) { }); } + @Test + public void testNumDocsResultNegative() { + // assert that negative values cause an assertion error + assertThrows(AssertionError.class, () -> { + Repositories.consumeNoTransaction(repository, conn -> { + try (TupleQueryResult res = conn.prepareTupleQuery( + "SELECT ?Resource {\n" + + " ?Resource <" + MATCHES + "> [\n " + + " <" + QUERY + "> \"one\";\n " + + " <" + NUM_DOCS + "> " + -2 + ";\n " + + " ]. } " + ).evaluate()) { + assertFalse(res.hasNext()); + } + }); + }); + } + protected void assertQueryResult(String literal, IRI predicate, Resource resultUri) { try (RepositoryConnection connection = repository.getConnection()) { // fire a query for all subjects with a given term diff --git a/tools/console/src/main/java/org/eclipse/rdf4j/console/command/Convert.java b/tools/console/src/main/java/org/eclipse/rdf4j/console/command/Convert.java index 70af757cb4e..602cc55f132 100644 --- a/tools/console/src/main/java/org/eclipse/rdf4j/console/command/Convert.java +++ b/tools/console/src/main/java/org/eclipse/rdf4j/console/command/Convert.java @@ -104,7 +104,7 @@ private void convert(String fileFrom, String fileTo) { return; } Optional fmtFrom = Rio.getParserFormatForFileName(fileFrom); - if (!fmtFrom.isPresent()) { + if (fmtFrom.isEmpty()) { writeError("No RDF parser for " + fileFrom); return; } @@ -116,7 +116,7 @@ private void convert(String fileFrom, String fileTo) { return; } Optional fmtTo = Rio.getWriterFormatForFileName(fileTo); - if (!fmtTo.isPresent()) { + if (fmtTo.isEmpty()) { writeError("No RDF writer for " + fileTo); return; } diff --git a/tools/console/src/main/java/org/eclipse/rdf4j/console/command/QueryEvaluator.java b/tools/console/src/main/java/org/eclipse/rdf4j/console/command/QueryEvaluator.java index 06cfde2e29a..af11e6bbd98 100644 --- a/tools/console/src/main/java/org/eclipse/rdf4j/console/command/QueryEvaluator.java +++ b/tools/console/src/main/java/org/eclipse/rdf4j/console/command/QueryEvaluator.java @@ -316,7 +316,7 @@ private QueryResultWriter getQueryResultWriter(Path path, OutputStream out) thro w = new ConsoleQueryResultWriter(consoleIO, getConsoleWidth()); } else { Optional fmt = QueryResultIO.getWriterFormatForFileName(path.toFile().toString()); - if (!fmt.isPresent()) { + if (fmt.isEmpty()) { throw new IllegalArgumentException("No suitable result writer found"); } w = QueryResultIO.createWriter(fmt.get(), out); @@ -342,7 +342,7 @@ private RDFWriter getRDFWriter(Path path, OutputStream out) throws IllegalArgume w = new ConsoleRDFWriter(consoleIO, getConsoleWidth()); } else { Optional fmt = Rio.getWriterFormatForFileName(path.toFile().toString()); - if (!fmt.isPresent()) { + if (fmt.isEmpty()) { throw new IllegalArgumentException("No suitable result writer found"); } w = Rio.createWriter(fmt.get(), out);