Class CalendricalRule<T>
- java.lang.Object
-
- javax.time.calendar.CalendricalRule<T>
-
- Type Parameters:
T
- the underlying type representing the data, typically aCalendrical
,Number
orEnum
, must be immutable, should be comparable
- All Implemented Interfaces:
Serializable
,Comparable<CalendricalRule<?>>
,Comparator<Calendrical>
- Direct Known Subclasses:
DateTimeFieldRule
public abstract class CalendricalRule<T> extends Object implements Comparable<CalendricalRule<?>>, Comparator<Calendrical>, Serializable
A rule defining how a single well-defined calendrical element operates.Calendrical rules may define fields like day-of-month, combinations like date-time, or other related types like time-zone.
Each rule uses an underlying type to represent the data. This is captured in the generic type of the rule. The underlying type is reified and made available via
getReifiedType()
. It is expected, but not enforced, that the underlying type isComparable
.CalendricalRule is an abstract class and must be implemented with care to ensure other classes in the framework operate correctly. All instantiable subclasses must be final, immutable and thread-safe and must ensure serialization works correctly.
- Author:
- Michael Nascimento Santos, Stephen Colebourne
- See Also:
- Serialized Form
-
-
Constructor Summary
Constructors Modifier Constructor Description protected
CalendricalRule(Class<T> reifiedClass, Chronology chronology, String name, PeriodUnit periodUnit, PeriodUnit periodRange)
Constructor used to create a rule.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description int
compare(Calendrical cal1, Calendrical cal2)
Compares twoCalendrical
implementations based on the value of this rule extracted from each calendrical.int
compareTo(CalendricalRule<?> other)
Compares thisCalendricalRule
to another.protected T
derive(Calendrical calendrical)
Derives the value of this rule from a calendrical.<R> R
deriveValueFor(CalendricalRule<R> rule, T value, Calendrical calendrical, Chronology chronology)
Derives the value of the specified rule from a calendrical.T
deriveValueFrom(Calendrical calendrical)
Derives the value of this rule from a calendrical.boolean
equals(Object obj)
Compares two rules based on their ID.Chronology
getChronology()
Gets the chronology of the rule.String
getID()
Gets the ID of the rule.String
getName()
Gets the name of the rule.PeriodUnit
getPeriodRange()
Gets the range that the rule is bound by.PeriodUnit
getPeriodUnit()
Gets the unit that the rule is measured in.Class<T>
getReifiedType()
Gets the reified class representing the underlying type of the rule.T
getValue(Calendrical calendrical)
Gets the value of this rule from the specified calendrical returningnull
if the value cannot be returned.T
getValueChecked(Calendrical calendrical)
Gets the value of the rule from the specified calendrical throwing an exception if the rule cannot be returned.int
hashCode()
Returns a hash code based on the ID.protected T
interpret(CalendricalMerger merger, Object value)
Interprets the specified value converting it into an in range value of the correct type for this rule.protected void
merge(CalendricalMerger merger)
Merges this field with other fields to form higher level fields.T
reify(Object value)
Returns the input value cast to the correct generic type.String
toString()
Returns a string representation of the rule.-
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
-
Methods inherited from interface java.util.Comparator
reversed, thenComparing, thenComparing, thenComparing, thenComparingDouble, thenComparingInt, thenComparingLong
-
-
-
-
Constructor Detail
-
CalendricalRule
protected CalendricalRule(Class<T> reifiedClass, Chronology chronology, String name, PeriodUnit periodUnit, PeriodUnit periodRange)
Constructor used to create a rule.- Parameters:
reifiedClass
- the reified class, not nullchronology
- the chronology, not nullname
- the name of the type, not nullperiodUnit
- the period unit, may be nullperiodRange
- the period range, may be null
-
-
Method Detail
-
getChronology
public final Chronology getChronology()
Gets the chronology of the rule.- Returns:
- the chronology of the rule, never null
-
getID
public final String getID()
Gets the ID of the rule.The ID is of the form 'ChronologyName.RuleName'. No two fields should have the same ID.
- Returns:
- the ID of the rule, never null
-
getName
public final String getName()
Gets the name of the rule.Implementations should use the name that best represents themselves. If the rule represents a field, then the form 'UnitOfRange' should be used. Otherwise, use the simple class name of the generic type, such as 'ZoneOffset'.
- Returns:
- the name of the rule, never null
-
getPeriodUnit
public PeriodUnit getPeriodUnit()
Gets the unit that the rule is measured in.Most rules define a field such as 'hour of day' or 'month of year'. The unit is the period that varies within the range.
For example, the rule for hour-of-day will return Hours, while the rule for month-of-year will return Months. The rule for a date will return Days as a date could alternately be described as 'days of forever'.
The
null
value is returned if the rule is not defined by a unit and range.- Returns:
- the unit defining the rule unit, null if this rule isn't based on a period
-
getPeriodRange
public PeriodUnit getPeriodRange()
Gets the range that the rule is bound by.Most rules define a field such as 'hour of day' or 'month of year'. The range is the period that the field varies within.
For example, the rule for hour-of-day will return Days, while the rule for month-of-year will return Years.
When the range is unbounded, such as for a date or the year field, then
null
will be returned. Thenull
value is also returned if the rule is not defined by a unit and range.- Returns:
- the unit defining the rule range, null if unbounded, or if this rule isn't based on a period
-
getReifiedType
public final Class<T> getReifiedType()
Gets the reified class representing the underlying type of the rule.Each rule uses an underlying type to represent the data. This is captured in the generic type of the rule. Since the generic implementation is Java is limited to the compiler, the underlying type has been reified and made available through this method. It is expected, but not enforced, that the underlying type is
Comparable
.- Returns:
- the reified type of values of the rule, never null
-
reify
public final T reify(Object value)
Returns the input value cast to the correct generic type.Each rule uses an underlying type to represent the data. This is captured in the generic type of the rule. Since the generic implementation is Java is limited to the compiler, the underlying type has been reified which allows this method to validate the generic type fully. The implementation simply returns the input value typed as the generic type.
- Parameters:
value
- the value to reify, may be null- Returns:
- the type-cast input value, may be null
- Throws:
ClassCastException
- if the value is not of the reified type
-
getValue
public final T getValue(Calendrical calendrical)
Gets the value of this rule from the specified calendrical returningnull
if the value cannot be returned.This method simply queries the calendrical.
- Parameters:
calendrical
- the calendrical to get the field value from, not null- Returns:
- the value of the field, null if unable to extract the field
-
getValueChecked
public final T getValueChecked(Calendrical calendrical)
Gets the value of the rule from the specified calendrical throwing an exception if the rule cannot be returned.This convenience method uses
getValue(Calendrical)
to find the value and then ensures it isn'tnull
.- Parameters:
calendrical
- the calendrical to get the field value from, not null- Returns:
- the value of the field, never null
- Throws:
UnsupportedRuleException
- if the rule cannot be extracted
-
deriveValueFor
public final <R> R deriveValueFor(CalendricalRule<R> rule, T value, Calendrical calendrical, Chronology chronology)
Derives the value of the specified rule from a calendrical.This method is provided for implementations of
Calendrical.get(javax.time.calendar.CalendricalRule<T>)
and is rarely called directly by application code. It is used when the calendrical has its own rule, and this method is called on the rule of the calendrical implementation, not the rule passed into theget
method.public
The last parameter in the code snippet above is alwaysT get(CalendricalRule rule) { return IMPLEMENTATION_RULE.deriveValueFor(rule, this, this); } this
, however the second parameter may be a different representation, for example inYear.get(javax.time.calendar.CalendricalRule<T>)
.If this rule and the specified rule are the same, then the value is returned. Otherwise, an attempt is made to
derive(javax.time.calendar.Calendrical)
the field value.- Parameters:
rule
- the rule to retrieve, not nullvalue
- the value to return if this rule is the specified rule, not nullcalendrical
- the calendrical to get the value from, not nullchronology
- the chronology the value belongs to, null if chronology neutral- Returns:
- the value, null if unable to derive the value
-
deriveValueFrom
public final T deriveValueFrom(Calendrical calendrical)
Derives the value of this rule from a calendrical.This method is provided for implementations of
Calendrical.get(javax.time.calendar.CalendricalRule<T>)
and is rarely called directly by application code. It is used when the calendrical has its own values but does not have its own rule.public
T get(CalendricalRule rule) { // return data, for example if (rule.equals(...)) { return valueForRule; } // call this method return rule.deriveValueFrom(this); } - Parameters:
calendrical
- the calendrical to get the value from, not null- Returns:
- the value, null if unable to derive the value
-
derive
protected T derive(Calendrical calendrical)
Derives the value of this rule from a calendrical.This method derives the value for this field from other fields in the calendrical without directly querying the calendrical for the value.
For example, if this field is quarter-of-year, then the value can be derived from month-of-year.
The implementation only needs to derive the value based on its immediate parents. The use of
Calendrical.get(javax.time.calendar.CalendricalRule<T>)
will extract any further parents on demand.A typical implementation of this method obtains the parent value and performs a calculation. For example, here is a simple implementation for the quarter-of-year field:
Integer moyVal = calendrical.get(ISOChronology.monthOfYearRule()); return (moyVal != null ? ((moyVal - 1) % 4) + 1) : null;
This method is designed to be overridden in subclasses. The subclass implementation must be thread-safe. The subclass implementation must not request the value of this rule from the specified calendrical, otherwise a stack overflow error will occur.
- Parameters:
calendrical
- the calendrical to derive from, not null- Returns:
- the derived value, null if unable to derive
-
interpret
protected T interpret(CalendricalMerger merger, Object value)
Interprets the specified value converting it into an in range value of the correct type for this rule.Before this method is called, the value will be checked to ensure it is not of the type of this rule.
- Parameters:
merger
- the merger instance controlling the merge process, not nullvalue
- the value to interpret, null if unable to interpret the value- Returns:
- the interpreted value
-
merge
protected void merge(CalendricalMerger merger)
Merges this field with other fields to form higher level fields.The aim of this method is to assist in the process of extracting the most date-time information possible from a map of field-value pairs. The merging process is controlled by the mutable merger instance and the input and output of the this merge are held there.
Subclasses that override this method may use methods on the merger to obtain the values to merge. The value is guaranteed to be available for this field if this method is called.
If the override successfully merged some fields then the following must be performed. The merged field must be stored using
CalendricalMerger.storeMerged(javax.time.calendar.CalendricalRule<T>, T)
. Each field used in the merge must be marked as being used by callingCalendricalMerger.removeProcessed(javax.time.calendar.CalendricalRule<?>)
.An example to merge two fields into one - hour of AM/PM and AM/PM:
Integer hapVal = merger.getValue(ISOChronology.hourOfAmPmRule()); if (hapVal != null) { AmPmOfDay amPm = merger.getValue(this); int hourOfDay = MathUtils.safeAdd(MathUtils.safeMultiply(amPm, 12), hapVal); merger.storeMerged(ISOChronology.hourOfDayRule(), hourOfDay); merger.removeProcessed(this); merger.removeProcessed(ISOChronology.hourOfAmPmRule()); }
- Parameters:
merger
- the merger instance controlling the merge process, not null
-
compare
public int compare(Calendrical cal1, Calendrical cal2)
Compares twoCalendrical
implementations based on the value of this rule extracted from each calendrical.This implements the
Comparator
interface and allows any twoCalendrical
implementations to be compared using this rule. The comparison is based on the result of callingCalendrical.get(javax.time.calendar.CalendricalRule<T>)
on each calendrical, and comparing those values.For example, to sort a list into year order when the list may contain any mixture of calendricals, such as a
LocalDate
,YearMonth
andZonedDateTime
:List
If the value of this rule cannot be obtained from a calendrical, then an exception is thrown.list = ... Collections.sort(list, ISOChronology.yearRule()); If the underlying type of this rule does not implement
Comparable
then an exception will be thrown.- Specified by:
compare
in interfaceComparator<T>
- Parameters:
cal1
- the first calendrical to compare, not nullcal2
- the second calendrical to compare, not null- Returns:
- the comparator result, negative if first is less, positive if first is greater, zero if equal
- Throws:
NullPointerException
- if either input is nullClassCastException
- if this rule has a type that is not comparableIllegalArgumentException
- if this rule cannot be extracted from either input parameter
-
compareTo
public int compareTo(CalendricalRule<?> other)
Compares thisCalendricalRule
to another.The comparison is based on the period unit followed by the period range followed by the rule ID. The period unit is compared first, so MinuteOfHour will be less than HourOfDay, which will be less than DayOfWeek. When the period unit is the same, the period range is compared, so DayOfWeek is less than DayOfMonth, which is less than DayOfYear. Finally, the rule ID is compared.
- Specified by:
compareTo
in interfaceComparable<T>
- Parameters:
other
- the other type to compare to, not null- Returns:
- the comparator result, negative if less, positive if greater, zero if equal
- Throws:
NullPointerException
- if other is null
-
equals
public boolean equals(Object obj)
Compares two rules based on their ID.- Specified by:
equals
in interfaceComparator<T>
- Overrides:
equals
in classObject
- Returns:
- true if the rules are the same
-
hashCode
public int hashCode()
Returns a hash code based on the ID.
-
-