Skip to content

Conversation

@rogin
Copy link
Contributor

@rogin rogin commented Apr 19, 2025

This was an old feature, requested by several people, that NextGen chose to ignore. Prior code review comments are here. I compiled it with Java 8, and the test ran successfully. No further testing on my part.

@tonygermano
Copy link
Member

Thanks for submitting this! I always meant to give it a more thorough review and suggest a few things. Just a heads up, this probably will not be a top priority until after we get our first release out the door.

Signed-off-by: Richard Ogin <rogin@users.noreply.github.com>
@NicoPiel
Copy link
Contributor

NicoPiel commented Sep 3, 2025

Can this be revisited now? @tonygermano

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements the java.util.Set<Integer> interface for the DestinationSet class, addressing a long-standing feature request. The implementation adds standard Set methods (add, contains, iterator, etc.) and modernizes the code with Java 8 streams and Optional.

Key Changes:

  • DestinationSet now implements Set<Integer>, enabling use as a standard Java collection
  • Refactored existing methods to use streams and Optional for cleaner code
  • Added comprehensive test suite with 20+ test cases covering Set interface methods

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 21 comments.

File Description
server/src/com/mirth/connect/server/userutil/DestinationSet.java Implements Set interface with all required methods, refactors internal logic to use streams and Optional
server/test/com/mirth/connect/userutil/DestinationSetTest.java Adds comprehensive test suite for Set interface implementation and existing functionality

Critical Issues Found:

  1. NullPointerException bug: The constructor leaves metaDataIds null when the source map doesn't contain the required key, causing NPEs in all Set methods
  2. Test reliability: Multiple tests assume HashSet iteration order, which is not guaranteed and could cause intermittent test failures
  3. Missing test coverage: No test for the scenario where the source map lacks the DESTINATION_SET_KEY

Code Quality Issues:

  • Inconsistent spacing in control flow statements (if, for)
  • Unchecked casts that will generate compiler warnings
  • Comment formatting inconsistencies

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


@Override
public boolean retainAll(Collection<?> metaDataIdOrConnectorNames) {
return removeAllExcept((Collection<Object>)metaDataIdOrConnectorNames);
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unchecked cast from Collection<?> to Collection<Object>. While this works, it will generate a compiler warning. Consider adding @SuppressWarnings("unchecked") to this method or refactoring to avoid the cast.

Copilot uses AI. Check for mistakes.

@Override
public boolean removeAll(Collection<?> metaDataIdOrConnectorNames) {
return remove((Collection<Object>)metaDataIdOrConnectorNames);
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unchecked cast from Collection<?> to Collection<Object>. While this works, it will generate a compiler warning. Consider adding @SuppressWarnings("unchecked") to this method or refactoring to avoid the cast.

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +63
@Test
public void testIsEmptyWithoutSourceMapKey() throws Exception {
DestinationSet ds = getNewTestDestinationSetUsing(new Integer[0]);

assertTrue(ds.isEmpty());
assertEquals(0, ds.size());
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name testIsEmptyWithoutSourceMapKey is misleading. The test actually creates a source map WITH the key (line 47 in getNewTestDestinationSetUsing), just with an empty set.

There's no test coverage for the scenario where the source map does NOT contain Constants.DESTINATION_SET_KEY at all (i.e., when line 45 in DestinationSet.java returns false). This is a critical gap because that scenario will cause a NullPointerException with the current implementation.

Add a test like:

@Test
public void testWithoutSourceMapKey() throws Exception {
    ConnectorMessage cm = new ConnectorMessage();
    Map<String, Object> sm = new HashMap<>();
    // Don't put DESTINATION_SET_KEY in the map
    cm.setSourceMap(sm);
    ImmutableConnectorMessage icm = new ImmutableConnectorMessage(cm);
    DestinationSet ds = new DestinationSet(icm);
    
    assertTrue(ds.isEmpty());
    assertEquals(0, ds.size());
}

Copilot uses AI. Check for mistakes.
Comment on lines +353 to +364
public void testToArrayGenericProperlySized() throws Exception {
DestinationSet ds = getNewTestDestinationSet();

Integer[] arr = new Integer[ds.size()];
//the input and response should be the same array
Integer[] resp = ds.toArray(arr);
assertEquals(3, resp.length);
assertTrue(Arrays.equals(arr, resp));
assertEquals(Integer.valueOf(1), arr[0]);
assertEquals(Integer.valueOf(2), arr[1]);
assertEquals(Integer.valueOf(3), arr[2]);
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test assumes a specific array order (1, 2, 3), but DestinationSet uses a HashSet internally, which does not guarantee any specific order. The test is flawed and could fail intermittently.

The test should verify that all expected elements are present without assuming order.

Copilot uses AI. Check for mistakes.
DestinationSet ds = getNewTestDestinationSet();

Integer[] arr = new Integer[ds.size()];
//the input and response should be the same array
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment formatting should follow convention with a space after //. Should be // the input and response should be the same array.

Suggested change
//the input and response should be the same array
// the input and response should be the same array

Copilot uses AI. Check for mistakes.

assertFalse(ds.contains(0));
assertTrue(ds.contains(1));
assertTrue(ds.contains("Map to 2"));
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actual argument type 'String' is incompatible with expected argument type 'Integer'.

Suggested change
assertTrue(ds.contains("Map to 2"));
assertTrue(ds.contains(2));

Copilot uses AI. Check for mistakes.
assertTrue(ds.contains("Map to 2"));
assertTrue(ds.contains(3));
assertFalse(ds.contains(4));
assertFalse(ds.contains("Invalid"));
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actual argument type 'String' is incompatible with expected argument type 'Integer'.

Copilot uses AI. Check for mistakes.
* @return A boolean indicating whether at least one destination connector was actually removed
* from processing for this message.
*/
public boolean removeAllExcept(Object metaDataIdOrConnectorName) {
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method DestinationSet.removeAllExcept(..) could be confused with overloaded method removeAllExcept, since dispatch depends on static types.

Copilot uses AI. Check for mistakes.
* @return A boolean indicating whether at least one destination connector was actually removed
* from processing for this message.
*/
public boolean remove(Object metaDataIdOrConnectorName) {
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method DestinationSet.remove(..) could be confused with overloaded method remove, since dispatch depends on static types.

Copilot uses AI. Check for mistakes.
* destination connector name.
* @return A boolean indicating whether at least one destination connector was actually removed
* from processing for this message.
*/
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method overrides Set.remove; it is advisable to add an Override annotation.

Suggested change
*/
*/
@Override

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants