jmrozanec/cron-utils

Implement equals and hashCode

csisy opened this issue · 3 comments

csisy commented

It would be nice if the equals and hashCode would be implemented especially for the CronDefinition.

Example use case: We need to figure out if a given cron definition is one of the pre-defined ones (QUARTZ, for example). In the following code eq == false, because the mentioned methods are not implemented at all.

final var a = instanceDefinitionFor(CronType.QUARTZ);
final var b = instanceDefinitionFor(CronType.QUARTZ);
final var eq = a.equals(b); // false

Or is there any other way to find whether a given cron definition matches another one?

@csisy thank you for using cron-utils, and the feedback provided. We will work on it. Contributions are always welcome! 😄 If you could provide some tests to highlight this functionality, we will be glad to merge them. Best!

csisy commented

Thank you for the library! :)

Didn't have the time to create it as a pull request, but the test code would be something like this:

package com.cronutils.model.definition;

// ...

public class CronDefinitionTest {
	// ...

	@ParameterizedTest
	@EnumSource(CronType.class)
	public void testBuiltInDefinitionsAreEqual(CronType cronType) {
		final var definition1 = instanceDefinitionFor(cronType);
		final var definition2 = instanceDefinitionFor(cronType);

		assertEquals(definition1, definition2);
	}

	@Test
	public void testCustomDefinitionEqualsToBuiltIn() {
		final var builtIn = instanceDefinitionFor(CronType.QUARTZ);
		final var custom = CronDefinitionBuilder.defineCron()
				.withSeconds().withValidRange(0, 59).and()
				.withMinutes().withValidRange(0, 59).and()
				.withHours().withValidRange(0, 23).and()
				.withDayOfMonth().withValidRange(1, 31).supportsL().supportsW().supportsLW().supportsQuestionMark().and()
				.withMonth().withValidRange(1, 12).and()
				.withDayOfWeek().withValidRange(1, 7).withMondayDoWValue(2).supportsHash().supportsL().supportsQuestionMark().and()
				.withYear().withValidRange(1970, 2099).withStrictRange().optional().and()
				.withCronValidation(CronConstraintsFactory.ensureEitherDayOfWeekOrDayOfMonth())
				.instance();

		assertEquals(builtIn, custom);
	}

Implementing equals and hashCode can be a bit tricky however, not sure what would be the correct implementation.

Instead of implementing equals and hashCode on the CronDefinition itself, a helper method could be created, something like boolean isDefinitionOf(CronType cronType), maybe on the CronDefinition itself.

@ParameterizedTest
@EnumSource(CronType.class)
public void testWhetherBuiltInOrNot(CronType cronType) {
	final var definition = instanceDefinitionFor(cronType);
	
	assertTrue(definition.isDefinitionOf(cronType));
}

Without equals, its implementation would be redundant with the definition itself. However, we could make the built-in definitions singletons and a simple reference equals would be enough in this case. Another option would be a package-private CronDefinition constructor that has an additional CronType parameter. When a built-in instanceDefinitionFor is used, it could pass the appropriate CronType to the constructor.

However, none of these would work with custom-built cron definitions that are actually equal to one of the built-in definition, but since it's built by the user code, the above methods would not work properly. This is not a use-case for us, but added for the sake of completeness.

The use-case is that we'd like to store some data that contains a CronDefinition. The data must be serialized (into a string) and it would be nice if the serialized data would only contain "QUARTZ" instead of the fully serialized CronDefinition object, since we can easily restore a CronDefinition from a name (using instanceDefinitionFor).

What do you think, what would be an easy way to determine whether a CronDefinition is a built-in one or not? Or better, how to serialize (and deserialize) a built-in CronDefinition in a more compact way?

Thanks

@csisy @kamilbednarski release 9.1.7 was published! Thanks! 😄