Fix CodeQL note-severity alerts: deprecated JDK calls and inefficient expressions - #823
Conversation
… expressions
Migrate away from JDK and third party API deprecated in Java 9 and later, and
apply the mechanical cleanups reported by the java/inefficient-* queries:
* Class.newInstance() is replaced with getDeclaredConstructor().newInstance() in
the 53 places where components are loaded reflectively. All of these call sites
already caught Exception, except the quicksetup application loader whose catch
clauses now also handle NoSuchMethodException and InvocationTargetException.
* X509Certificate.getSubjectDN()/getIssuerDN(), which return a Principal from the
internal sun.security API, are replaced with getSubjectX500Principal() and
getIssuerX500Principal(). The call sites either print the DN, log it or use it
as a trust store alias; Platform.isSelfSigned() now compares the canonical
X.500 forms of the two DNs.
* new Integer/Long/Byte(...) are replaced with valueOf(...), the Provider
constructor taking a double version with the one taking a version string,
JList.getSelectedValues() with getSelectedValuesList(),
JsonParser.getCurrentName() with currentName(), and InputEvent.getModifiers()
with getModifiersEx().
* equals("") is replaced with isEmpty(), new String(literal) with the literal
itself, and two key set iterations with entry set iterations.
* LDIF.toLDIF() no longer calls toString() on the writer it has just written to,
ReturnCode gets a toString(), and the replication trace logs the DN of the
initialize task instead of its identity hash.
* Two @throws tags documenting an exception which cannot be thrown are removed.
Left alone: the calls to the deprecated internal API of the server itself
(ObjectClass.isPlaceHolder, AttributeDescription.getNameOrOID, Entry.addAttribute,
DirectoryServer.getConfigEntry and friends), which need a real migration rather
than a mechanical change; Subject.getSubject(), whose replacement Subject.current()
requires Java 18 while the project targets Java 11; and five "".equals(x) tests
which are deliberately null safe.
maximthomas
left a comment
There was a problem hiding this comment.
LGTM.
One thing worth fixing: getDeclaredConstructor().newInstance() wraps constructor failures, and InvocationTargetException.toString() is just the class name with a null message. Ten sites format the throwable with %s, so:
before: ...does not contain a valid extended operation handler implementation:
java.lang.IllegalStateException: keystore file /opt/opendj/keys.p12 is unreadable
after: ...does not contain a valid extended operation handler implementation:
java.lang.reflect.InvocationTargetException
…tiation error messages getDeclaredConstructor().newInstance() wraps constructor failures in InvocationTargetException, whose toString() is just the class name. At the ten sites that format the caught exception with %s, format it via getExceptionMessage()/stackTraceToSingleLineString() instead — both unwrap the InvocationTargetException — so the message shows the real cause again.
|
@maximthomas Good catch, fixed in 9d5b399. Exactly ten sites formatted the caught exception with |
Third batch of note-severity code scanning fixes (after #814 and #817). Mechanical migration away from deprecated JDK/third party API plus the
java/inefficient-*cleanups — about 135 alerts, no behaviour change intended.Deprecated JDK and third party calls (88 of the 180
java/deprecated-callalerts)Class.newInstance()→getDeclaredConstructor().newInstance()(53) — deprecated since Java 9 because it silently propagates the checked exceptions thrown by the constructor. The call sites are the reflective component loaders (*ConfigManager,AbstractLogger,TaskScheduler,RecurringTask,SchemaHandler, makeldifTemplateFile, …); all of them already catchException, so the only structural change is in the quicksetup application loader, whose narrow catch clauses now also handleNoSuchMethodExceptionandInvocationTargetException.Review follow-up: the new call wraps constructor failures in
InvocationTargetException, whosetoString()is just the class name, so the ten sites that formatted the caught exception with%s(bothTemplateFiles,ExtendedOperationConfigManager,LogRetentionPolicyConfigManager,LogRotationPolicyConfigManager,AbstractLogger) now format it viagetExceptionMessage()/stackTraceToSingleLineString()— both unwrap theInvocationTargetException— so the error message shows the real cause.X509Certificate.getSubjectDN()/getIssuerDN()→getSubjectX500Principal()/getIssuerX500Principal()(20) — the deprecated accessors return aPrincipalimplemented by the internalsun.securityAPI. Every call site either prints the DN, logs it, or uses it as a trust store alias;Platform.isSelfSigned()now compares the canonical X.500 forms, which is stricter than the previousPrincipal.equals().new Integer/Long/Byte(...)→valueOf(...)(8, SNMP), theProvider(String, double, String)constructor → the version-string one (1),JList.getSelectedValues()→getSelectedValuesList()(3, which also removes three@SuppressWarnings("deprecation")),JsonParser.getCurrentName()→currentName()(2),InputEvent.getModifiers()→getModifiersEx()(1).Inefficient expressions and small defects (47)
s.equals("")/"".equals(s)→s.isEmpty()— 30 of 35 alerts.new String("literal")→ the literal (1); twokeySet()iterations that immediately callmap.get(key)→entrySet()iterations (3).java/call-to-object-tostring(3):LDIF.toLDIF()calledtoString()on the writer it had just written to and discarded the result — removed;ReturnCodegained atoString()so that it no longer logs asReturnCode@1a2b3c; the replication trace logs the DN of the initialize task instead of its identity hash.java/inconsistent-javadoc-throws(2): removed two@throwstags for exceptions the methods cannot throw.Alerts deliberately left open
java/deprecated-callon the server's own deprecated API (ObjectClass.isPlaceHolder27,AttributeDescription.getNameOrOID20,Entry.addAttribute/removeAttribute23,DirectoryServer.getConfigEntry9,AttributeDescription.create7, …). That is an internal API migration, not a mechanical change, and belongs in its own work.Subject.getSubject()(1) — the replacementSubject.current()requires Java 18; this project targets Java 11."".equals(x)tests (ConsoleApplication,LDIFChangeRecordReader,NewSchemaElementsTask,InstallDS,Installer) where the literal-first form is deliberately null safe andx.isEmpty()would throw.Testing
Full test suites:
opendj-core8173 tests,opendj-rest2ldap531 tests,opendj-cli46 tests — all passing.opendj-server-legacy(-Pprecommit), classes exercising server startup — which is what loads every component reflectively — plus groups, password policies, schema, tasks, makeldif and LDIF import/export:SchemaBackendTestCase(165),PasswordPolicyTestCase(144),TaskBackendTestCase(62),HostPortTest(37),LDAPURLTest(29),GroupManagerTestCase(25),LDIFBackendTestCase(22),MakeLDIFTestCase(17),TestBackupAndRestore(12),TestImportAndExport(12),SubentryPasswordPolicyTestCase(11),LDAPURLTestCase(8) — all passing.Four of these classes initially failed in
setUp/startServerwithIOException(Address already in use)while binding the administration connector to its fixed port; another OpenDJ test JVM was running concurrently on the same machine and holding ports 65534/65528. All four pass when re-run against a free port.After the review follow-up: both modules recompiled,
EntryGeneratorTestCase(33) andTemplateTagTestCase(21) re-run — passing.