From 4a8a53e634f7a1b7f38a8ea236202fb17e1845ba Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 14 Jan 2026 20:15:17 +0200 Subject: [PATCH 1/9] Fixed NN_NAKED_NOTIFY Spotbugs Issues (#4417) --- .github/scripts/generate-quality-report.py | 3 +++ CodenameOne/src/com/codename1/capture/Capture.java | 2 +- CodenameOne/src/com/codename1/components/WebBrowser.java | 2 +- .../com/codename1/impl/CodenameOneImplementation.java | 6 +----- CodenameOne/src/com/codename1/io/NetworkManager.java | 4 ++-- CodenameOne/src/com/codename1/ui/Display.java | 4 ++-- CodenameOne/src/com/codename1/ui/RunnableWrapper.java | 2 +- .../ui/html/AsyncDocumentRequestHandlerImpl.java | 2 +- maven/core-unittests/spotbugs-exclude.xml | 9 +++++++++ 9 files changed, 21 insertions(+), 13 deletions(-) diff --git a/.github/scripts/generate-quality-report.py b/.github/scripts/generate-quality-report.py index 7855cad769..0f46f75376 100755 --- a/.github/scripts/generate-quality-report.py +++ b/.github/scripts/generate-quality-report.py @@ -815,6 +815,7 @@ def main() -> None: "NM_CONFUSING", "NM_FIELD_NAMING_CONVENTION", "NM_METHOD_NAMING_CONVENTION", + "NN_NAKED_NOTIFY", "NO_NOTIFY_NOT_NOTIFYALL", "NP_LOAD_OF_KNOWN_NULL_VALUE", "NP_BOOLEAN_RETURN_NULL", @@ -851,6 +852,8 @@ def _is_exempt(f: Finding) -> bool: return True if f.rule == "URF_UNREAD_FIELD" and "GridBagLayoutInfo" in loc: return True + if f.rule == "NN_NAKED_NOTIFY" and "Display.java" in loc: + return True return False diff --git a/CodenameOne/src/com/codename1/capture/Capture.java b/CodenameOne/src/com/codename1/capture/Capture.java index 4b65da9637..8571073ce2 100644 --- a/CodenameOne/src/com/codename1/capture/Capture.java +++ b/CodenameOne/src/com/codename1/capture/Capture.java @@ -257,8 +257,8 @@ public void actionPerformed(ActionEvent evt) { } else { url = (String) evt.getSource(); } - completed = true; synchronized (this) { + completed = true; this.notifyAll(); } } diff --git a/CodenameOne/src/com/codename1/components/WebBrowser.java b/CodenameOne/src/com/codename1/components/WebBrowser.java index 50f4791d8b..0067d89f00 100644 --- a/CodenameOne/src/com/codename1/components/WebBrowser.java +++ b/CodenameOne/src/com/codename1/components/WebBrowser.java @@ -154,8 +154,8 @@ protected void readResponse(InputStream input) throws IOException { if (callback != null) { callback.streamReady(input, docInfo); } else { - response[0] = input; synchronized (LOCK) { + response[0] = input; LOCK.notifyAll(); } } diff --git a/CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java b/CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java index 0fdaad117e..b329e3adca 100644 --- a/CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java +++ b/CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java @@ -7177,13 +7177,9 @@ protected final void pushReceived(String data) { * Sets the frequency for polling the server in case of polling based push notification * * @param freq the frequency in milliseconds + * @deprecated we no longer support push polling */ public void setPollingFrequency(int freq) { - if (callback != null && pollingThreadRunning) { - synchronized (callback) { - callback.notifyAll(); - } - } } /** diff --git a/CodenameOne/src/com/codename1/io/NetworkManager.java b/CodenameOne/src/com/codename1/io/NetworkManager.java index a96c460b8f..438917d40e 100644 --- a/CodenameOne/src/com/codename1/io/NetworkManager.java +++ b/CodenameOne/src/com/codename1/io/NetworkManager.java @@ -330,8 +330,8 @@ public void shutdown() { } } } - networkThreads = null; synchronized (LOCK) { + networkThreads = null; LOCK.notifyAll(); } @@ -970,10 +970,10 @@ public void run() { if (!runCurrentRequest(currentRequest)) { continue; } - currentRequest = null; // wakeup threads waiting for the completion of this network operation synchronized (LOCK) { + currentRequest = null; LOCK.notifyAll(); } } else { diff --git a/CodenameOne/src/com/codename1/ui/Display.java b/CodenameOne/src/com/codename1/ui/Display.java index 45d8ebd0b5..d9c1db5ac5 100644 --- a/CodenameOne/src/com/codename1/ui/Display.java +++ b/CodenameOne/src/com/codename1/ui/Display.java @@ -506,9 +506,8 @@ public static void init(Object m) { * Notice that minimize (being a Codename One method) MUST be invoked before invoking this method! */ public static void deinitialize() { - - INSTANCE.codenameOneRunning = false; synchronized (lock) { + INSTANCE.codenameOneRunning = false; lock.notifyAll(); } } @@ -4684,6 +4683,7 @@ public String getDatabasePath(String databaseName) { * Sets the frequency for polling the server in case of polling based push notification * * @param freq the frequency in milliseconds + * @deprecated we no longer support push polling */ public void setPollingFrequency(int freq) { impl.setPollingFrequency(freq); diff --git a/CodenameOne/src/com/codename1/ui/RunnableWrapper.java b/CodenameOne/src/com/codename1/ui/RunnableWrapper.java index 985534c41c..44c4643254 100644 --- a/CodenameOne/src/com/codename1/ui/RunnableWrapper.java +++ b/CodenameOne/src/com/codename1/ui/RunnableWrapper.java @@ -106,8 +106,8 @@ public void run() { switch (type) { case 0: internal.run(); - done = true; synchronized (Display.lock) { + done = true; Display.lock.notifyAll(); } break; diff --git a/CodenameOne/src/com/codename1/ui/html/AsyncDocumentRequestHandlerImpl.java b/CodenameOne/src/com/codename1/ui/html/AsyncDocumentRequestHandlerImpl.java index 15b65a0e5d..f4c02f4b74 100644 --- a/CodenameOne/src/com/codename1/ui/html/AsyncDocumentRequestHandlerImpl.java +++ b/CodenameOne/src/com/codename1/ui/html/AsyncDocumentRequestHandlerImpl.java @@ -155,8 +155,8 @@ protected void readResponse(InputStream input) throws IOException { if (callback != null) { callback.streamReady(input, docInfo); } else { - response[0] = input; synchronized (LOCK) { + response[0] = input; LOCK.notifyAll(); } } diff --git a/maven/core-unittests/spotbugs-exclude.xml b/maven/core-unittests/spotbugs-exclude.xml index 83d432d54b..221cdb8d49 100644 --- a/maven/core-unittests/spotbugs-exclude.xml +++ b/maven/core-unittests/spotbugs-exclude.xml @@ -152,6 +152,15 @@ + + + + + + From da736bfdaf969b32ac41ed80cac5ad915a0a1040 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 14 Jan 2026 20:32:21 +0200 Subject: [PATCH 2/9] Fix SpotBugs findings and enforce rules (#4414) --- .github/scripts/generate-quality-report.py | 6 +++ .../codename1/charts/views/PieSegment.java | 7 ++-- .../codename1/charts/views/RadarChart.java | 5 ++- .../com/codename1/io/MultipartRequest.java | 10 ++--- .../com/codename1/io/rest/RequestBuilder.java | 5 ++- .../codename1/properties/PropertyIndex.java | 8 ++-- .../properties/PropertyXMLElement.java | 24 +++++++++-- .../src/com/codename1/ui/geom/Rectangle.java | 29 -------------- .../ui/layouts/mig/ConstraintParser.java | 2 +- .../codename1/ui/layouts/mig/UnitValue.java | 40 ++++++++++++++++--- .../codename1/ui/plaf/RoundRectBorder.java | 2 +- 11 files changed, 83 insertions(+), 55 deletions(-) diff --git a/.github/scripts/generate-quality-report.py b/.github/scripts/generate-quality-report.py index 0f46f75376..a3d3c57dfa 100755 --- a/.github/scripts/generate-quality-report.py +++ b/.github/scripts/generate-quality-report.py @@ -823,6 +823,12 @@ def main() -> None: "REC_CATCH_EXCEPTION", "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", "RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT", + "INT_VACUOUS_COMPARISON", + "DM_STRING_TOSTRING", + "HE_HASHCODE_USE_OBJECT_EQUALS", + "IM_BAD_CHECK_FOR_ODD", + "IT_NO_SUCH_ELEMENT", + "FL_FLOATS_AS_LOOP_COUNTERS", "UI_INHERITANCE_UNSAFE_GETRESOURCE", "URF_UNREAD_FIELD", "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", diff --git a/CodenameOne/src/com/codename1/charts/views/PieSegment.java b/CodenameOne/src/com/codename1/charts/views/PieSegment.java index caf8bee97e..756bba6087 100644 --- a/CodenameOne/src/com/codename1/charts/views/PieSegment.java +++ b/CodenameOne/src/com/codename1/charts/views/PieSegment.java @@ -52,9 +52,10 @@ public boolean isInSegment(double angle) { double cAngle = angle % 360; double startAngle = mStartAngle; double stopAngle = mEndAngle; - while (stopAngle > 360) { - startAngle -= 360; - stopAngle -= 360; + if (stopAngle > 360) { + int rotations = (int) Math.floor(stopAngle / 360d); + startAngle -= 360 * rotations; + stopAngle -= 360 * rotations; } return cAngle >= startAngle && cAngle <= stopAngle; } diff --git a/CodenameOne/src/com/codename1/charts/views/RadarChart.java b/CodenameOne/src/com/codename1/charts/views/RadarChart.java index 7adb92969e..7bc8de3671 100644 --- a/CodenameOne/src/com/codename1/charts/views/RadarChart.java +++ b/CodenameOne/src/com/codename1/charts/views/RadarChart.java @@ -112,8 +112,9 @@ public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint paint.setColor(ColorUtil.GRAY); float thisRad = (float) Math.toRadians(90 - currentAngle); float nextRad = (float) Math.toRadians(90 - (currentAngle + angle)); - for (double level = 0; level <= 1d; level += decCoef) { // PMD Fix: DontUseFloatTypeForLoopIndices switched to double - float levelFactor = (float) level; + int levelSteps = (int) Math.round(1d / decCoef); + for (int level = 0; level <= levelSteps; level++) { + float levelFactor = (float) (level * decCoef); float thisX = (float) (centerX - Math.sin(thisRad) * radius * levelFactor); float thisY = (float) (centerY - Math.cos(thisRad) * radius * levelFactor); float nextX = (float) (centerX - Math.sin(nextRad) * radius * levelFactor); diff --git a/CodenameOne/src/com/codename1/io/MultipartRequest.java b/CodenameOne/src/com/codename1/io/MultipartRequest.java index 7a383cd34a..ff026cc1ef 100644 --- a/CodenameOne/src/com/codename1/io/MultipartRequest.java +++ b/CodenameOne/src/com/codename1/io/MultipartRequest.java @@ -269,9 +269,9 @@ protected long calculateContentLength() { length += key.length(); if (ignoreEncoding.contains(key)) { try { - length += value.toString().getBytes("UTF-8").length; + length += ((String) value).getBytes("UTF-8").length; } catch (UnsupportedEncodingException ex) { - length += StringUtil.getBytes(value.toString()).length; + length += StringUtil.getBytes((String) value).length; } } else { if (base64Binaries) { @@ -287,9 +287,9 @@ protected long calculateContentLength() { length += key.length(); if (ignoreEncoding.contains(key)) { try { - length += s.toString().getBytes("UTF-8").length; + length += s.getBytes("UTF-8").length; } catch (UnsupportedEncodingException ex) { - length += StringUtil.getBytes(value.toString()).length; + length += StringUtil.getBytes(s).length; } } else { if (base64Binaries) { @@ -534,4 +534,4 @@ public int hashCode() { result = 31 * result + (args != null ? args.hashCode() : 0); return result; } -} \ No newline at end of file +} diff --git a/CodenameOne/src/com/codename1/io/rest/RequestBuilder.java b/CodenameOne/src/com/codename1/io/rest/RequestBuilder.java index a143338ed6..4294da0491 100644 --- a/CodenameOne/src/com/codename1/io/rest/RequestBuilder.java +++ b/CodenameOne/src/com/codename1/io/rest/RequestBuilder.java @@ -48,6 +48,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; /** * This class is used to build, invoke the http request and to get the http @@ -249,8 +250,8 @@ public RequestBuilder queryParam(String key, String[] values) { */ public RequestBuilder header(String key, String value) { checkFetched(); - // .toString() is used to trigger an NPE early for null headers - headers.put(key.toString(), value.toString()); + headers.put(Objects.requireNonNull(key, "Header key cannot be null"), + Objects.requireNonNull(value, "Header value cannot be null")); return this; } diff --git a/CodenameOne/src/com/codename1/properties/PropertyIndex.java b/CodenameOne/src/com/codename1/properties/PropertyIndex.java index 9ed9fe4770..1956334faf 100644 --- a/CodenameOne/src/com/codename1/properties/PropertyIndex.java +++ b/CodenameOne/src/com/codename1/properties/PropertyIndex.java @@ -55,6 +55,7 @@ import java.util.List; import java.util.Map; import java.util.Enumeration; +import java.util.NoSuchElementException; /** * Maps the properties that are in a class/object and provides access to them so tools such as ORM @@ -198,9 +199,10 @@ public void remove() { } public PropertyBase next() { - int i = off; - off++; - return properties[i]; + if (!hasNext()) { + throw new NoSuchElementException(); + } + return properties[off++]; } }; } diff --git a/CodenameOne/src/com/codename1/properties/PropertyXMLElement.java b/CodenameOne/src/com/codename1/properties/PropertyXMLElement.java index 54601eed8f..d885a27ae6 100644 --- a/CodenameOne/src/com/codename1/properties/PropertyXMLElement.java +++ b/CodenameOne/src/com/codename1/properties/PropertyXMLElement.java @@ -29,6 +29,8 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Vector; /** @@ -295,7 +297,21 @@ public boolean isEmpty() { @Override public int hashCode() { - return parent.hashCode(); + return Objects.hash(parent, parentElement, index); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof PropertyXMLElement)) { + return false; + } + PropertyXMLElement other = (PropertyXMLElement) obj; + return index == other.index + && Objects.equals(parent, other.parent) + && Objects.equals(parentElement, other.parentElement); } @Override @@ -330,8 +346,10 @@ public boolean hasNext() { @Override public Element next() { - offset++; - return getChildAt(index); + if (!hasNext()) { + throw new NoSuchElementException(); + } + return getChildAt(offset++); } @Override diff --git a/CodenameOne/src/com/codename1/ui/geom/Rectangle.java b/CodenameOne/src/com/codename1/ui/geom/Rectangle.java index 292db87755..b84a036fa9 100644 --- a/CodenameOne/src/com/codename1/ui/geom/Rectangle.java +++ b/CodenameOne/src/com/codename1/ui/geom/Rectangle.java @@ -188,16 +188,6 @@ public static void intersection(int rrX, int rrY, int rrW, int rrH, int rtx1, in tx2 -= tx1; ty2 -= ty1; - // tx2,ty2 will never overflow (they will never be - // larger than the smallest of the two source w,h) - // they might underflow, though... - if (tx2 < Integer.MIN_VALUE) { - tx2 = Integer.MIN_VALUE; - } - if (ty2 < Integer.MIN_VALUE) { - ty2 = Integer.MIN_VALUE; - } - dest.x = tx1; dest.y = ty1; dest.size.setWidth(tx2); @@ -422,16 +412,6 @@ public Rectangle intersection(int rX, int rY, int rW, int rH) { } tx2 -= tx1; ty2 -= ty1; - // tx2,ty2 will never overflow (they will never be - // larger than the smallest of the two source w,h) - // they might underflow, though... - if (tx2 < Integer.MIN_VALUE) { - tx2 = Integer.MIN_VALUE; - } - if (ty2 < Integer.MIN_VALUE) { - ty2 = Integer.MIN_VALUE; - } - return new Rectangle(tx1, ty1, tx2, ty2); } @@ -462,15 +442,6 @@ public void intersection(Rectangle input, Rectangle output) { } tx2 -= tx1; ty2 -= ty1; - // tx2,ty2 will never overflow (they will never be - // larger than the smallest of the two source w,h) - // they might underflow, though... - if (tx2 < Integer.MIN_VALUE) { - tx2 = Integer.MIN_VALUE; - } - if (ty2 < Integer.MIN_VALUE) { - ty2 = Integer.MIN_VALUE; - } tx2 = Math.max(0, tx2); ty2 = Math.max(0, ty2); output.setBounds(tx1, ty1, tx2, ty2); diff --git a/CodenameOne/src/com/codename1/ui/layouts/mig/ConstraintParser.java b/CodenameOne/src/com/codename1/ui/layouts/mig/ConstraintParser.java index c6128d94f1..3c3313e7f7 100644 --- a/CodenameOne/src/com/codename1/ui/layouts/mig/ConstraintParser.java +++ b/CodenameOne/src/com/codename1/ui/layouts/mig/ConstraintParser.java @@ -969,7 +969,7 @@ public static UnitValue[] parseInsets(String s, boolean acceptPanel) { String[] insS = toTrimmedTokens(s, ' '); UnitValue[] ins = new UnitValue[4]; for (int j = 0; j < 4; j++) { - UnitValue insSz = parseUnitValue(insS[j < insS.length ? j : insS.length - 1], UnitValue.ZERO, j % 2 == 1); + UnitValue insSz = parseUnitValue(insS[j < insS.length ? j : insS.length - 1], UnitValue.ZERO, (j & 1) != 0); ins[j] = insSz != null ? insSz : PlatformDefaults.getPanelInsets(j); } return ins; diff --git a/CodenameOne/src/com/codename1/ui/layouts/mig/UnitValue.java b/CodenameOne/src/com/codename1/ui/layouts/mig/UnitValue.java index ef83274fff..cb1e34268f 100644 --- a/CodenameOne/src/com/codename1/ui/layouts/mig/UnitValue.java +++ b/CodenameOne/src/com/codename1/ui/layouts/mig/UnitValue.java @@ -35,8 +35,10 @@ import com.codename1.util.MathUtil; -import java.util.ArrayList; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Objects; public final class UnitValue { /** @@ -617,7 +619,33 @@ public String getConstraintString() { return LayoutUtil.getCCString(this); } - public int hashCode() { - return (int) (value * 12345) + (oper >>> 5) + unit >>> 17; - } -} + public int hashCode() { + int result = 17; + result = 31 * result + Float.floatToIntBits(value); + result = 31 * result + unit; + result = 31 * result + oper; + result = 31 * result + (isHor ? 1 : 0); + result = 31 * result + (unitStr != null ? unitStr.hashCode() : 0); + result = 31 * result + (linkId != null ? linkId.hashCode() : 0); + result = 31 * result + Arrays.hashCode(subUnits); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof UnitValue)) { + return false; + } + UnitValue other = (UnitValue) obj; + return Float.compare(value, other.value) == 0 + && unit == other.unit + && oper == other.oper + && isHor == other.isHor + && Objects.equals(unitStr, other.unitStr) + && Objects.equals(linkId, other.linkId) + && Arrays.equals(subUnits, other.subUnits); + } +} diff --git a/CodenameOne/src/com/codename1/ui/plaf/RoundRectBorder.java b/CodenameOne/src/com/codename1/ui/plaf/RoundRectBorder.java index 91d3b46ba0..4d22101d86 100644 --- a/CodenameOne/src/com/codename1/ui/plaf/RoundRectBorder.java +++ b/CodenameOne/src/com/codename1/ui/plaf/RoundRectBorder.java @@ -886,7 +886,7 @@ private GeneralPath createShape(int shapeW, int shapeH) { x += strokePx / 2f; y += strokePx / 2f; - if (strokePx % 2 == 1) { + if ((strokePx & 1) != 0) { x += 0.5f; y += 0.5f; } From 48978034c23311d7ddcdb2753439f0b1e5597689 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 15 Jan 2026 04:09:25 +0200 Subject: [PATCH 3/9] Fix SpotBugs warnings and tighten gates (#4418) --- .github/scripts/generate-quality-report.py | 5 +++++ .../src/com/codename1/facebook/FacebookRESTService.java | 5 ++++- .../src/com/codename1/io/gzip/DeflaterOutputStream.java | 2 +- CodenameOne/src/com/codename1/location/LocationManager.java | 5 +++-- CodenameOne/src/com/codename1/properties/InstantUI.java | 2 +- CodenameOne/src/com/codename1/ui/BrowserComponent.java | 2 +- CodenameOne/src/com/codename1/ui/html/HTMLComponent.java | 6 +++--- CodenameOne/src/com/codename1/ui/plaf/UIManager.java | 1 - CodenameOne/src/com/codename1/util/TBigInteger.java | 2 +- 9 files changed, 19 insertions(+), 11 deletions(-) diff --git a/.github/scripts/generate-quality-report.py b/.github/scripts/generate-quality-report.py index a3d3c57dfa..9084a2a20f 100755 --- a/.github/scripts/generate-quality-report.py +++ b/.github/scripts/generate-quality-report.py @@ -763,6 +763,7 @@ def main() -> None: if spotbugs: forbidden_rules = { "NP_ALWAYS_NULL", + "NP_NULL_PARAM_DEREF", "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE", "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", @@ -772,6 +773,7 @@ def main() -> None: "IA_AMBIGUOUS_INVOCATION_OF_INHERITED_OR_OUTER_METHOD", "LI_LAZY_INIT_STATIC", "RpC_REPEATED_CONDITIONAL_TEST", + "NS_NON_SHORT_CIRCUIT", "ES_COMPARING_PARAMETER_STRING_WITH_EQ", "FE_FLOATING_POINT_EQUALITY", "FE_TEST_IF_EQUAL_TO_NOT_A_NUMBER", @@ -787,7 +789,9 @@ def main() -> None: "EQ_DOESNT_OVERRIDE_EQUALS", "CO_COMPARETO_INCORRECT_FLOATING", "DL_SYNCHRONIZATION_ON_SHARED_CONSTANT", + "SSD_DO_NOT_USE_INSTANCE_LOCK_ON_SHARED_STATIC_DATA", "DLS_DEAD_LOCAL_STORE", + "DLS_DEAD_LOCAL_STORE_OF_NULL", "DM_NUMBER_CTOR", "DMI_INVOKING_TOSTRING_ON_ARRAY", "EC_NULL_ARG", @@ -819,6 +823,7 @@ def main() -> None: "NO_NOTIFY_NOT_NOTIFYALL", "NP_LOAD_OF_KNOWN_NULL_VALUE", "NP_BOOLEAN_RETURN_NULL", + "RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN", "REFLC_REFLECTION_MAY_INCREASE_ACCESSIBILITY_OF_CLASS", "REC_CATCH_EXCEPTION", "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", diff --git a/CodenameOne/src/com/codename1/facebook/FacebookRESTService.java b/CodenameOne/src/com/codename1/facebook/FacebookRESTService.java index f9c8ad68d1..82a6b05926 100644 --- a/CodenameOne/src/com/codename1/facebook/FacebookRESTService.java +++ b/CodenameOne/src/com/codename1/facebook/FacebookRESTService.java @@ -239,8 +239,11 @@ public void numericToken(double tok) { } public void keyValue(String key, String value) { + if (key == null) { + return; + } //make sure value is not null to prevent NPE - if (key != null && value == null) { + if (value == null) { value = ""; } getCurrent().put(key, value); diff --git a/CodenameOne/src/com/codename1/io/gzip/DeflaterOutputStream.java b/CodenameOne/src/com/codename1/io/gzip/DeflaterOutputStream.java index eb3a2733a9..71dcc2f4a2 100644 --- a/CodenameOne/src/com/codename1/io/gzip/DeflaterOutputStream.java +++ b/CodenameOne/src/com/codename1/io/gzip/DeflaterOutputStream.java @@ -84,7 +84,7 @@ public void write(int b) throws IOException { public void write(byte[] b, int off, int len) throws IOException { if (deflater.finished()) { throw new IOException("finished"); - } else if (off < 0 | len < 0 | off + len > b.length) { + } else if (off < 0 || len < 0 || off + len > b.length) { throw new IndexOutOfBoundsException(); } else if (len == 0) { } else { diff --git a/CodenameOne/src/com/codename1/location/LocationManager.java b/CodenameOne/src/com/codename1/location/LocationManager.java index cb29be9d96..1cd246771c 100644 --- a/CodenameOne/src/com/codename1/location/LocationManager.java +++ b/CodenameOne/src/com/codename1/location/LocationManager.java @@ -52,6 +52,7 @@ public abstract class LocationManager { public static final int OUT_OF_SERVICE = 1; public static final int TEMPORARILY_UNAVAILABLE = 2; private static LocationListener listener; + private static final Object LISTENER_LOCK = new Object(); private LocationRequest request; private static Class backgroundlistener; private int status = TEMPORARILY_UNAVAILABLE; @@ -198,7 +199,7 @@ protected LocationListener getLocationListener() { * from getting updates */ public void setLocationListener(final LocationListener l) { - synchronized (this) { + synchronized (LISTENER_LOCK) { if (listener != null) { clearListener(); request = null; @@ -243,7 +244,7 @@ protected Class getBackgroundLocationListener() { * try to create an instance and invoke the locationUpdated method */ public void setBackgroundLocationListener(Class locationListener) { - synchronized (this) { + synchronized (LISTENER_LOCK) { if (backgroundlistener != null) { clearBackgroundListener(); } diff --git a/CodenameOne/src/com/codename1/properties/InstantUI.java b/CodenameOne/src/com/codename1/properties/InstantUI.java index 6802aca598..b13fc8e6c1 100644 --- a/CodenameOne/src/com/codename1/properties/InstantUI.java +++ b/CodenameOne/src/com/codename1/properties/InstantUI.java @@ -81,7 +81,7 @@ public void excludeProperties(PropertyBase... exclude) { * @return true if the property was excluded from the GUI */ public boolean isExcludedProperty(PropertyBase exclude) { - return exclude.getClientProperty("cn1$excludeFromUI") == Boolean.TRUE; + return Boolean.TRUE.equals(exclude.getClientProperty("cn1$excludeFromUI")); } /** diff --git a/CodenameOne/src/com/codename1/ui/BrowserComponent.java b/CodenameOne/src/com/codename1/ui/BrowserComponent.java index afc234a438..eeefc7bd05 100644 --- a/CodenameOne/src/com/codename1/ui/BrowserComponent.java +++ b/CodenameOne/src/com/codename1/ui/BrowserComponent.java @@ -1601,7 +1601,7 @@ public void putClientProperty(String key, Object value) { * @return true if debug mode was activated */ public boolean isDebugMode() { - return getClientProperty("BrowserComponent.firebug") == Boolean.TRUE; + return Boolean.TRUE.equals(getClientProperty("BrowserComponent.firebug")); } /** diff --git a/CodenameOne/src/com/codename1/ui/html/HTMLComponent.java b/CodenameOne/src/com/codename1/ui/html/HTMLComponent.java index 1fe1a7aedd..5be218e7d2 100644 --- a/CodenameOne/src/com/codename1/ui/html/HTMLComponent.java +++ b/CodenameOne/src/com/codename1/ui/html/HTMLComponent.java @@ -463,13 +463,13 @@ public HTMLComponent(DocumentRequestHandler handler) { * @param font The actual Codename One font object */ public static void addFont(String fontKey, Font font) { - if (fontKey != null) { - fontKey = fontKey.toLowerCase(); - } else { + if (fontKey == null) { if (font.getCharset() != null) { throw new IllegalArgumentException("Font key must be non-null for bitmap fonts"); } + throw new IllegalArgumentException("Font key must be non-null"); } + fontKey = fontKey.toLowerCase(); fonts.put(fontKey, new HTMLFont(fontKey, font)); } diff --git a/CodenameOne/src/com/codename1/ui/plaf/UIManager.java b/CodenameOne/src/com/codename1/ui/plaf/UIManager.java index 98c405b3ef..c88228a367 100644 --- a/CodenameOne/src/com/codename1/ui/plaf/UIManager.java +++ b/CodenameOne/src/com/codename1/ui/plaf/UIManager.java @@ -1901,7 +1901,6 @@ Style createStyle(String id, String prefix, boolean selected) { style = new Style(getComponentStyle(baseStyle)); } } else { - baseStyle = null; if (selected) { style = new Style(defaultSelectedStyle); } else { diff --git a/CodenameOne/src/com/codename1/util/TBigInteger.java b/CodenameOne/src/com/codename1/util/TBigInteger.java index 8f2a34baf5..1581e4499d 100644 --- a/CodenameOne/src/com/codename1/util/TBigInteger.java +++ b/CodenameOne/src/com/codename1/util/TBigInteger.java @@ -1240,7 +1240,7 @@ public TBigInteger modPow(TBigInteger exponent, TBigInteger m) { } TBigInteger base = this; - if (m.isOne() | (exponent.sign > 0 & base.sign == 0)) { + if (m.isOne() || (exponent.sign > 0 && base.sign == 0)) { return TBigInteger.ZERO; } if (exponent.sign == 0) { From 4efa5650366dcbb187c04240e562596771189d27 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Thu, 15 Jan 2026 17:14:30 +0200 Subject: [PATCH 4/9] tail end of big spotbugs issues (#4419) --- .github/scripts/generate-quality-report.py | 4 ++ .../impl/CodenameOneImplementation.java | 13 +++--- .../com/codename1/impl/CodenameOneThread.java | 10 ++++- .../com/codename1/testing/DeviceRunner.java | 16 +++++--- maven/core-unittests/spotbugs-exclude.xml | 41 +++++++++++++++++++ 5 files changed, 69 insertions(+), 15 deletions(-) diff --git a/.github/scripts/generate-quality-report.py b/.github/scripts/generate-quality-report.py index 9084a2a20f..f6b4cb24a2 100755 --- a/.github/scripts/generate-quality-report.py +++ b/.github/scripts/generate-quality-report.py @@ -778,6 +778,7 @@ def main() -> None: "FE_FLOATING_POINT_EQUALITY", "FE_TEST_IF_EQUAL_TO_NOT_A_NUMBER", "ICAST_IDIV_CAST_TO_DOUBLE", + "ICAST_QUESTIONABLE_UNSIGNED_RIGHT_SHIFT", "SA_FIELD_SELF_ASSIGNMENT", "UC_USELESS_CONDITION", "UC_USELESS_OBJECT", @@ -824,6 +825,7 @@ def main() -> None: "NP_LOAD_OF_KNOWN_NULL_VALUE", "NP_BOOLEAN_RETURN_NULL", "RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN", + "OS_OPEN_STREAM", "REFLC_REFLECTION_MAY_INCREASE_ACCESSIBILITY_OF_CLASS", "REC_CATCH_EXCEPTION", "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", @@ -865,6 +867,8 @@ def _is_exempt(f: Finding) -> bool: return True if f.rule == "NN_NAKED_NOTIFY" and "Display.java" in loc: return True + if f.rule == "ICAST_QUESTIONABLE_UNSIGNED_RIGHT_SHIFT" and "Deflate.java" in loc: + return True return False diff --git a/CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java b/CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java index b329e3adca..0fcad66206 100644 --- a/CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java +++ b/CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java @@ -3966,10 +3966,7 @@ public Rectangle getDisplaySafeArea(Rectangle rect) { * common constants in this class or be a user/implementation defined sound */ public void playBuiltinSound(String soundIdentifier) { - boolean played = playUserSound(soundIdentifier); - if (!played) { - return; - } + playUserSound(soundIdentifier); } /** @@ -3977,11 +3974,11 @@ public void playBuiltinSound(String soundIdentifier) { * * @param soundIdentifier the sound identifier which can match one of the * common constants in this class or be a user/implementation defined sound - * @return true if a user sound exists and was sent to playback */ - protected boolean playUserSound(String soundIdentifier) { - Object sound = builtinSounds.get(soundIdentifier); - return sound != null; + protected void playUserSound(String soundIdentifier) { + // TODO: Reintroduce builitin sound support + //Object sound = builtinSounds.get(soundIdentifier); + //return sound != null; //playAudio(sound); } diff --git a/CodenameOne/src/com/codename1/impl/CodenameOneThread.java b/CodenameOne/src/com/codename1/impl/CodenameOneThread.java index 66dd820798..021ed7a562 100644 --- a/CodenameOne/src/com/codename1/impl/CodenameOneThread.java +++ b/CodenameOne/src/com/codename1/impl/CodenameOneThread.java @@ -23,6 +23,7 @@ package com.codename1.impl; import com.codename1.io.Log; +import com.codename1.io.Util; import com.codename1.ui.Display; import java.io.DataInputStream; @@ -133,6 +134,8 @@ public void storeStackForException(Throwable t, int currentStackFrame) { * Prints the stack trace matching the given stack */ public String getStack(Throwable t) { + InputStream inp = null; + DataInputStream di = null; try { StringBuilder b = new StringBuilder(); int size; @@ -145,11 +148,11 @@ public String getStack(Throwable t) { } String[] stk = new String[size]; - InputStream inp = Display.getInstance().getResourceAsStream(getClass(), "/methodData.dat"); + inp = Display.getInstance().getResourceAsStream(getClass(), "/methodData.dat"); if (inp == null) { return t.toString(); } - DataInputStream di = new DataInputStream(inp); + di = new DataInputStream(inp); int totalAmount = di.readInt(); String lastClass = ""; for (int x = 0; x < totalAmount; x++) { @@ -172,6 +175,9 @@ public String getStack(Throwable t) { return b.toString(); } catch (IOException ex) { ex.printStackTrace(); + } finally { + Util.cleanup(di); + Util.cleanup(inp); } return "Failed in stack generation for " + t; } diff --git a/CodenameOne/src/com/codename1/testing/DeviceRunner.java b/CodenameOne/src/com/codename1/testing/DeviceRunner.java index 04c5405b7a..503e47336f 100644 --- a/CodenameOne/src/com/codename1/testing/DeviceRunner.java +++ b/CodenameOne/src/com/codename1/testing/DeviceRunner.java @@ -23,6 +23,7 @@ package com.codename1.testing; import com.codename1.io.Log; +import com.codename1.io.Util; import com.codename1.ui.CN; import com.codename1.ui.Display; @@ -48,8 +49,10 @@ public void runTests() { failedTests = 0; passedTests = 0; Log.p("-----STARTING TESTS-----"); + InputStream is = null; + DataInputStream di = null; try { - InputStream is = DeviceRunner.class.getResourceAsStream("/tests.dat"); + is = DeviceRunner.class.getResourceAsStream("/tests.dat"); if (is == null) { is = Display.getInstance().getResourceAsStream(null, "/tests.dat"); @@ -60,7 +63,7 @@ public void runTests() { System.exit(2); return; } - DataInputStream di = new DataInputStream(is); + di = new DataInputStream(is); int version = di.readInt(); if (version > VERSION) { Log.p("Tests were built with a new version of Codename One and can't be executed with this runner"); @@ -72,13 +75,16 @@ public void runTests() { for (int iter = 0; iter < tests.length; iter++) { tests[iter] = di.readUTF(); } - di.close(); + Util.cleanup(di); - for (int iter = 0; iter < tests.length; iter++) { - runTest(tests[iter]); + for (String test : tests) { + runTest(test); } } catch (IOException err) { TestReporting.getInstance().logException(err); + } finally { + Util.cleanup(is); + Util.cleanup(di); } TestReporting.getInstance().testExecutionFinished(getClass().getName()); if (failedTests > 0) { diff --git a/maven/core-unittests/spotbugs-exclude.xml b/maven/core-unittests/spotbugs-exclude.xml index 221cdb8d49..7626676ffb 100644 --- a/maven/core-unittests/spotbugs-exclude.xml +++ b/maven/core-unittests/spotbugs-exclude.xml @@ -151,6 +151,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +