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