From 94abefeb90d65e9fe2ce9003476988d55fea1dbb Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 18 Sep 2026 19:27:25 +0300 Subject: [PATCH 1/4] Fix mechanical CodeQL note findings: reflection, boxing, deprecated closes Class.newInstance() is replaced with getDeclaredConstructor().newInstance() at every call site (20): all are already inside a catch (Exception) or catch (Throwable), or declared throws Exception, so the extra checked NoSuchMethodException needs no new handling. new Integer/Long/Boolean/Double/Float/Character(String) become valueOf/ parseX (19 sites); new String(x) becomes x. SQLUtil.closeQuietly(Connection/Statement/ResultSet), deprecated in favour of IOUtil.quietClose, is replaced at its 23 call sites, including its own internal use. IOUtil.quietClose(Connection) was missing the isClosed() check SQLUtil.closeQuietly(Connection) has, so it called close() on an already-closed connection where the old code did not; two tests using a strict-sequence mock caught it. IOUtil.quietClose(Connection) now checks isClosed() first, matching what it replaces. Plexus IOUtil.close(Closeable) ("deprecated: use try-with-resources instead") is replaced by try-with-resources at its 3 call sites in the maven plugin. XMLConfiguration.validate and GroovyDataProvider no longer ignore the return value of mkdir()/createNewFile(): a real failure now surfaces through the existing IOException handling instead of being silently masked by the following canWrite() check. Small ones: PrettyStringBuilder iterates entrySet() instead of keySet() followed by get(); StringUtil.isEmpty and an XSD annotation check use isEmpty() instead of comparing to ""; a missing space in a concatenated message and a stray comma in a @param tag are fixed. --- .../DatabaseTableConnection.java | 3 +- .../databasetable/DatabaseTableConnector.java | 31 ++++++++++--------- .../dbcommon/DatabaseConnection.java | 5 +-- .../identityconnectors/dbcommon/SQLUtil.java | 16 +++++----- .../contract/data/GroovyDataProvider.java | 8 ++--- .../contract/data/RandomGenerator.java | 15 ++++----- .../contract/test/ConnectorHelper.java | 4 +-- .../contract/test/MultiOpTests.java | 3 +- .../impl/api/local/ConnectorPoolManager.java | 3 +- .../impl/api/local/JavaClassProperties.java | 2 +- .../local/LocalConnectorInfoManagerImpl.java | 2 +- .../ConnectorAPIOperationRunnerProxy.java | 3 +- .../framework/server/ConnectorServer.java | 2 +- .../OsgiConnectorInfoManagerImpl.java | 2 +- .../AsyncOsgiConnectorInfoManagerImpl.java | 2 +- .../org/identityconnectors/common/IOUtil.java | 2 +- .../common/PrettyStringBuilder.java | 9 +++--- .../identityconnectors/common/StringUtil.java | 3 +- .../common/logging/Log.java | 3 +- .../common/script/ScriptExecutorFactory.java | 5 +-- .../common/security/EncryptorFactory.java | 3 +- .../framework/api/ConnectorFacadeFactory.java | 5 +-- .../api/ConnectorInfoManagerFactory.java | 2 +- .../serializer/ObjectSerializerFactory.java | 2 +- .../test/common/TestHelpers.java | 5 +-- .../ActiveDirectoryChangeLogSyncStrategy.java | 3 +- .../openicf/maven/ConnectorDocBuilder.java | 2 +- .../maven/ConnectorInfoReportMojo.java | 6 +--- .../openicf/maven/DocBookResourceMojo.java | 6 +--- .../openicf/maven/ReducePomMojo.java | 6 +--- .../connectors/xml/XMLConfiguration.java | 6 +++- .../xml/util/AttributeTypeUtil.java | 24 +++++++------- .../xml/xsdparser/XSDAnnotationParser.java | 3 +- 33 files changed, 102 insertions(+), 94 deletions(-) diff --git a/OpenICF-databasetable-connector/src/main/java/org/identityconnectors/databasetable/DatabaseTableConnection.java b/OpenICF-databasetable-connector/src/main/java/org/identityconnectors/databasetable/DatabaseTableConnection.java index 5797c1265..779a29fdf 100644 --- a/OpenICF-databasetable-connector/src/main/java/org/identityconnectors/databasetable/DatabaseTableConnection.java +++ b/OpenICF-databasetable-connector/src/main/java/org/identityconnectors/databasetable/DatabaseTableConnection.java @@ -38,6 +38,7 @@ import java.util.Map; import org.identityconnectors.common.StringUtil; +import org.identityconnectors.common.IOUtil; import org.identityconnectors.common.logging.Log; import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.databasetable.mapping.AttributeConvertor; @@ -289,7 +290,7 @@ public void test() { // nothing to do, just invalidate the connection throw new ConnectorException(config.getMessage(MSG_CAN_NOT_READ, sql), ex); } finally { - SQLUtil.closeQuietly(stmt); + IOUtil.quietClose(stmt); } } } diff --git a/OpenICF-databasetable-connector/src/main/java/org/identityconnectors/databasetable/DatabaseTableConnector.java b/OpenICF-databasetable-connector/src/main/java/org/identityconnectors/databasetable/DatabaseTableConnector.java index ed3722c3b..ea7ff3661 100644 --- a/OpenICF-databasetable-connector/src/main/java/org/identityconnectors/databasetable/DatabaseTableConnector.java +++ b/OpenICF-databasetable-connector/src/main/java/org/identityconnectors/databasetable/DatabaseTableConnector.java @@ -58,6 +58,7 @@ import org.identityconnectors.common.Assertions; import org.identityconnectors.common.CollectionUtil; +import org.identityconnectors.common.IOUtil; import org.identityconnectors.common.StringUtil; import org.identityconnectors.common.logging.Log; import org.identityconnectors.common.security.GuardedString; @@ -323,7 +324,7 @@ public Uid create(ObjectClass oclass, Set attrs, OperationOptions opt } } finally { // clean up... - SQLUtil.closeQuietly(pstmt); + IOUtil.quietClose(pstmt); closeConnection(); } log.ok("Account {0} created", accountName); @@ -404,7 +405,7 @@ public void delete(final ObjectClass oclass, final Uid uid, final OperationOptio throw new ConnectorException(config.getMessage(MSG_CAN_NOT_DELETE, accountUid), e); } finally { // clean up.. - SQLUtil.closeQuietly(stmt); + IOUtil.quietClose(stmt); closeConnection(); } log.ok("Account Uid {0} deleted", accountUid); @@ -489,7 +490,7 @@ public Uid update(ObjectClass oclass, Uid uid, Set attrs, OperationOp } } finally { // clean up.. - SQLUtil.closeQuietly(stmt); + IOUtil.quietClose(stmt); closeConnection(); } @@ -562,8 +563,8 @@ public void executeQuery(ObjectClass oclass, FilterWhereBuilder where, ResultsHa throw new ConnectorException(config.getMessage(MSG_CAN_NOT_READ, tblname), e); } } finally { - SQLUtil.closeQuietly(result); - SQLUtil.closeQuietly(statement); + IOUtil.quietClose(result); + IOUtil.quietClose(statement); closeConnection(); } log.ok("Query Account commited"); @@ -643,8 +644,8 @@ public void sync(ObjectClass oclass, SyncToken token, SyncResultsHandler handler SQLUtil.rollbackQuietly(getConn()); throw new ConnectorException(config.getMessage(MSG_CAN_NOT_READ, tblname), e); } finally { - SQLUtil.closeQuietly(result); - SQLUtil.closeQuietly(statement); + IOUtil.quietClose(result); + IOUtil.quietClose(statement); closeConnection(); } @@ -701,8 +702,8 @@ public SyncToken getLatestSyncToken(ObjectClass oclass) { throw new ConnectorException(config.getMessage(MSG_CAN_NOT_READ, tblname), e); } finally { // clean up.. - SQLUtil.closeQuietly(rset); - SQLUtil.closeQuietly(stmt); + IOUtil.quietClose(rset); + IOUtil.quietClose(stmt); closeConnection(); } @@ -840,8 +841,8 @@ public Uid authenticate(ObjectClass oclass, String username, GuardedString passw SQLUtil.rollbackQuietly(getConn()); throw new ConnectorException(config.getMessage(MSG_CAN_NOT_READ, config.getTable()), e); } finally { - SQLUtil.closeQuietly(result); - SQLUtil.closeQuietly(stmt); + IOUtil.quietClose(result); + IOUtil.quietClose(stmt); closeConnection(); } @@ -904,8 +905,8 @@ public Uid resolveUsername(ObjectClass oclass, String username, OperationOptions SQLUtil.rollbackQuietly(getConn()); throw new ConnectorException(config.getMessage(MSG_CAN_NOT_READ, config.getTable()), e); } finally { - SQLUtil.closeQuietly(result); - SQLUtil.closeQuietly(stmt); + IOUtil.quietClose(result); + IOUtil.quietClose(stmt); closeConnection(); } @@ -1059,8 +1060,8 @@ private Set buildSelectBasedAttributeInfos() { SQLUtil.rollbackQuietly(getConn()); throw new ConnectorException(config.getMessage(MSG_CAN_NOT_READ, config.getTable()), ex); } finally { - SQLUtil.closeQuietly(rset); - SQLUtil.closeQuietly(stmt); + IOUtil.quietClose(rset); + IOUtil.quietClose(stmt); } log.ok("schema created"); return attrInfo; diff --git a/OpenICF-dbcommon/src/main/java/org/identityconnectors/dbcommon/DatabaseConnection.java b/OpenICF-dbcommon/src/main/java/org/identityconnectors/dbcommon/DatabaseConnection.java index 7671eff5c..b7b23f508 100644 --- a/OpenICF-dbcommon/src/main/java/org/identityconnectors/dbcommon/DatabaseConnection.java +++ b/OpenICF-dbcommon/src/main/java/org/identityconnectors/dbcommon/DatabaseConnection.java @@ -19,6 +19,7 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.dbcommon; @@ -30,6 +31,7 @@ import java.util.List; import org.identityconnectors.common.logging.Log; +import org.identityconnectors.common.IOUtil; import org.identityconnectors.framework.common.exceptions.ConnectorException; import org.identityconnectors.framework.spi.Configuration; @@ -76,9 +78,8 @@ public DatabaseConnection(final Connection conn) { /** * Closes the internal {@link java.sql.Connection}. */ - @SuppressWarnings("deprecation") public void dispose() { - SQLUtil.closeQuietly(nativeConn); + IOUtil.quietClose(nativeConn); } /** diff --git a/OpenICF-dbcommon/src/main/java/org/identityconnectors/dbcommon/SQLUtil.java b/OpenICF-dbcommon/src/main/java/org/identityconnectors/dbcommon/SQLUtil.java index 6aef2ed80..2d75528a1 100644 --- a/OpenICF-dbcommon/src/main/java/org/identityconnectors/dbcommon/SQLUtil.java +++ b/OpenICF-dbcommon/src/main/java/org/identityconnectors/dbcommon/SQLUtil.java @@ -320,7 +320,7 @@ public static void closeQuietly(final Connection connection) { */ public static void closeQuietly(final DatabaseConnection conn) { if (conn != null) { - closeQuietly(conn.getConnection()); + IOUtil.quietClose(conn.getConnection()); } } @@ -434,7 +434,7 @@ public static java.sql.Date string2Date(String param) { } catch (IllegalArgumentException e) { // Wrong string, cloud be a string number try { - parsedDate = new java.sql.Date(new Long(param)); + parsedDate = new java.sql.Date(Long.parseLong(param)); } catch (NumberFormatException expected) { // Locale parsed date, possible lost of precision try { @@ -462,7 +462,7 @@ public static java.sql.Timestamp string2Timestamp(String param) { } catch (IllegalArgumentException e) { // Wrong string, cloud be a number try { - parsedTms = new java.sql.Timestamp(new Long(param)); + parsedTms = new java.sql.Timestamp(Long.parseLong(param)); } catch (NumberFormatException expected) { // Locale parsed date, possible lost of precision try { @@ -1051,8 +1051,8 @@ public static Object selectSingleValue(Connection conn, String sql, SQLParam... } return null; } finally { - closeQuietly(rs); - closeQuietly(st); + IOUtil.quietClose(rs); + IOUtil.quietClose(st); } } @@ -1096,8 +1096,8 @@ public static List selectRows(Connection conn, String sql, SQLParam... } return rows; } finally { - closeQuietly(rs); - closeQuietly(st); + IOUtil.quietClose(rs); + IOUtil.quietClose(st); } } @@ -1128,7 +1128,7 @@ public static int executeUpdateStatement(Connection conn, String sql, SQLParam.. setParams(st, Arrays.asList(params)); return st.executeUpdate(); } finally { - closeQuietly(st); + IOUtil.quietClose(st); } } } diff --git a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/GroovyDataProvider.java b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/GroovyDataProvider.java index 0263c309b..ff4a519ca 100644 --- a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/GroovyDataProvider.java +++ b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/GroovyDataProvider.java @@ -238,8 +238,8 @@ private void initQueriedPropsDump() { if (StringUtil.isNotBlank(pOut)) { try { _queriedPropsOutFile = new File(pOut); - if (!_queriedPropsOutFile.exists()) { - _queriedPropsOutFile.createNewFile(); + if (!_queriedPropsOutFile.exists() && !_queriedPropsOutFile.createNewFile()) { + throw new IOException("Could not create " + _queriedPropsOutFile); } if (!_queriedPropsOutFile.canWrite()) { _queriedPropsOutFile = null; @@ -263,8 +263,8 @@ private void initSnapshot() { if (StringUtil.isNotBlank(pOut)) { try { _propertyOutFile = new File(pOut); - if (!_propertyOutFile.exists()) { - _propertyOutFile.createNewFile(); + if (!_propertyOutFile.exists() && !_propertyOutFile.createNewFile()) { + throw new IOException("Could not create " + _propertyOutFile); } if (!_propertyOutFile.canWrite()) { _propertyOutFile = null; diff --git a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/RandomGenerator.java b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/RandomGenerator.java index 0f77cb6e4..ca03d4819 100644 --- a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/RandomGenerator.java +++ b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/RandomGenerator.java @@ -19,6 +19,7 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.contract.data; @@ -154,11 +155,11 @@ private static Map> getDefaultCharacterSetMap() { alpha_mixed.addAll(alpha_upper); // setup the mappings - characterSetMap.put(new Character('#'), numeric); - characterSetMap.put(new Character('a'), alpha_lower); - characterSetMap.put(new Character('A'), alpha_upper); - characterSetMap.put(new Character('?'), alpha_mixed); - characterSetMap.put(new Character('.'), alpha_numeric); + characterSetMap.put(Character.valueOf('#'), numeric); + characterSetMap.put(Character.valueOf('a'), alpha_lower); + characterSetMap.put(Character.valueOf('A'), alpha_upper); + characterSetMap.put(Character.valueOf('?'), alpha_mixed); + characterSetMap.put(Character.valueOf('.'), alpha_numeric); return characterSetMap; } @@ -179,7 +180,7 @@ private static void addRange(Set s, char min, char max) { } for (char i = min; i <= max; i++) { - s.add(new Character(i)); + s.add(Character.valueOf(i)); } } @@ -212,7 +213,7 @@ private static String createRandomString(String pattern, Map> characterSetMap) { StringBuffer replacement = new StringBuffer(); for (int i = 0; i < pattern.length(); i++) { - Set characterSet = characterSetMap.get(new Character( + Set characterSet = characterSetMap.get(Character.valueOf( pattern.charAt(i))); if (pattern.charAt(i) == '\\') { // do escape, and print the next character diff --git a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ConnectorHelper.java b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ConnectorHelper.java index ae9be0048..536406931 100644 --- a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ConnectorHelper.java +++ b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ConnectorHelper.java @@ -119,10 +119,10 @@ public static DataProvider createDataProvider() { throw new Exception("Class " + customDataProvider + " is not of type " + DataProvider.class.getName()); } - dp = (DataProvider) dpClass.newInstance(); + dp = (DataProvider) dpClass.getDeclaredConstructor().newInstance(); } else { logger.info("DataProvider class not specified, using default ''"+DEFAULT_DATA_PROVIDER+"''."); - dp = (DataProvider) DEFAULT_DATA_PROVIDER.newInstance(); + dp = (DataProvider) DEFAULT_DATA_PROVIDER.getDeclaredConstructor().newInstance(); } } catch (Exception ex) { throw ContractException.wrap(ex); diff --git a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/MultiOpTests.java b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/MultiOpTests.java index dabb83b72..b273ef188 100644 --- a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/MultiOpTests.java +++ b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/MultiOpTests.java @@ -21,6 +21,7 @@ * ==================== * * Portions Copyrighted 2012 ForgeRock AS + * Portions Copyrighted 2026 3A Systems, LLC * */ package org.identityconnectors.contract.test; @@ -580,7 +581,7 @@ public void testPasswordChangeIntervalPredAttribute(ObjectClass objectClass) { * @param createValue value used for create * @param updateValue value used for update * @param type expected type of the value - * @param addPassword, add password to attributes in the update + * @param addPassword add password to attributes in the update */ private void checkOpAttribute(ObjectClass objectClass, String attrName, Object createValue, Object updateValue, Class type, boolean addPassword) { final int iteration = 0; diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/ConnectorPoolManager.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/ConnectorPoolManager.java index d580a08e1..1605d3531 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/ConnectorPoolManager.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/ConnectorPoolManager.java @@ -20,6 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * Portions Copyrighted 2010-2013 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.framework.impl.api.local; @@ -165,7 +166,7 @@ public PoolableConnector makeObject() { config = context.getConfiguration(); } - connector = (PoolableConnector) clazz.newInstance(); + connector = (PoolableConnector) clazz.getDeclaredConstructor().newInstance(); connector.init(config); } else { throw new ConnectorException("The Connector is not PoolableConnector: " diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/JavaClassProperties.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/JavaClassProperties.java index 1769a5b1f..7601fc68b 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/JavaClassProperties.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/JavaClassProperties.java @@ -216,7 +216,7 @@ private static Set> translateOperations( private static Configuration createBean2(ConfigurationPropertiesImpl properties, Class configClass) throws Exception { - Configuration rv = configClass.newInstance(); + Configuration rv = configClass.getDeclaredConstructor().newInstance(); rv.setConnectorMessages(properties.getParent().getConnectorInfo().getMessages()); mergeIntoBean2(properties, rv); return rv; diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/LocalConnectorInfoManagerImpl.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/LocalConnectorInfoManagerImpl.java index 18c5701d6..892f9e9bd 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/LocalConnectorInfoManagerImpl.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/LocalConnectorInfoManagerImpl.java @@ -326,7 +326,7 @@ public static APIConfigurationImpl createDefaultAPIConfiguration( try { final Class connectorClass = localInfo.getConnectorClass(); final APIConfigurationImpl rv = new APIConfigurationImpl(); - final Configuration config = localInfo.getConnectorConfigurationClass().newInstance(); + final Configuration config = localInfo.getConnectorConfigurationClass().getDeclaredConstructor().newInstance(); final boolean pooling = PoolableConnector.class.isAssignableFrom(connectorClass); rv.setConnectorPoolingSupported(pooling); rv.setConfigurationProperties(JavaClassProperties.createConfigurationProperties(config)); diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/operations/ConnectorAPIOperationRunnerProxy.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/operations/ConnectorAPIOperationRunnerProxy.java index ad5ba971e..dfdd35d7a 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/operations/ConnectorAPIOperationRunnerProxy.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/operations/ConnectorAPIOperationRunnerProxy.java @@ -20,6 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * Portions Copyrighted 2010-2015 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.framework.impl.api.local.operations; @@ -95,7 +96,7 @@ public Object invoke(Object proxy, Method method, Object[] args) } else { // get a new instance of the connector.. - connector = connectorClazz.newInstance(); + connector = connectorClazz.getDeclaredConstructor().newInstance(); // initialize the connector.. connector.init(context.getConfiguration()); } diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/server/ConnectorServer.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/server/ConnectorServer.java index 40d0f72e1..aaf5aecf6 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/server/ConnectorServer.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/server/ConnectorServer.java @@ -110,7 +110,7 @@ public abstract class ConnectorServer { public static ConnectorServer newInstance() { try { final Class clazz = Class.forName(IMPL_NAME); - return (ConnectorServer) clazz.newInstance(); + return (ConnectorServer) clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw ConnectorException.wrap(e); } diff --git a/OpenICF-java-framework/connector-framework-osgi/src/main/java/org/forgerock/openicf/framework/impl/api/osgi/internal/OsgiConnectorInfoManagerImpl.java b/OpenICF-java-framework/connector-framework-osgi/src/main/java/org/forgerock/openicf/framework/impl/api/osgi/internal/OsgiConnectorInfoManagerImpl.java index 1f8805904..af6e54f0e 100644 --- a/OpenICF-java-framework/connector-framework-osgi/src/main/java/org/forgerock/openicf/framework/impl/api/osgi/internal/OsgiConnectorInfoManagerImpl.java +++ b/OpenICF-java-framework/connector-framework-osgi/src/main/java/org/forgerock/openicf/framework/impl/api/osgi/internal/OsgiConnectorInfoManagerImpl.java @@ -335,7 +335,7 @@ private APIConfigurationImpl createDefaultAPIConfiguration(LocalConnectorInfoImp try { Class connectorClass = localInfo.getConnectorClass(); APIConfigurationImpl rv = new APIConfigurationImpl(); - Configuration config = localInfo.getConnectorConfigurationClass().newInstance(); + Configuration config = localInfo.getConnectorConfigurationClass().getDeclaredConstructor().newInstance(); boolean pooling = PoolableConnector.class.isAssignableFrom(connectorClass); rv.setConnectorPoolingSupported(pooling); rv.setConfigurationProperties(JavaClassProperties.createConfigurationProperties(config)); diff --git a/OpenICF-java-framework/connector-framework-server/src/main/java/org/forgerock/openicf/framework/osgi/internal/AsyncOsgiConnectorInfoManagerImpl.java b/OpenICF-java-framework/connector-framework-server/src/main/java/org/forgerock/openicf/framework/osgi/internal/AsyncOsgiConnectorInfoManagerImpl.java index 03b139fd8..9e35525ac 100644 --- a/OpenICF-java-framework/connector-framework-server/src/main/java/org/forgerock/openicf/framework/osgi/internal/AsyncOsgiConnectorInfoManagerImpl.java +++ b/OpenICF-java-framework/connector-framework-server/src/main/java/org/forgerock/openicf/framework/osgi/internal/AsyncOsgiConnectorInfoManagerImpl.java @@ -242,7 +242,7 @@ private APIConfigurationImpl createDefaultAPIConfiguration(OsgiConnectorInfoImpl try { Class connectorClass = localInfo.getConnectorClass(); APIConfigurationImpl rv = new APIConfigurationImpl(); - Configuration config = localInfo.getConnectorConfigurationClass().newInstance(); + Configuration config = localInfo.getConnectorConfigurationClass().getDeclaredConstructor().newInstance(); boolean pooling = PoolableConnector.class.isAssignableFrom(connectorClass); rv.setConnectorPoolingSupported(pooling); rv.setConfigurationProperties(JavaClassProperties.createConfigurationProperties(config)); diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/IOUtil.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/IOUtil.java index 9a9921718..a1814f9da 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/IOUtil.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/IOUtil.java @@ -183,7 +183,7 @@ public static void quietClose(final Statement stmt) { */ public static void quietClose(final Connection conn) { try { - if (conn != null) { + if (conn != null && !conn.isClosed()) { conn.close(); } } catch (SQLException e) { diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/PrettyStringBuilder.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/PrettyStringBuilder.java index 4477f8c50..743919d8b 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/PrettyStringBuilder.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/PrettyStringBuilder.java @@ -20,6 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * Portions Copyrighted 2015 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.common; @@ -96,13 +97,13 @@ protected String toPrettyString(final Object obj) { s.append(')'); } else if (obj instanceof Map) { final Map map = (Map) obj; - final Iterator it = map.keySet().iterator(); + final Iterator it = map.entrySet().iterator(); int i = 0; s.append('{'); while ((it.hasNext() && (i++ < maxArrayLen))) { - final Object key = it.next(); - s.append(key).append(':'); - s.append(toPrettyString(map.get(key))); + final Map.Entry entry = (Map.Entry) it.next(); + s.append(entry.getKey()).append(':'); + s.append(toPrettyString(entry.getValue())); if (it.hasNext()) { s.append(","); } diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/StringUtil.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/StringUtil.java index d17023730..fb821d9fb 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/StringUtil.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/StringUtil.java @@ -19,6 +19,7 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.common; @@ -285,7 +286,7 @@ public static int indexOf(final String src, final char[] ch, final int idx) { * @return true if the string is empty else false. */ public static boolean isEmpty(final String val) { - return (val == null) ? true : "".equals(val) ? true : false; + return (val == null) || val.isEmpty(); } /** diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/logging/Log.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/logging/Log.java index ce848b981..512385b8b 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/logging/Log.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/logging/Log.java @@ -20,6 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * Portions Copyrighted 2014 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.common.logging; @@ -143,7 +144,7 @@ public static Log getLog(final Class clazz) { throw new IllegalArgumentException(); } // attempt to get an instance.. - final LogSpi logImpl = (LogSpi) getSpiClass().newInstance(); + final LogSpi logImpl = (LogSpi) getSpiClass().getDeclaredConstructor().newInstance(); return new Log(clazz, logImpl); } catch (RuntimeException e) { throw e; diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/script/ScriptExecutorFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/script/ScriptExecutorFactory.java index 8b65b7586..f942ca015 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/script/ScriptExecutorFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/script/ScriptExecutorFactory.java @@ -20,6 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * Portions Copyrighted 2015 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.common.script; @@ -70,7 +71,7 @@ private static synchronized Map> getFactoryCache() { Class clazz = Class.forName(factory); // Create an instance in order to get the supported // language. - ScriptExecutorFactory instance = (ScriptExecutorFactory) clazz.newInstance(); + ScriptExecutorFactory instance = (ScriptExecutorFactory) clazz.getDeclaredConstructor().newInstance(); String language = instance.getLanguageName(); // Do not override a factory earlier in the classpath. if (!factoryCache.containsKey(language)) { @@ -169,7 +170,7 @@ public static ScriptExecutorFactory newInstance(String language) { } // exceptions here should not happened because of the register try { - return (ScriptExecutorFactory) clazz.newInstance(); + return (ScriptExecutorFactory) clazz.getDeclaredConstructor().newInstance(); } catch (RuntimeException e) { throw e; } catch (Exception e) { diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/EncryptorFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/EncryptorFactory.java index d235db190..3cf6a8642 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/EncryptorFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/EncryptorFactory.java @@ -19,6 +19,7 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.common.security; @@ -37,7 +38,7 @@ public static synchronized EncryptorFactory getInstance() { if (instance == null) { try { Class clazz = Class.forName(IMPL_NAME); - Object object = clazz.newInstance(); + Object object = clazz.getDeclaredConstructor().newInstance(); instance = EncryptorFactory.class.cast(object); } catch (RuntimeException e) { throw e; diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorFacadeFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorFacadeFactory.java index 100aabccb..92979c5cc 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorFacadeFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorFacadeFactory.java @@ -20,6 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * Portions Copyrighted 2010-2013 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.framework.api; @@ -51,7 +52,7 @@ public static synchronized ConnectorFacadeFactory getInstance() { if (instance == null) { try { final Class clazz = Class.forName(IMPL_NAME); - final Object object = clazz.newInstance(); + final Object object = clazz.getDeclaredConstructor().newInstance(); instance = ConnectorFacadeFactory.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); @@ -70,7 +71,7 @@ public static synchronized ConnectorFacadeFactory getManagedInstance() { if (managedInstance == null) { try { final Class clazz = Class.forName(IMPL_NAME_MANAGED); - final Object object = clazz.newInstance(); + final Object object = clazz.getDeclaredConstructor().newInstance(); managedInstance = ConnectorFacadeFactory.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorInfoManagerFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorInfoManagerFactory.java index e374921c4..6f36a6c9f 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorInfoManagerFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorInfoManagerFactory.java @@ -48,7 +48,7 @@ public static synchronized ConnectorInfoManagerFactory getInstance() { if (instance == null) { try { Class clazz = Class.forName(IMPL_NAME); - Object object = clazz.newInstance(); + Object object = clazz.getDeclaredConstructor().newInstance(); instance = ConnectorInfoManagerFactory.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/common/serializer/ObjectSerializerFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/common/serializer/ObjectSerializerFactory.java index 93622eef5..01530ae01 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/common/serializer/ObjectSerializerFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/common/serializer/ObjectSerializerFactory.java @@ -51,7 +51,7 @@ public static ObjectSerializerFactory getInstance() { if (instance == null) { try { final Class clazz = Class.forName(IMPL_NAME); - final Object object = clazz.newInstance(); + final Object object = clazz.getDeclaredConstructor().newInstance(); instance = ObjectSerializerFactory.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); diff --git a/OpenICF-java-framework/connector-test-common/src/main/java/org/identityconnectors/test/common/TestHelpers.java b/OpenICF-java-framework/connector-test-common/src/main/java/org/identityconnectors/test/common/TestHelpers.java index 67190cc84..2c0ce6434 100644 --- a/OpenICF-java-framework/connector-test-common/src/main/java/org/identityconnectors/test/common/TestHelpers.java +++ b/OpenICF-java-framework/connector-test-common/src/main/java/org/identityconnectors/test/common/TestHelpers.java @@ -20,6 +20,7 @@ * "Portions Copyrighted [year] [name of copyright owner]" * ==================== * Portions Copyrighted 2014 ForgeRock AS. + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.test.common; @@ -215,7 +216,7 @@ private static synchronized TestHelpersSpi getSpi() { if (instance == null) { try { Class clazz = Class.forName(IMPL_NAME); - Object object = clazz.newInstance(); + Object object = clazz.getDeclaredConstructor().newInstance(); instance = TestHelpersSpi.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); @@ -308,7 +309,7 @@ public static PropertyBag getProperties(Class clazz, String environment) { Class configObject = Class.forName("groovy.util.ConfigObject"); Object slurpInstance = null; if (StringUtil.isBlank(environment)) { - slurpInstance = slurper.newInstance(); + slurpInstance = slurper.getDeclaredConstructor().newInstance(); } else { slurpInstance = slurper.getConstructor(String.class).newInstance(environment); } diff --git a/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/sync/activedirectory/ActiveDirectoryChangeLogSyncStrategy.java b/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/sync/activedirectory/ActiveDirectoryChangeLogSyncStrategy.java index b9b6ccdd4..41adde35f 100644 --- a/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/sync/activedirectory/ActiveDirectoryChangeLogSyncStrategy.java +++ b/OpenICF-ldap-connector/src/main/java/org/identityconnectors/ldap/sync/activedirectory/ActiveDirectoryChangeLogSyncStrategy.java @@ -20,6 +20,7 @@ * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" + * Portions Copyrighted 2026 3A Systems, LLC */ package org.identityconnectors.ldap.sync.activedirectory; @@ -321,7 +322,7 @@ private String gethighestCommittedUSN() { Attributes attrs = conn.getInitialContext().getAttributes("", new String[]{HCU_CHANGED_ATTR}); hcUSN = getStringAttrValue(attrs, HCU_CHANGED_ATTR); if (hcUSN == null) { - String error = "Unable to read the highestCommittedUSN attribute" + String error = "Unable to read the highestCommittedUSN attribute " + "from the rootDSE of Active Directory "; throw new ConnectorException(error); } diff --git a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorDocBuilder.java b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorDocBuilder.java index 6562b28c3..398e104f1 100644 --- a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorDocBuilder.java +++ b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorDocBuilder.java @@ -200,7 +200,7 @@ protected void executeReport() throws MojoExecutionException { Class connectorClass = ((LocalConnectorInfoImpl) info).getConnectorClass(); try { - SchemaOp connector = (SchemaOp) connectorClass.newInstance(); + SchemaOp connector = (SchemaOp) connectorClass.getDeclaredConstructor().newInstance(); schema = connector.schema(); } catch (Throwable t) { handler.getLog().debug("Getting Schema with Connector Instance", t); diff --git a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorInfoReportMojo.java b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorInfoReportMojo.java index 62ff4edae..f09c507d5 100644 --- a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorInfoReportMojo.java +++ b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorInfoReportMojo.java @@ -352,12 +352,8 @@ protected void executeReport(Locale locale) throws MavenReportException { } } else if (!name.endsWith(".xml")) { if (!destination.exists()) { - FileOutputStream output = null; - try { - output = new FileOutputStream(destination); + try (FileOutputStream output = new FileOutputStream(destination)) { IOUtil.copy(zip, output); - } finally { - IOUtil.close(output); } } } diff --git a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/DocBookResourceMojo.java b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/DocBookResourceMojo.java index 4e258c802..a74519e49 100644 --- a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/DocBookResourceMojo.java +++ b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/DocBookResourceMojo.java @@ -423,12 +423,8 @@ public boolean accept(File pathname) { } } else { if (!destination.exists()) { - FileOutputStream output = null; - try { - output = new FileOutputStream(destination); + try (FileOutputStream output = new FileOutputStream(destination)) { IOUtil.copy(zip, output); - } finally { - IOUtil.close(output); } } } diff --git a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ReducePomMojo.java b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ReducePomMojo.java index 957395355..a5dfa1b0b 100644 --- a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ReducePomMojo.java +++ b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ReducePomMojo.java @@ -144,15 +144,11 @@ public void execute() throws MojoExecutionException { f.delete(); } - Writer w = null; - try { - w = WriterFactory.newXmlWriter(f); + try (Writer w = WriterFactory.newXmlWriter(f)) { MavenXpp3Writer pomWriter = new MavenXpp3Writer(); pomWriter.write(w, model); } catch (IOException exception) { throw new MojoExecutionException("Cannot generate reduced POM", exception); - } finally { - IOUtil.close(w); } /* diff --git a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/XMLConfiguration.java b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/XMLConfiguration.java index 8bcd444d0..e33352bed 100644 --- a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/XMLConfiguration.java +++ b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/XMLConfiguration.java @@ -20,6 +20,7 @@ * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted 2010 [name of copyright owner]" + * Portions Copyrighted 2026 3A Systems, LLC * * $Id$ */ @@ -106,7 +107,10 @@ public void validate() { } else if (!xmlFilePath.exists()) { if (createFileIfNotExists) { try { - xmlFilePath.getParentFile().mkdir(); + File parentFile = xmlFilePath.getParentFile(); + if (parentFile != null && !parentFile.isDirectory() && !parentFile.mkdir()) { + throw new IOException("Could not create " + parentFile); + } if (xmlFilePath.createNewFile()) { xmlFilePath.delete(); } diff --git a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java index b6bc1296b..85de870e5 100644 --- a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java +++ b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java @@ -20,6 +20,7 @@ * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted 2010 [name of copyright owner]" + * Portions Copyrighted 2026 3A Systems, LLC * * $Id$ */ @@ -44,47 +45,46 @@ public class AttributeTypeUtil { public static Object createInstantiatedObject(String attrValue, String javaclass) { if (javaclass.equals(XmlHandlerUtil.STRING)) { - String s = new String(attrValue); - return s; + return attrValue; } else if (javaclass.equals(XmlHandlerUtil.INT_PRIMITIVE)) { - int i = new Integer(attrValue); + int i = Integer.valueOf(attrValue); return i; } else if (javaclass.equals(XmlHandlerUtil.INTEGER)) { - Integer i = new Integer(attrValue); + Integer i = Integer.valueOf(attrValue); return i; } else if (javaclass.equals(XmlHandlerUtil.LONG)) { - Long l = new Long(attrValue); + Long l = Long.valueOf(attrValue); return l; } else if (javaclass.equals(XmlHandlerUtil.LONG_PRIMITIVE)) { - long l = new Long(attrValue); + long l = Long.valueOf(attrValue); return l; } else if (javaclass.equals(XmlHandlerUtil.BOOLEAN)) { - Boolean b = new Boolean(attrValue); + Boolean b = Boolean.valueOf(attrValue); return b; } else if (javaclass.equals(XmlHandlerUtil.BOOLEAN_PRIMITIVE)) { - boolean b = new Boolean(attrValue); + boolean b = Boolean.valueOf(attrValue); return b; } else if (javaclass.equals(XmlHandlerUtil.DOUBLE)) { - Double d = new Double(attrValue); + Double d = Double.valueOf(attrValue); return d; } else if (javaclass.equals(XmlHandlerUtil.DOUBLE_PRIMITIVE)) { - double d = new Double(attrValue); + double d = Double.valueOf(attrValue); return d; } else if (javaclass.equals(XmlHandlerUtil.FLOAT)) { - Float f = new Float(attrValue); + Float f = Float.valueOf(attrValue); return f; } else if (javaclass.equals(XmlHandlerUtil.FLOAT_PRIMITIVE)) { - float f = new Float(attrValue); + float f = Float.valueOf(attrValue); return f; } else if (javaclass.equals(XmlHandlerUtil.CHARACTER)) { diff --git a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/xsdparser/XSDAnnotationParser.java b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/xsdparser/XSDAnnotationParser.java index e7e0661fd..7515acc68 100644 --- a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/xsdparser/XSDAnnotationParser.java +++ b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/xsdparser/XSDAnnotationParser.java @@ -20,6 +20,7 @@ * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted 2010 [name of copyright owner]" + * Portions Copyrighted 2026 3A Systems, LLC * * $Id$ */ @@ -71,7 +72,7 @@ public void characters(char[] chars, int start, int length) throws SAXException if(parse){ StringBuilder sb = new StringBuilder(); sb.append(chars, start, length); - if(!sb.toString().replace(" ", "").trim().equals("")){ + if(!sb.toString().replace(" ", "").trim().isEmpty()){ String stringToAppend = addValue + " " + sb.toString().trim(); stringBuilder.append(stringToAppend); stringBuilder.append("\n"); From 5994ee7e08fe0b042891debf3062caf56f0b4132 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 18 Sep 2026 23:17:59 +0300 Subject: [PATCH 2/4] Wrap malformed numeric attribute values in a ConnectorException createInstantiatedObject used to let a NumberFormatException from Integer/Long/Double/Float.valueOf (and BigInteger/BigDecimal) escape uncaught, with no indication of which attribute or target type failed to parse. Converting the deprecated boxed constructors to valueOf earlier in this branch made CodeQL recognise the parse call and flag it (java/uncaught-number-format-exception) - the bug was already there, just invisible to the query through the old constructor form. --- .../xml/util/AttributeTypeUtil.java | 8 +++ .../xml/util/AttributeTypeUtilTest.java | 68 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTest.java diff --git a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java index 85de870e5..405adc528 100644 --- a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java +++ b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java @@ -44,6 +44,14 @@ public class AttributeTypeUtil { public static Object createInstantiatedObject(String attrValue, String javaclass) { + try { + return createInstantiatedObjectUnchecked(attrValue, javaclass); + } catch (NumberFormatException e) { + throw new ConnectorException("Value '" + attrValue + "' is not a valid " + javaclass, e); + } + } + + private static Object createInstantiatedObjectUnchecked(String attrValue, String javaclass) { if (javaclass.equals(XmlHandlerUtil.STRING)) { return attrValue; } diff --git a/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTest.java b/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTest.java new file mode 100644 index 000000000..c2b7c6eb9 --- /dev/null +++ b/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTest.java @@ -0,0 +1,68 @@ +/* + * The contents of this file are subject to the terms of the Common Development and + * Distribution License (the License). You may not use this file except in compliance with the + * License. + * + * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the + * specific language governing permission and limitations under the License. + * + * When distributing Covered Software, include this CDDL Header Notice in each file and include + * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL + * Header, with the fields enclosed by brackets [] replaced by your own identifying + * information: "Portions copyright [year] [name of copyright owner]". + * + * Copyright 2026 3A Systems, LLC. + */ +package org.forgerock.openicf.connectors.xml.util; + +import static org.testng.Assert.assertEquals; + +import org.identityconnectors.framework.common.exceptions.ConnectorException; +import org.testng.annotations.Test; + +public class AttributeTypeUtilTest { + + @Test + public void createInstantiatedObjectParsesEachNumericType() { + assertEquals(AttributeTypeUtil.createInstantiatedObject("3", XmlHandlerUtil.INT_PRIMITIVE), 3); + assertEquals(AttributeTypeUtil.createInstantiatedObject("3", XmlHandlerUtil.INTEGER), 3); + assertEquals(AttributeTypeUtil.createInstantiatedObject("3", XmlHandlerUtil.LONG_PRIMITIVE), 3L); + assertEquals(AttributeTypeUtil.createInstantiatedObject("3", XmlHandlerUtil.LONG), 3L); + assertEquals(AttributeTypeUtil.createInstantiatedObject("3.5", XmlHandlerUtil.DOUBLE_PRIMITIVE), 3.5); + assertEquals(AttributeTypeUtil.createInstantiatedObject("3.5", XmlHandlerUtil.DOUBLE), 3.5); + assertEquals(AttributeTypeUtil.createInstantiatedObject("3.5", XmlHandlerUtil.FLOAT_PRIMITIVE), 3.5f); + assertEquals(AttributeTypeUtil.createInstantiatedObject("3.5", XmlHandlerUtil.FLOAT), 3.5f); + } + + /** + * A malformed numeric value in the XML data file must fail with a + * ConnectorException naming the value and the target type, not a bare + * NumberFormatException with no indication of which attribute it came + * from. + */ + @Test(expectedExceptions = ConnectorException.class, + dataProvider = "numericTypes") + public void createInstantiatedObjectWrapsMalformedNumber(String type) { + AttributeTypeUtil.createInstantiatedObject("not-a-number", type); + } + + @Test(expectedExceptions = ConnectorException.class, + dataProvider = "numericTypes") + public void createInstantiatedObjectWrapsBlankNumber(String type) { + AttributeTypeUtil.createInstantiatedObject("", type); + } + + @org.testng.annotations.DataProvider + public Object[][] numericTypes() { + return new Object[][] { + { XmlHandlerUtil.INT_PRIMITIVE }, + { XmlHandlerUtil.INTEGER }, + { XmlHandlerUtil.LONG_PRIMITIVE }, + { XmlHandlerUtil.LONG }, + { XmlHandlerUtil.DOUBLE_PRIMITIVE }, + { XmlHandlerUtil.DOUBLE }, + { XmlHandlerUtil.FLOAT_PRIMITIVE }, + { XmlHandlerUtil.FLOAT }, + }; + } +} From d77ed96e606a3816adce9cad318b752c7bbb2c4a Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Sat, 19 Sep 2026 10:47:27 +0300 Subject: [PATCH 3/4] Declare NumberFormatException on the AttributeTypeUtil parse helper CodeQL's uncaught-number-format-exception query only sees a catch in the same method or a throws clause on the enclosing one; the wrapper added in the previous commit left all eight alerts open at the helper's lines. --- .../openicf/connectors/xml/util/AttributeTypeUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java index 405adc528..23da35814 100644 --- a/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java +++ b/OpenICF-xml-connector/src/main/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtil.java @@ -51,7 +51,8 @@ public static Object createInstantiatedObject(String attrValue, String javaclass } } - private static Object createInstantiatedObjectUnchecked(String attrValue, String javaclass) { + private static Object createInstantiatedObjectUnchecked(String attrValue, String javaclass) + throws NumberFormatException { if (javaclass.equals(XmlHandlerUtil.STRING)) { return attrValue; } From 7500a98cfd61fee7049e965de90a06c82442b68f Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 2 Oct 2026 15:15:26 +0300 Subject: [PATCH 4/4] Pass constructor exceptions through unchanged when instantiating reflectively getDeclaredConstructor().newInstance() wraps whatever the constructor throws in InvocationTargetException, so the catch-and-wrap sites turned e.g. a ConfigurationException from a connector constructor into a plain ConnectorException("java.lang.reflect.InvocationTargetException"), and ScriptExecutorFactory logged a failing factory as "Exception:null". ReflectionUtil.newInstance(Lookup, Class) restores what Class.newInstance() did: the constructor's exception reaches the caller as is, and access is checked against the caller's lookup, so a package-private class such as StdOutLogger stays instantiable from its own package. GroovyDataProvider no longer keeps an out file it failed to create: a dangling symlink or a directory at that path now stores nothing, as before, instead of logging "will not be stored" and writing through it. AttributeTypeUtilTest pins the exception message and cause and covers BigInteger/BigDecimal; XMLConfigurationTests covers a file path without a parent directory. --- .../contract/data/GroovyDataProvider.java | 6 +- .../contract/test/ConnectorHelper.java | 6 +- .../impl/api/local/ConnectorPoolManager.java | 4 +- .../impl/api/local/JavaClassProperties.java | 3 +- .../local/LocalConnectorInfoManagerImpl.java | 3 +- .../ConnectorAPIOperationRunnerProxy.java | 4 +- .../framework/server/ConnectorServer.java | 4 +- .../OsgiConnectorInfoManagerImpl.java | 3 +- .../AsyncOsgiConnectorInfoManagerImpl.java | 3 +- .../common/ReflectionUtil.java | 45 ++++++++++++ .../common/logging/Log.java | 3 +- .../common/script/ScriptExecutorFactory.java | 6 +- .../common/security/EncryptorFactory.java | 6 +- .../framework/api/ConnectorFacadeFactory.java | 7 +- .../api/ConnectorInfoManagerFactory.java | 4 +- .../serializer/ObjectSerializerFactory.java | 4 +- .../common/ReflectionUtilTests.java | 73 +++++++++++++++++++ .../test/common/TestHelpers.java | 6 +- .../openicf/maven/ConnectorDocBuilder.java | 4 +- .../connectors/xml/XMLConfigurationTests.java | 19 +++++ .../xml/util/AttributeTypeUtilTest.java | 29 ++++++-- 21 files changed, 214 insertions(+), 28 deletions(-) diff --git a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/GroovyDataProvider.java b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/GroovyDataProvider.java index ff4a519ca..a64a73228 100644 --- a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/GroovyDataProvider.java +++ b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/data/GroovyDataProvider.java @@ -238,7 +238,7 @@ private void initQueriedPropsDump() { if (StringUtil.isNotBlank(pOut)) { try { _queriedPropsOutFile = new File(pOut); - if (!_queriedPropsOutFile.exists() && !_queriedPropsOutFile.createNewFile()) { + if (!_queriedPropsOutFile.createNewFile() && !_queriedPropsOutFile.isFile()) { throw new IOException("Could not create " + _queriedPropsOutFile); } if (!_queriedPropsOutFile.canWrite()) { @@ -248,6 +248,7 @@ private void initQueriedPropsDump() { LOG.info("Storing parameter values to ''{0}'', you can rerun the test with the same parameters later", pOut); } } catch (IOException iOException) { + _queriedPropsOutFile = null; LOG.warn("Unable to create ''{0}'' file, the test parameters will not be stored", pOut); } } @@ -263,7 +264,7 @@ private void initSnapshot() { if (StringUtil.isNotBlank(pOut)) { try { _propertyOutFile = new File(pOut); - if (!_propertyOutFile.exists() && !_propertyOutFile.createNewFile()) { + if (!_propertyOutFile.createNewFile() && !_propertyOutFile.isFile()) { throw new IOException("Could not create " + _propertyOutFile); } if (!_propertyOutFile.canWrite()) { @@ -273,6 +274,7 @@ private void initSnapshot() { LOG.info("Storing parameter values to ''{0}'', you can rerun the test with the same parameters later", pOut); } } catch (IOException iOException) { + _propertyOutFile = null; LOG.warn("Unable to create ''{0}'' file, the test parameters will not be stored", pOut); } } diff --git a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ConnectorHelper.java b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ConnectorHelper.java index 536406931..5e763fb60 100644 --- a/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ConnectorHelper.java +++ b/OpenICF-java-framework/connector-framework-contract/src/main/java/org/identityconnectors/contract/test/ConnectorHelper.java @@ -31,6 +31,7 @@ import static org.testng.Assert.assertTrue; import java.io.File; +import java.lang.invoke.MethodHandles; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collection; @@ -44,6 +45,7 @@ import org.identityconnectors.common.CollectionUtil; +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.common.StringUtil; import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.contract.data.DataProvider; @@ -119,10 +121,10 @@ public static DataProvider createDataProvider() { throw new Exception("Class " + customDataProvider + " is not of type " + DataProvider.class.getName()); } - dp = (DataProvider) dpClass.getDeclaredConstructor().newInstance(); + dp = (DataProvider) ReflectionUtil.newInstance(MethodHandles.lookup(), dpClass); } else { logger.info("DataProvider class not specified, using default ''"+DEFAULT_DATA_PROVIDER+"''."); - dp = (DataProvider) DEFAULT_DATA_PROVIDER.getDeclaredConstructor().newInstance(); + dp = (DataProvider) ReflectionUtil.newInstance(MethodHandles.lookup(), DEFAULT_DATA_PROVIDER); } } catch (Exception ex) { throw ContractException.wrap(ex); diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/ConnectorPoolManager.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/ConnectorPoolManager.java index 1605d3531..1513ae19a 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/ConnectorPoolManager.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/ConnectorPoolManager.java @@ -25,11 +25,13 @@ package org.identityconnectors.framework.impl.api.local; +import java.lang.invoke.MethodHandles; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.identityconnectors.common.Pair; +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.common.logging.Log; import org.identityconnectors.common.pooling.ObjectPoolConfiguration; import org.identityconnectors.framework.api.ConfigurationPropertyChangeListener; @@ -166,7 +168,7 @@ public PoolableConnector makeObject() { config = context.getConfiguration(); } - connector = (PoolableConnector) clazz.getDeclaredConstructor().newInstance(); + connector = (PoolableConnector) ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); connector.init(config); } else { throw new ConnectorException("The Connector is not PoolableConnector: " diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/JavaClassProperties.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/JavaClassProperties.java index 7601fc68b..34f614237 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/JavaClassProperties.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/JavaClassProperties.java @@ -28,6 +28,7 @@ import java.beans.IndexedPropertyDescriptor; import java.beans.Introspector; import java.beans.PropertyDescriptor; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.text.MessageFormat; @@ -216,7 +217,7 @@ private static Set> translateOperations( private static Configuration createBean2(ConfigurationPropertiesImpl properties, Class configClass) throws Exception { - Configuration rv = configClass.getDeclaredConstructor().newInstance(); + Configuration rv = ReflectionUtil.newInstance(MethodHandles.lookup(), configClass); rv.setConnectorMessages(properties.getParent().getConnectorInfo().getMessages()); mergeIntoBean2(properties, rv); return rv; diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/LocalConnectorInfoManagerImpl.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/LocalConnectorInfoManagerImpl.java index 892f9e9bd..7be5c3605 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/LocalConnectorInfoManagerImpl.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/LocalConnectorInfoManagerImpl.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; +import java.lang.invoke.MethodHandles; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; @@ -326,7 +327,7 @@ public static APIConfigurationImpl createDefaultAPIConfiguration( try { final Class connectorClass = localInfo.getConnectorClass(); final APIConfigurationImpl rv = new APIConfigurationImpl(); - final Configuration config = localInfo.getConnectorConfigurationClass().getDeclaredConstructor().newInstance(); + final Configuration config = ReflectionUtil.newInstance(MethodHandles.lookup(), localInfo.getConnectorConfigurationClass()); final boolean pooling = PoolableConnector.class.isAssignableFrom(connectorClass); rv.setConnectorPoolingSupported(pooling); rv.setConfigurationProperties(JavaClassProperties.createConfigurationProperties(config)); diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/operations/ConnectorAPIOperationRunnerProxy.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/operations/ConnectorAPIOperationRunnerProxy.java index dfdd35d7a..6f4cc9ee3 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/operations/ConnectorAPIOperationRunnerProxy.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/impl/api/local/operations/ConnectorAPIOperationRunnerProxy.java @@ -24,12 +24,14 @@ */ package org.identityconnectors.framework.impl.api.local.operations; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicBoolean; +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.common.logging.Log; import org.identityconnectors.framework.common.objects.Subscription; import org.identityconnectors.framework.impl.api.local.ObjectPool; @@ -96,7 +98,7 @@ public Object invoke(Object proxy, Method method, Object[] args) } else { // get a new instance of the connector.. - connector = connectorClazz.getDeclaredConstructor().newInstance(); + connector = ReflectionUtil.newInstance(MethodHandles.lookup(), connectorClazz); // initialize the connector.. connector.init(context.getConfiguration()); } diff --git a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/server/ConnectorServer.java b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/server/ConnectorServer.java index aaf5aecf6..80e673cae 100644 --- a/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/server/ConnectorServer.java +++ b/OpenICF-java-framework/connector-framework-internal/src/main/java/org/identityconnectors/framework/server/ConnectorServer.java @@ -25,6 +25,7 @@ package org.identityconnectors.framework.server; +import java.lang.invoke.MethodHandles; import java.net.InetAddress; import java.net.URL; import java.util.List; @@ -32,6 +33,7 @@ import javax.net.ssl.KeyManager; import org.identityconnectors.common.CollectionUtil; +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.common.logging.Log; import org.identityconnectors.framework.common.exceptions.ConnectorException; @@ -110,7 +112,7 @@ public abstract class ConnectorServer { public static ConnectorServer newInstance() { try { final Class clazz = Class.forName(IMPL_NAME); - return (ConnectorServer) clazz.getDeclaredConstructor().newInstance(); + return (ConnectorServer) ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); } catch (Exception e) { throw ConnectorException.wrap(e); } diff --git a/OpenICF-java-framework/connector-framework-osgi/src/main/java/org/forgerock/openicf/framework/impl/api/osgi/internal/OsgiConnectorInfoManagerImpl.java b/OpenICF-java-framework/connector-framework-osgi/src/main/java/org/forgerock/openicf/framework/impl/api/osgi/internal/OsgiConnectorInfoManagerImpl.java index af6e54f0e..ffcd7483d 100644 --- a/OpenICF-java-framework/connector-framework-osgi/src/main/java/org/forgerock/openicf/framework/impl/api/osgi/internal/OsgiConnectorInfoManagerImpl.java +++ b/OpenICF-java-framework/connector-framework-osgi/src/main/java/org/forgerock/openicf/framework/impl/api/osgi/internal/OsgiConnectorInfoManagerImpl.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.InputStream; +import java.lang.invoke.MethodHandles; import java.net.URL; import java.util.ArrayList; import java.util.Collections; @@ -335,7 +336,7 @@ private APIConfigurationImpl createDefaultAPIConfiguration(LocalConnectorInfoImp try { Class connectorClass = localInfo.getConnectorClass(); APIConfigurationImpl rv = new APIConfigurationImpl(); - Configuration config = localInfo.getConnectorConfigurationClass().getDeclaredConstructor().newInstance(); + Configuration config = ReflectionUtil.newInstance(MethodHandles.lookup(), localInfo.getConnectorConfigurationClass()); boolean pooling = PoolableConnector.class.isAssignableFrom(connectorClass); rv.setConnectorPoolingSupported(pooling); rv.setConfigurationProperties(JavaClassProperties.createConfigurationProperties(config)); diff --git a/OpenICF-java-framework/connector-framework-server/src/main/java/org/forgerock/openicf/framework/osgi/internal/AsyncOsgiConnectorInfoManagerImpl.java b/OpenICF-java-framework/connector-framework-server/src/main/java/org/forgerock/openicf/framework/osgi/internal/AsyncOsgiConnectorInfoManagerImpl.java index 9e35525ac..513a99785 100644 --- a/OpenICF-java-framework/connector-framework-server/src/main/java/org/forgerock/openicf/framework/osgi/internal/AsyncOsgiConnectorInfoManagerImpl.java +++ b/OpenICF-java-framework/connector-framework-server/src/main/java/org/forgerock/openicf/framework/osgi/internal/AsyncOsgiConnectorInfoManagerImpl.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.InputStream; +import java.lang.invoke.MethodHandles; import java.net.URL; import java.util.ArrayList; import java.util.Collections; @@ -242,7 +243,7 @@ private APIConfigurationImpl createDefaultAPIConfiguration(OsgiConnectorInfoImpl try { Class connectorClass = localInfo.getConnectorClass(); APIConfigurationImpl rv = new APIConfigurationImpl(); - Configuration config = localInfo.getConnectorConfigurationClass().getDeclaredConstructor().newInstance(); + Configuration config = ReflectionUtil.newInstance(MethodHandles.lookup(), localInfo.getConnectorConfigurationClass()); boolean pooling = PoolableConnector.class.isAssignableFrom(connectorClass); rv.setConnectorPoolingSupported(pooling); rv.setConfigurationProperties(JavaClassProperties.createConfigurationProperties(config)); diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/ReflectionUtil.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/ReflectionUtil.java index 7fef46a69..acfc24908 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/ReflectionUtil.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/ReflectionUtil.java @@ -19,10 +19,15 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * Portions Copyright 2026 3A Systems, LLC. */ package org.identityconnectors.common; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -116,6 +121,46 @@ public static boolean overridesEqualsAndHashcode(final Class clazz) { } } + /** + * Creates a new instance of the class through its no-argument constructor, + * as the deprecated {@link Class#newInstance()} did. + *

+ * Unlike a bare {@code getDeclaredConstructor().newInstance()}, whatever + * the constructor throws reaches the caller unchanged instead of wrapped + * in an {@link java.lang.reflect.InvocationTargetException}, so callers + * that pass a {@link RuntimeException} through or wrap a checked exception + * keep seeing the original exception type and message. + *

+ * Access to the constructor is checked against {@code lookup}, so the + * caller passes its own {@link MethodHandles#lookup()}: a package-private + * class stays instantiable from its own package, as it was with + * {@link Class#newInstance()}. + * + * @param + * the type of the instance. + * @param lookup + * the caller's lookup, {@code MethodHandles.lookup()}. + * @param clazz + * class to instantiate. + * @return the new instance. + * @throws Exception + * whatever the constructor throws, or the reflective exception + * if the class has no no-argument constructor accessible to + * {@code lookup}. + */ + public static T newInstance(final MethodHandles.Lookup lookup, final Class clazz) + throws Exception { + final MethodHandle constructor = + lookup.findConstructor(clazz, MethodType.methodType(void.class)); + try { + return clazz.cast(constructor.invoke()); + } catch (Exception | Error e) { + throw e; + } catch (Throwable t) { + throw new UndeclaredThrowableException(t); + } + } + /** * Returns the package the class is associated with. * diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/logging/Log.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/logging/Log.java index 512385b8b..ffce1aca0 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/logging/Log.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/logging/Log.java @@ -27,6 +27,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.lang.invoke.MethodHandles; import java.text.MessageFormat; import java.util.Collection; import java.util.Properties; @@ -144,7 +145,7 @@ public static Log getLog(final Class clazz) { throw new IllegalArgumentException(); } // attempt to get an instance.. - final LogSpi logImpl = (LogSpi) getSpiClass().getDeclaredConstructor().newInstance(); + final LogSpi logImpl = (LogSpi) ReflectionUtil.newInstance(MethodHandles.lookup(), getSpiClass()); return new Log(clazz, logImpl); } catch (RuntimeException e) { throw e; diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/script/ScriptExecutorFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/script/ScriptExecutorFactory.java index f942ca015..7c179de54 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/script/ScriptExecutorFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/script/ScriptExecutorFactory.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.invoke.MethodHandles; import java.net.URL; import java.util.ArrayList; import java.util.Collections; @@ -37,6 +38,7 @@ import java.util.Set; import org.identityconnectors.common.CollectionUtil; +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.common.StringUtil; import org.identityconnectors.common.logging.Log; import org.identityconnectors.framework.api.operations.ScriptOnConnectorApiOp; @@ -71,7 +73,7 @@ private static synchronized Map> getFactoryCache() { Class clazz = Class.forName(factory); // Create an instance in order to get the supported // language. - ScriptExecutorFactory instance = (ScriptExecutorFactory) clazz.getDeclaredConstructor().newInstance(); + ScriptExecutorFactory instance = (ScriptExecutorFactory) ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); String language = instance.getLanguageName(); // Do not override a factory earlier in the classpath. if (!factoryCache.containsKey(language)) { @@ -170,7 +172,7 @@ public static ScriptExecutorFactory newInstance(String language) { } // exceptions here should not happened because of the register try { - return (ScriptExecutorFactory) clazz.getDeclaredConstructor().newInstance(); + return (ScriptExecutorFactory) ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); } catch (RuntimeException e) { throw e; } catch (Exception e) { diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/EncryptorFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/EncryptorFactory.java index 3cf6a8642..db5766299 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/EncryptorFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/common/security/EncryptorFactory.java @@ -23,6 +23,10 @@ */ package org.identityconnectors.common.security; +import java.lang.invoke.MethodHandles; + +import org.identityconnectors.common.ReflectionUtil; + public abstract class EncryptorFactory { // At some point we might make this pluggable, but for now, hard-code @@ -38,7 +42,7 @@ public static synchronized EncryptorFactory getInstance() { if (instance == null) { try { Class clazz = Class.forName(IMPL_NAME); - Object object = clazz.getDeclaredConstructor().newInstance(); + Object object = ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); instance = EncryptorFactory.class.cast(object); } catch (RuntimeException e) { throw e; diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorFacadeFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorFacadeFactory.java index 92979c5cc..2f4317f9e 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorFacadeFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorFacadeFactory.java @@ -24,6 +24,9 @@ */ package org.identityconnectors.framework.api; +import java.lang.invoke.MethodHandles; + +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.framework.common.exceptions.ConnectorException; /** @@ -52,7 +55,7 @@ public static synchronized ConnectorFacadeFactory getInstance() { if (instance == null) { try { final Class clazz = Class.forName(IMPL_NAME); - final Object object = clazz.getDeclaredConstructor().newInstance(); + final Object object = ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); instance = ConnectorFacadeFactory.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); @@ -71,7 +74,7 @@ public static synchronized ConnectorFacadeFactory getManagedInstance() { if (managedInstance == null) { try { final Class clazz = Class.forName(IMPL_NAME_MANAGED); - final Object object = clazz.getDeclaredConstructor().newInstance(); + final Object object = ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); managedInstance = ConnectorFacadeFactory.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorInfoManagerFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorInfoManagerFactory.java index 6f36a6c9f..8445da198 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorInfoManagerFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/api/ConnectorInfoManagerFactory.java @@ -23,8 +23,10 @@ */ package org.identityconnectors.framework.api; +import java.lang.invoke.MethodHandles; import java.net.URL; +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.framework.common.exceptions.ConnectorException; /** @@ -48,7 +50,7 @@ public static synchronized ConnectorInfoManagerFactory getInstance() { if (instance == null) { try { Class clazz = Class.forName(IMPL_NAME); - Object object = clazz.getDeclaredConstructor().newInstance(); + Object object = ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); instance = ConnectorInfoManagerFactory.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); diff --git a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/common/serializer/ObjectSerializerFactory.java b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/common/serializer/ObjectSerializerFactory.java index 01530ae01..bbe1840be 100644 --- a/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/common/serializer/ObjectSerializerFactory.java +++ b/OpenICF-java-framework/connector-framework/src/main/java/org/identityconnectors/framework/common/serializer/ObjectSerializerFactory.java @@ -26,7 +26,9 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; +import java.lang.invoke.MethodHandles; +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.framework.common.exceptions.ConnectorException; import org.xml.sax.InputSource; @@ -51,7 +53,7 @@ public static ObjectSerializerFactory getInstance() { if (instance == null) { try { final Class clazz = Class.forName(IMPL_NAME); - final Object object = clazz.getDeclaredConstructor().newInstance(); + final Object object = ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); instance = ObjectSerializerFactory.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); diff --git a/OpenICF-java-framework/connector-framework/src/test/java/org/identityconnectors/common/ReflectionUtilTests.java b/OpenICF-java-framework/connector-framework/src/test/java/org/identityconnectors/common/ReflectionUtilTests.java index 32c290121..5d5214435 100644 --- a/OpenICF-java-framework/connector-framework/src/test/java/org/identityconnectors/common/ReflectionUtilTests.java +++ b/OpenICF-java-framework/connector-framework/src/test/java/org/identityconnectors/common/ReflectionUtilTests.java @@ -19,14 +19,20 @@ * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== + * Portions Copyright 2026 3A Systems, LLC. */ package org.identityconnectors.common; import static org.identityconnectors.common.ReflectionUtil.containsInterface; import static org.identityconnectors.common.ReflectionUtil.getAllInterfaces; +import static org.identityconnectors.common.ReflectionUtil.newInstance; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; +import java.io.IOException; +import java.lang.invoke.MethodHandles; import java.util.Set; import org.testng.annotations.Test; @@ -46,6 +52,46 @@ public void functional() { assertFalse(containsInterface(C1.class, I3.class)); } + @Test + public void newInstanceCallsNoArgConstructor() throws Exception { + assertTrue(newInstance(MethodHandles.lookup(), Constructible.class) instanceof Constructible); + } + + @Test + public void newInstancePassesRuntimeExceptionThroughUnchanged() throws Exception { + try { + newInstance(MethodHandles.lookup(), ThrowsRuntimeException.class); + fail("IllegalArgumentException expected"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "from constructor"); + } + } + + @Test + public void newInstancePassesCheckedExceptionThroughUnchanged() throws Exception { + try { + newInstance(MethodHandles.lookup(), ThrowsCheckedException.class); + fail("IOException expected"); + } catch (IOException e) { + assertEquals(e.getMessage(), "from constructor"); + } + } + + @Test + public void newInstancePassesErrorThroughUnchanged() throws Exception { + try { + newInstance(MethodHandles.lookup(), ThrowsError.class); + fail("NoClassDefFoundError expected"); + } catch (NoClassDefFoundError e) { + assertEquals(e.getMessage(), "from constructor"); + } + } + + @Test(expectedExceptions = NoSuchMethodException.class) + public void newInstanceFailsWithoutNoArgConstructor() throws Exception { + newInstance(MethodHandles.lookup(), NoNoArgConstructor.class); + } + // ======================================================================= // Helper Classes/Interfaces // ======================================================================= @@ -72,4 +118,31 @@ interface I5 extends I1 { class C2 implements I5 { } + + public static class Constructible { + + } + + public static class ThrowsRuntimeException { + public ThrowsRuntimeException() { + throw new IllegalArgumentException("from constructor"); + } + } + + public static class ThrowsCheckedException { + public ThrowsCheckedException() throws IOException { + throw new IOException("from constructor"); + } + } + + public static class ThrowsError { + public ThrowsError() { + throw new NoClassDefFoundError("from constructor"); + } + } + + public static class NoNoArgConstructor { + public NoNoArgConstructor(String value) { + } + } } diff --git a/OpenICF-java-framework/connector-test-common/src/main/java/org/identityconnectors/test/common/TestHelpers.java b/OpenICF-java-framework/connector-test-common/src/main/java/org/identityconnectors/test/common/TestHelpers.java index 2c0ce6434..47c033e2a 100644 --- a/OpenICF-java-framework/connector-test-common/src/main/java/org/identityconnectors/test/common/TestHelpers.java +++ b/OpenICF-java-framework/connector-test-common/src/main/java/org/identityconnectors/test/common/TestHelpers.java @@ -25,6 +25,7 @@ package org.identityconnectors.test.common; import java.io.File; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.net.URI; import java.net.URL; @@ -38,6 +39,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.TrueFileFilter; +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.common.StringUtil; import org.identityconnectors.framework.api.APIConfiguration; import org.identityconnectors.framework.api.operations.SearchApiOp; @@ -216,7 +218,7 @@ private static synchronized TestHelpersSpi getSpi() { if (instance == null) { try { Class clazz = Class.forName(IMPL_NAME); - Object object = clazz.getDeclaredConstructor().newInstance(); + Object object = ReflectionUtil.newInstance(MethodHandles.lookup(), clazz); instance = TestHelpersSpi.class.cast(object); } catch (Exception e) { throw ConnectorException.wrap(e); @@ -309,7 +311,7 @@ public static PropertyBag getProperties(Class clazz, String environment) { Class configObject = Class.forName("groovy.util.ConfigObject"); Object slurpInstance = null; if (StringUtil.isBlank(environment)) { - slurpInstance = slurper.getDeclaredConstructor().newInstance(); + slurpInstance = ReflectionUtil.newInstance(MethodHandles.lookup(), slurper); } else { slurpInstance = slurper.getConstructor(String.class).newInstance(environment); } diff --git a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorDocBuilder.java b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorDocBuilder.java index 398e104f1..ac9ec7cbb 100644 --- a/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorDocBuilder.java +++ b/OpenICF-maven-plugin/src/main/java/org/forgerock/openicf/maven/ConnectorDocBuilder.java @@ -26,6 +26,7 @@ package org.forgerock.openicf.maven; import java.io.Writer; +import java.lang.invoke.MethodHandles; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; @@ -56,6 +57,7 @@ import org.codehaus.plexus.util.ReaderFactory; import org.identityconnectors.common.CollectionUtil; import org.identityconnectors.common.Pair; +import org.identityconnectors.common.ReflectionUtil; import org.identityconnectors.framework.api.APIConfiguration; import org.identityconnectors.framework.api.ConfigurationProperty; import org.identityconnectors.framework.api.ConnectorFacadeFactory; @@ -200,7 +202,7 @@ protected void executeReport() throws MojoExecutionException { Class connectorClass = ((LocalConnectorInfoImpl) info).getConnectorClass(); try { - SchemaOp connector = (SchemaOp) connectorClass.getDeclaredConstructor().newInstance(); + SchemaOp connector = (SchemaOp) ReflectionUtil.newInstance(MethodHandles.lookup(), connectorClass); schema = connector.schema(); } catch (Throwable t) { handler.getLog().debug("Getting Schema with Connector Instance", t); diff --git a/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/XMLConfigurationTests.java b/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/XMLConfigurationTests.java index 2c3b7e69f..cf882a079 100644 --- a/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/XMLConfigurationTests.java +++ b/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/XMLConfigurationTests.java @@ -20,6 +20,7 @@ * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted 2010 [name of copyright owner]" + * Portions Copyright 2026 3A Systems, LLC. * * $Id$ */ @@ -29,6 +30,7 @@ import org.testng.annotations.BeforeMethod; import org.testng.AssertJUnit; import java.io.File; +import java.io.IOException; public class XMLConfigurationTests { @@ -74,4 +76,21 @@ public void shouldThrowIllegalArgumentExceptionWhenValidatingWithBlankFilepath() config.setXmlFilePath(new File("")); config.validate(); } + + @Test + public void shouldValidateXmlFilePathWithoutParentDirectory() throws IOException { + File xsd = File.createTempFile("schema", ".xsd"); + File xml = new File("xml-config-" + System.nanoTime() + ".xml"); + try { + AssertJUnit.assertNull(xml.getParentFile()); + config.setXsdFilePath(xsd); + config.setXmlFilePath(xml); + config.setCreateFileIfNotExists(true); + config.validate(); + AssertJUnit.assertFalse(xml.exists()); + } finally { + xml.delete(); + xsd.delete(); + } + } } diff --git a/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTest.java b/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTest.java index c2b7c6eb9..f6de3982e 100644 --- a/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTest.java +++ b/OpenICF-xml-connector/src/test/java/org/forgerock/openicf/connectors/xml/util/AttributeTypeUtilTest.java @@ -16,6 +16,11 @@ package org.forgerock.openicf.connectors.xml.util; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.math.BigDecimal; +import java.math.BigInteger; import org.identityconnectors.framework.common.exceptions.ConnectorException; import org.testng.annotations.Test; @@ -32,6 +37,8 @@ public void createInstantiatedObjectParsesEachNumericType() { assertEquals(AttributeTypeUtil.createInstantiatedObject("3.5", XmlHandlerUtil.DOUBLE), 3.5); assertEquals(AttributeTypeUtil.createInstantiatedObject("3.5", XmlHandlerUtil.FLOAT_PRIMITIVE), 3.5f); assertEquals(AttributeTypeUtil.createInstantiatedObject("3.5", XmlHandlerUtil.FLOAT), 3.5f); + assertEquals(AttributeTypeUtil.createInstantiatedObject("3", XmlHandlerUtil.BIG_INTEGER), new BigInteger("3")); + assertEquals(AttributeTypeUtil.createInstantiatedObject("3.5", XmlHandlerUtil.BIG_DECIMAL), new BigDecimal("3.5")); } /** @@ -40,16 +47,24 @@ public void createInstantiatedObjectParsesEachNumericType() { * NumberFormatException with no indication of which attribute it came * from. */ - @Test(expectedExceptions = ConnectorException.class, - dataProvider = "numericTypes") + @Test(dataProvider = "numericTypes") public void createInstantiatedObjectWrapsMalformedNumber(String type) { - AttributeTypeUtil.createInstantiatedObject("not-a-number", type); + assertWrapsNumberFormatException("not-a-number", type); } - @Test(expectedExceptions = ConnectorException.class, - dataProvider = "numericTypes") + @Test(dataProvider = "numericTypes") public void createInstantiatedObjectWrapsBlankNumber(String type) { - AttributeTypeUtil.createInstantiatedObject("", type); + assertWrapsNumberFormatException("", type); + } + + private static void assertWrapsNumberFormatException(String value, String type) { + try { + AttributeTypeUtil.createInstantiatedObject(value, type); + fail("ConnectorException expected for " + type); + } catch (ConnectorException e) { + assertEquals(e.getMessage(), "Value '" + value + "' is not a valid " + type); + assertTrue(e.getCause() instanceof NumberFormatException); + } } @org.testng.annotations.DataProvider @@ -63,6 +78,8 @@ public Object[][] numericTypes() { { XmlHandlerUtil.DOUBLE }, { XmlHandlerUtil.FLOAT_PRIMITIVE }, { XmlHandlerUtil.FLOAT }, + { XmlHandlerUtil.BIG_INTEGER }, + { XmlHandlerUtil.BIG_DECIMAL }, }; } }