Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import org.yarnandtail.andhow.valuetype.LocalDateTimeType;

/**
* A Property that refers to a Long value.
* A Property that refers to a LocalDateTime value.
Copy link
Owner

Choose a reason for hiding this comment

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

Nice catch - I wonder how long that has been there??

*
* All the basic Java types use a three letter abv. to keep declaration lines
* short, in the form of: [Type]Prop
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package org.yarnandtail.andhow.property;

import org.yarnandtail.andhow.api.*;
import org.yarnandtail.andhow.valid.ZonedDateTimeValidator;
import org.yarnandtail.andhow.valuetype.ZonedDateTimeType;

import java.time.ZonedDateTime;
import java.util.List;

/**
* A Property that refers to a ZonedDateTime value.
*
* By default this uses the TrimToNullTrimmer, which removes all whitespace from
* the value and ultimately null if the value is all whitespace. The String
* constructor version is used when creating instances of BigDecimal.
Copy link
Owner

Choose a reason for hiding this comment

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

The note about 'BigDecimal' can just be deleted. But, it would be nice to note how the string value is interpreted in this class. There is a note about string date format further down.

*
* @author chace86
*/
public class ZonedDateTimeProp extends PropertyBase<ZonedDateTime> {
Copy link
Owner

Choose a reason for hiding this comment

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

It looks like you started from BigDecimal as a template for this class, but LocalDateTime might be a better place to start. The builder methods in LocalDateTime use time related terms like before and after, rather that greater than or less than.


public ZonedDateTimeProp(ZonedDateTime defaultValue, boolean required, String shortDesc, List<Validator<ZonedDateTime>> validators,
List<Name> aliases, PropertyType paramType, ValueType<ZonedDateTime> valueType, Trimmer trimmer, String helpText) {
super(defaultValue, required, shortDesc, validators, aliases, paramType, valueType, trimmer, helpText);
}

/**
* Return an instance of ZonedDateTimeBuilder
*/
public static ZonedDateTimeBuilder builder() { return new ZonedDateTimeBuilder(); }

/**
* Build a ZonedDateTimeProp
*/
public static class ZonedDateTimeBuilder extends PropertyBuilderBase<ZonedDateTimeBuilder, ZonedDateTimeProp, ZonedDateTime> {

/**
* Construct an instance of ZonedDateTimeBuilder
*/
public ZonedDateTimeBuilder() {
instance = this;
valueType(ZonedDateTimeType.instance());
trimmer(TrimToNullTrimmer.instance());
}

@Override
public ZonedDateTimeProp build() {
return new ZonedDateTimeProp(_defaultValue, _nonNull, _desc, _validators,
_aliases, PropertyType.SINGLE_NAME_VALUE, _valueType, _trimmer, _helpText);
}

/**
* The property must be greater than the reference
* @param reference value the property must be greater than
* @return the builder instance
*/
public ZonedDateTimeBuilder mustBeGreaterThan(ZonedDateTime reference) {
Copy link
Owner

Choose a reason for hiding this comment

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

See naming in LocalDateTime for all.

validation(new ZonedDateTimeValidator.GreaterThan(reference));
return instance;
}

/**
* The property must be greater than or equal to the reference
* @param reference value the property must be greater than or equal to
* @return the builder instance
*/
public ZonedDateTimeBuilder mustBeGreaterThanOrEqualTo(ZonedDateTime reference) {
validation(new ZonedDateTimeValidator.GreaterThanOrEqualTo(reference));
return instance;
}

/**
* The property must be less than the reference
* @param reference value the property must be less than
* @return the builder instance
*/
public ZonedDateTimeBuilder mustBeLessThan(ZonedDateTime reference) {
validation(new ZonedDateTimeValidator.LessThan(reference));
return instance;
}

/**
* The property must be less than or equal to the reference
* @param reference value the property must be less than or equal to
* @return the builder instance
*/
public ZonedDateTimeBuilder mustBeLessThanOrEqualTo(ZonedDateTime reference) {
validation(new ZonedDateTimeValidator.LessThanOrEqualTo(reference));
return instance;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package org.yarnandtail.andhow.valid;

import org.yarnandtail.andhow.api.Validator;

import java.time.ZonedDateTime;

/**
* Abstract class implementing the Validator interface for ZonedDateTime.
* Extended by nested static classes. The nested classes implement
* constraints that may be used when building the property.
*/
public abstract class ZonedDateTimeValidator implements Validator<ZonedDateTime> {
Copy link
Owner

Choose a reason for hiding this comment

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

Similar, refer to LocalDateTimeValidator.java for method names, ie before/after.


final ZonedDateTime ref;

/**
* Base constructor of ZonedDateTimeValidator constraints
* @param ref to be compared to property value
*/
ZonedDateTimeValidator(ZonedDateTime ref) { this.ref = ref; }

@Override
public boolean isSpecificationValid() { return ref != null; }

@Override
public String getInvalidSpecificationMessage() { return "The constraint may not be null"; }

/**
* Validate that a ZonedDateTime is greater than specified reference.
*/
public static class GreaterThan extends ZonedDateTimeValidator {

/**
* Construct a GreaterThan property constraint
* @param ref to be compared to property value
*/
public GreaterThan(ZonedDateTime ref) { super(ref); }

@Override
public boolean isValid(ZonedDateTime value) { return value != null && value.isAfter(ref); }

@Override
public String getTheValueMustDescription() { return "be greater than " + ref.toString(); }
}

/**
* Validate that a ZonedDateTime is greater than or equal to specified reference.
*/
public static class GreaterThanOrEqualTo extends ZonedDateTimeValidator {

/**
* Construct a GreaterThanOrEqualTo property constraint
* @param ref to be compared to property value
*/
public GreaterThanOrEqualTo(ZonedDateTime ref) { super(ref); }

@Override
public boolean isValid(ZonedDateTime value) { return value != null && (value.isEqual(ref) || value.isAfter(ref)); }

@Override
public String getTheValueMustDescription() { return "be greater than or equal to " + ref; }
}

/**
* Validate that a ZonedDateTime is less than to specified reference.
*/
public static class LessThan extends ZonedDateTimeValidator {

/**
* Construct a LessThan property constraint
* @param ref to be compared to property value
*/
public LessThan(ZonedDateTime ref) { super(ref); }

@Override
public boolean isValid(ZonedDateTime value) { return value != null && value.isBefore(ref); }

@Override
public String getTheValueMustDescription() { return "be less than " + ref; }
}

/**
* Validate that a ZonedDateTime is less than or equal to specified reference.
*/
public static class LessThanOrEqualTo extends ZonedDateTimeValidator {

/**
* Construct a LessThanOrEqualTo property constraint
* @param ref to be compared to property value
*/
public LessThanOrEqualTo(ZonedDateTime ref) { super(ref); }

@Override
public boolean isValid(ZonedDateTime value) { return value != null && (value.isEqual(ref) || value.isBefore(ref)); }

@Override
public String getTheValueMustDescription() { return "be less than or equal to " + ref; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/**
* Type representation of Java BigDecimal objects.
*
* This class is threadsafe and uses a singleton pattern to prevent multiple
* This class is threadsafe and uses a singleton pattern to prevent multiple
* instances, since all users can safely use the same instance.
*
* @author chace86
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.yarnandtail.andhow.valuetype;

import org.yarnandtail.andhow.api.ParsingException;

import java.time.ZonedDateTime;

/**
* Type representation of a Java ZonedDateTime objects.
*
* This class is threadsafe and uses a singleton pattern to prevent multiple
* instances, since all users can safely use the same instance.
*
* @author chace86
*/
public class ZonedDateTimeType extends BaseValueType<ZonedDateTime> {

private static final ZonedDateTimeType INSTANCE = new ZonedDateTimeType();

private ZonedDateTimeType() { super(ZonedDateTime.class); }

/**
* @return An instance of the {@link #ZonedDateTimeType()}
*/
public static ZonedDateTimeType instance() { return INSTANCE; }

/**
* The text format used is the default for ZonedDateTime objects, which uses the
* ISO format like this: <code>2019-10-31T03:16:15.149Z[Europe/Paris]</code>. Full documentation
* is here: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_ZONED_DATE_TIME
* @param sourceValue The {@link String} value to be parsed into a @{@link ZonedDateTime}
* @return A valid @{@link ZonedDateTime}
* @throws ParsingException If the @{@link String} cannot be parsed into a @{@link ZonedDateTime}
*/
@Override
public ZonedDateTime parse(String sourceValue) throws ParsingException {

if (sourceValue != null) {
try {
return ZonedDateTime.parse(sourceValue);
Copy link
Owner

Choose a reason for hiding this comment

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

I think we want to make this easier to construct. The default parse method requires the square bracket construction where as most users don't care about the named region, just the hour offset. Can we switch to this format/parser: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_ZONED_DATE_TIME

That should allow either.

} catch (Exception e) {
throw new ParsingException("Unable to convert to a LocalDateTime", sourceValue, e);
Copy link
Owner

Choose a reason for hiding this comment

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

Should be ZonedDateTime

}
} else {
return null;
}
}

@Override
public ZonedDateTime cast(Object o) throws RuntimeException {
return (ZonedDateTime)o;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.yarnandtail.andhow.valid;

import org.junit.Test;

import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import static org.junit.Assert.*;

public class ZonedDateTimeValidatorTest {

private static String EXPECTED_DBL_VALIDATOR_INVALID_MESSAGE = "The constraint may not be null";
private static final ZonedDateTime CURRENT_TIME = ZonedDateTime.now();

@Test
public void testGreaterThan_IsSpecificationValid() {
ZonedDateTimeValidator.GreaterThan instance = new ZonedDateTimeValidator.GreaterThan(CURRENT_TIME);
assertTrue(instance.isSpecificationValid());

instance = new ZonedDateTimeValidator.GreaterThan(null);
assertFalse(instance.isSpecificationValid());
assertEquals(EXPECTED_DBL_VALIDATOR_INVALID_MESSAGE, instance.getInvalidSpecificationMessage());
}

@Test
public void testGreaterThan_GetTheValueMustDescription() {
ZonedDateTimeValidator.GreaterThan instance = new ZonedDateTimeValidator.GreaterThan(CURRENT_TIME);
assertEquals("be greater than " + CURRENT_TIME, instance.getTheValueMustDescription());
}

@Test
public void testGreaterThan_IsValid() {
ZonedDateTimeValidator.GreaterThan instance = new ZonedDateTimeValidator.GreaterThan(CURRENT_TIME);
assertFalse(instance.isValid(CURRENT_TIME));
assertFalse(instance.isValid(CURRENT_TIME.minus(1, ChronoUnit.DAYS)));
assertTrue(instance.isValid(CURRENT_TIME.plus(1, ChronoUnit.DAYS)));
assertFalse(instance.isValid(null));
}

@Test
public void testGreaterThanOrEqualTo_IsSpecificationValid() {
ZonedDateTimeValidator.GreaterThanOrEqualTo instance = new ZonedDateTimeValidator.GreaterThanOrEqualTo(CURRENT_TIME);
assertTrue(instance.isSpecificationValid());

instance = new ZonedDateTimeValidator.GreaterThanOrEqualTo(null);
assertFalse(instance.isSpecificationValid());
assertEquals(EXPECTED_DBL_VALIDATOR_INVALID_MESSAGE, instance.getInvalidSpecificationMessage());
}

@Test
public void testGreaterThanOrEqualTo_GetTheValueMustDescription() {
ZonedDateTimeValidator.GreaterThanOrEqualTo instance = new ZonedDateTimeValidator.GreaterThanOrEqualTo(CURRENT_TIME);
assertEquals("be greater than or equal to " + CURRENT_TIME, instance.getTheValueMustDescription());
}

@Test
public void testGreaterThanOrEqualTo_IsValid() {
ZonedDateTimeValidator.GreaterThanOrEqualTo instance = new ZonedDateTimeValidator.GreaterThanOrEqualTo(CURRENT_TIME);
assertTrue(instance.isValid(CURRENT_TIME));
assertFalse(instance.isValid(CURRENT_TIME.minus(1, ChronoUnit.DAYS)));
assertTrue(instance.isValid(CURRENT_TIME.plus(1, ChronoUnit.DAYS)));
assertFalse(instance.isValid(null));
}

@Test
public void testLessThan_IsSpecificationValid() {
ZonedDateTimeValidator.LessThan instance = new ZonedDateTimeValidator.LessThan(CURRENT_TIME);
assertTrue(instance.isSpecificationValid());

instance = new ZonedDateTimeValidator.LessThan(null);
assertFalse(instance.isSpecificationValid());
assertEquals(EXPECTED_DBL_VALIDATOR_INVALID_MESSAGE, instance.getInvalidSpecificationMessage());
}

@Test
public void testLessThan_GetTheValueMustDescription() {
ZonedDateTimeValidator.LessThan instance = new ZonedDateTimeValidator.LessThan(CURRENT_TIME);
assertEquals("be less than " + CURRENT_TIME, instance.getTheValueMustDescription());
}

@Test
public void testLessThan_IsValid() {
ZonedDateTimeValidator.LessThan instance = new ZonedDateTimeValidator.LessThan(CURRENT_TIME);
assertFalse(instance.isValid(CURRENT_TIME));
assertTrue(instance.isValid(CURRENT_TIME.minus(1, ChronoUnit.DAYS)));
assertFalse(instance.isValid(CURRENT_TIME.plus(1, ChronoUnit.DAYS)));
assertFalse(instance.isValid(null));
}

@Test
public void testLessThanOrEqualTo_IsSpecificationValid() {
ZonedDateTimeValidator.LessThanOrEqualTo instance = new ZonedDateTimeValidator.LessThanOrEqualTo(CURRENT_TIME);
assertTrue(instance.isSpecificationValid());

instance = new ZonedDateTimeValidator.LessThanOrEqualTo(null);
assertFalse(instance.isSpecificationValid());
assertEquals(EXPECTED_DBL_VALIDATOR_INVALID_MESSAGE, instance.getInvalidSpecificationMessage());
}

@Test
public void testLessThanOrEqualTo_GetTheValueMustDescription() {
ZonedDateTimeValidator.LessThanOrEqualTo instance = new ZonedDateTimeValidator.LessThanOrEqualTo(CURRENT_TIME);
assertEquals("be less than or equal to " + CURRENT_TIME, instance.getTheValueMustDescription());
}

@Test
public void testLessThanOrEqualTo_IsValid() {
ZonedDateTimeValidator.LessThanOrEqualTo instance = new ZonedDateTimeValidator.LessThanOrEqualTo(CURRENT_TIME);
assertTrue(instance.isValid(CURRENT_TIME));
assertTrue(instance.isValid(CURRENT_TIME.minus(1, ChronoUnit.DAYS)));
assertFalse(instance.isValid(CURRENT_TIME.plus(1, ChronoUnit.DAYS)));
assertFalse(instance.isValid(null));
}
}
Loading