diff --git a/framework/rest-api/src/main/java/org/apache/ofbiz/ws/rs/model/ModelApiReader.java b/framework/rest-api/src/main/java/org/apache/ofbiz/ws/rs/model/ModelApiReader.java index a6aab6c294e..bec41a8739a 100644 --- a/framework/rest-api/src/main/java/org/apache/ofbiz/ws/rs/model/ModelApiReader.java +++ b/framework/rest-api/src/main/java/org/apache/ofbiz/ws/rs/model/ModelApiReader.java @@ -61,7 +61,7 @@ public static ModelApi getModelApi(final File apiDef) { api.setName(UtilXml.checkEmpty(docElement.getAttribute("name")).intern()); api.setDescription(UtilXml.checkEmpty(docElement.getAttribute("description")).intern()); api.setPath(UtilXml.checkEmpty(docElement.getAttribute("path")).intern()); - api.setPublish(Boolean.parseBoolean(UtilXml.checkEmpty(docElement.getAttribute("publish")).intern())); + api.setPublish(parseBooleanDefaultTrue(docElement.getAttribute("publish"))); for (Element resourceEle : UtilXml.childElementList(docElement, "resource")) { createModelResource(resourceEle, api); } @@ -107,8 +107,8 @@ private static ModelResource buildResource(Element resourceEle) { .description(UtilXml.checkEmpty(resourceEle.getAttribute("description")).intern()) .displayName(UtilXml.checkEmpty(resourceEle.getAttribute("displayName")).intern()) .path(UtilXml.checkEmpty(resourceEle.getAttribute("path")).intern()) - .publish(Boolean.parseBoolean(UtilXml.checkEmpty(resourceEle.getAttribute("publish")).intern())) - .auth(Boolean.parseBoolean(UtilXml.checkEmpty(resourceEle.getAttribute("auth")).intern())) + .publish(parseBooleanDefaultTrue(resourceEle.getAttribute("publish"))) + .auth(parseBooleanDefaultTrue(resourceEle.getAttribute("auth"))) .primaryPermission(UtilXml.checkEmpty(resourceEle.getAttribute("primaryPermission")).intern()) .mainAction(UtilXml.checkEmpty(resourceEle.getAttribute("mainAction")).intern()) .customHeaders(UtilXml.checkEmpty(resourceEle.getAttribute("customHeaders")).intern()); @@ -125,7 +125,7 @@ private static void createOperations(Element resourceEle, ModelResource resource .produces(UtilXml.checkEmpty(operationEle.getAttribute("produces")).intern()) .consumes(UtilXml.checkEmpty(operationEle.getAttribute("consumes")).intern()) .description(UtilXml.checkEmpty(operationEle.getAttribute("description")).intern()) - .auth(Boolean.parseBoolean(UtilXml.checkEmpty(operationEle.getAttribute("auth")).intern())) + .auth(parseBooleanDefaultTrue(operationEle.getAttribute("auth"))) .primaryPermission(UtilXml.checkEmpty(operationEle.getAttribute("primaryPermission"), resourceEle.getAttribute("primaryPermission")).intern()) .mainAction(UtilXml.checkEmpty(operationEle.getAttribute("mainAction"), @@ -144,6 +144,21 @@ private static void createOperations(Element resourceEle, ModelResource resource } + /** + * Parses an {@code xs:boolean}-typed attribute that {@code rest-api.xsd} declares with + * {@code default="true"} (currently {@code publish} and {@code auth}). DOM's + * {@code Element.getAttribute} returns {@code ""} for an attribute that is absent from the + * source XML, so the omitted case must be defaulted explicitly rather than handed to + * {@link Boolean#parseBoolean(String)}, which would otherwise resolve it to {@code false}. + * + * @param attributeValue the raw attribute value, or {@code ""} if the attribute was omitted + * @return {@code true} if the attribute was omitted or explicitly {@code "true"}; {@code false} otherwise + */ + private static boolean parseBooleanDefaultTrue(String attributeValue) { + String value = UtilXml.checkEmpty(attributeValue).intern(); + return value.isEmpty() || Boolean.parseBoolean(value); + } + private static void createQueryParams(Element operationEle, ModelOperation operation) { for (Element queryParamEle : UtilXml.childElementList(operationEle, "queryParam")) { ModelQueryParam qp = new ModelQueryParam() diff --git a/framework/rest-api/src/test/java/org/apache/ofbiz/ws/rs/model/ModelApiReaderTest.java b/framework/rest-api/src/test/java/org/apache/ofbiz/ws/rs/model/ModelApiReaderTest.java index 5cb0f398dae..6d21ed7e6fb 100644 --- a/framework/rest-api/src/test/java/org/apache/ofbiz/ws/rs/model/ModelApiReaderTest.java +++ b/framework/rest-api/src/test/java/org/apache/ofbiz/ws/rs/model/ModelApiReaderTest.java @@ -19,7 +19,6 @@ package org.apache.ofbiz.ws.rs.model; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -67,15 +66,14 @@ void testGetModelApiParsesTopLevelAttributes() throws IOException { } @Test - void testGetModelApiMissingPublishAttributeDefaultsToFalse() throws IOException { - // No "publish" attribute at all -> UtilXml.checkEmpty(...) yields "", - // and Boolean.parseBoolean("") is false. This locks in that implicit - // default so a change in checkEmpty/parseBoolean behavior is caught. + void testGetModelApiMissingPublishAttributeDefaultsToTrue() throws IOException { + // No "publish" attribute at all -> rest-api.xsd declares this attribute + // default="true", so an omitted attribute must resolve to true. File file = writeXml(""); ModelApi api = ModelApiReader.getModelApi(file); - assertFalse(api.isPublish()); + assertTrue(api.isPublish()); } @Test