I'm trying to extends TemporalAdjuster so that one looks like,
public interface TypedTemporalAdjuster<T extends Temporal & Comparable<? super T>> {
T adjustInto(T temporal);
}
When I tried to directly extends the base interface,
public interface TypedTemporalAdjuster<T extends Temporal & Comparable<? super T>>
extends TemporalAdjuster {
T adjustInto(T temporal);
}
I got an error.
...java: name clash: ... have the same erasure, yet neither overrides the other
Is there any way to do this?
So far, I did.
public interface TypedTemporalAdjuster<T extends Temporal & Comparable<? super T>> { //extends TemporalAdjuster {
static <T extends Temporal & Comparable<? super T>> TypedTemporalAdjuster<T> of(
final Class<T> temporalClass, final TemporalAdjuster temporalAdjuster) {
return temporal -> temporalClass.cast(temporalAdjuster.adjustInto(temporalClass.cast(temporal)));
}
T adjustInto(T temporal);
}
You can not override a method with more restrictive parameters, i.e. T adjustInto(T temporal); does not override Temporal adjustInto(Temporal temporal); as the parameter type T is more restrictive than Temporal. So you have two methods with the name adjustInto now, but due to type erasure, the parameter types are identical on the byte code level, as T extends Temporal & Comparable<? super T> gets erased to Temporal.
You could fix that by changing the declaration to
public interface TypedTemporalAdjuster<T extends Comparable<? super T> & Temporal>
extends TemporalAdjuster {
T adjustInto(T temporal);
}
as then, the semantically identical T extends Comparable<? super T> & Temporal gets erased to Comparable instead of Temporal. You could also use T extends Object & Comparable<? super T> & Temporal which gets erased to Object (usually, such knowledge is only relevant when you need compatibility with pre-Generics code).
However, the fundamental problem remains, adjustInto(T temporal); does not override adjustInto(Temporal temporal); as T is a more restrictive parameter, so now, the interface is not a functional interface anymore, as it has two abstract methods.
A sub-interface of TemporalAdjuster must provide all of its operatation, including an adjustInto accepting any Temporal. So you can only do
public interface TypedTemporalAdjuster<T extends Temporal & Comparable<? super T>>
extends TemporalAdjuster {
static <T extends Temporal & Comparable<? super T>> TypedTemporalAdjuster<T> of(
final Class<T> temporalClass, final TemporalAdjuster temporalAdjuster) {
return temporal -> temporalClass.cast(temporalAdjuster.adjustInto(temporal));
}
@Override T adjustInto(Temporal temporal);
}
However, such wrapped adjusters can not ensure correct arguments and only hide the type cast which still may fail at runtime. But it looks like you are trying to solve a non-existent problem here, as you can simply use the with method on the temporal, to get a type safe operation, e.g.
TemporalAdjuster a = TemporalAdjusters.lastDayOfMonth();
LocalDate date1 = LocalDate.now(), date2 = date1.with(a);
LocalDateTime dateTime1 = LocalDateTime.now(), dateTime2 = dateTime1.with(a);
ZonedDateTime zoned1 = ZonedDateTime.now(), zoned2 = zoned1.with(a);
That’s even more powerful than your wrapper, as when you do, e.g.
TemporalAdjuster a = TemporalAdjusters.ofDateAdjuster(date -> date.plusDays(1));
ZonedDateTime zoned1 = ZonedDateTime.now(), zoned2 = zoned1.with(a);
You define an operation only once, in terms of a LocalDate manipulation, while it works for other temporals by converting them on-the-fly, rather than casting.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With