Unchecked conversion warning with generics - java

I don't quite understand, why my code has to do a unchecked conversion and how I can fix that.
I am implementing immutable objects with the builder pattern for which I implemented the "Immutable" interface with the inner interface "Builder".
Each immutable class implements the Immutable interface and implements a inner static class Builder, which implements the Builder interface.
All this works fine.
Now, I am implementing a bunch of very simple classes that don't really need a builder, but I still want to implement the Immutable interface, so the objects of those classes are instances of "Immutable", but I don't want to implement empty builders without any functionality for each class. I'd rather have an abstract class in which to implement one simple builder for all the simple classes. The builder will just store the original object and return it through the build() method, so the Immutable interface is implemented completely
The build() method of the builder has to return an object of the implementing class, though. So I added generics.
public interface Immutable {
public interface Builder<T> {
public T build();
}
public <T> Builder<T> builder();
}
public interface Interface extends Immutable {
public interface BuilderInterface<T> extends Immutable.Builder<T> {
}
}
public abstract class AbstractClass implements Interface {
public static class AbstractBuilder<T> implements Interface.BuilderInterface<T> {
private final T object;
public AbstractBuilder(T object) {
this.object = object;
}
#Override
public T build() {
return this.object;
}
}
protected AbstractClass() {
super();
}
}
public class ConcreteClass extends AbstractClass {
public ConcreteClass() {
}
#Override
public AbstractBuilder<ConcreteClass> builder() {
return new AbstractClass.AbstractBuilder<ConcreteClass>(this);
}
}
I was expecting the generic type T of the Immutable interface to take the type of the implementing class, but instead it seems to be Object, which leads to the following warning:
Type safety: The return type AbstractClass.AbstractBuilder<ConcreteClass> for builder() from the type ConcreteClass needs unchecked conversion to conform to Immutable.Builder<Object> from the type Immutable
EDIT: The warning is given by the builder() method of ConcreteClass.

It's quite simple - the method signature of Immutable#builder expects the type parameter T set "on the fly" for the actual method call and not being bound to the class. To appropriately override this method, the signatur in ConcreteClass would be
public <T> Builder<T> builder() {
which obviously clashes with your builder definition
return new AbstractClass.AbstractBuilder<ConcreteClass>(this);
To make this all compilable, you have to infer T for Immutable#builder from the class and not from the method caller, i.e. that you finally have
public interface Immutable<T> {
public interface Builder<T> {
public T build();
}
public Builder<T> builder();
}
and all inheriting classes changed accordingly to pass a T to its predecessors.
public interface Interface<T> extends Immutable<T> {
public interface BuilderInterface<T> extends Immutable.Builder<T> {
}
}
public abstract class AbstractClass<T> implements Interface<T> {
public static class AbstractBuilder<T> implements Interface.BuilderInterface<T> {
private final T object;
public AbstractBuilder(T object) {
this.object = object;
}
#Override
public T build() {
return this.object;
}
}
protected AbstractClass() {
super();
}
}
public class ConcreteClass extends AbstractClass<ConcreteClass> {
public ConcreteClass() {
}
#Override
public Builder<ConcreteClass> builder() {
return new AbstractClass.AbstractBuilder<ConcreteClass>(this);
}
}

Related

How to override abstract generic method with concrete return type?

How do I create an abstract method that is generic, but is implemented to return a concrete type?
Consider this simple abstract class:
public abstract class Master {
public abstract <T> T getValue();
}
Each of the subclasses of Master should implement the getValue() method, but return a concrete type:
public class DateSlave extends Master {
#Override
public LocalDate getValue() {
return LocalDate.now();
}
}
Or:
public class ListSlave extends Master {
#Override
public List<String> getValue() {
return new ArrayList<String>();
}
}
I assume I am doing the whole generics thing wrong as I'm not very well-versed in their usage. The above subclasses offer this warning: Unchecked overriding: return type requires unchecked conversion. Found 'java.util.List<java.lang.String>', required 'T'.
Is there a better way to create an abstract method that the subclasses must implement, while also providing their own concrete return type?
This is what you are looking for:
public abstract class Master<T> {
public abstract T getValue();
}
public class DateSlave extends Master<LocalDate> {
#Override
public LocalDate getValue() {
return LocalDate.now();
}
}
public class ListSlave extends Master<List<String>> {
#Override
public List<String> getValue() {
return new ArrayList<String>();
}
}
Master<T> is a generic class. The return type is declared on each concrete class.

How to make an interface extends its own generic type

I would like to create a contract (an interface), with a generic parameter, which enforces that the implemented class must also be the type specified in the generic parameter.
public interface SelfDefaultAlternativeDetailSupport<T extends AlternativeDetail> extends T { // syntax error (extends T)
default T resolveDetail() {
if (someConditions()) {
return this;
} else {
return getAlternativeDetails().stream()
.filter(somePredicate)
.findFirst().orElse(null);
}
}
List<T> getAlternativeDetails();
}
Example Usage
public interface CustomerDetail extends AlternativeDetail {
String getName();
}
public class Customer implements SelfDefaultAlternativeDetailSupport<CustomerDetail>, CustomerDetail {
#Override
public String getName() {
return "default name";
}
#Override
public List<AlternativeDetails> getAlternativeDetails() {
...
}
}
In other words, I would like that when a class implements SomeInterface<X>, the class must also implement X, But the attempt above has syntax because I cannot make SelfDefaultAlternativeDetailSupport extends T. Is this possible in Java?
You can make it a self-referential generic type:
public interface SelfDefaultAlternativeDetailSupport<T extends SelfDefaultAlternativeDetailSupport<T> & AlternativeDetail> {
#SuppressWarnings("unchecked")
default T resolveDetail() {
if (someConditions()) {
return (T) this;
} else {
return getAlternativeDetails().stream()
.filter(somePredicate)
.findFirst().orElse(null);
}
}
List<T> getAlternativeDetails();
}
Then you can have:
public class Customer implements SelfDefaultAlternativeDetailSupport<Customer>, CustomerDetail {
#Override
public List<Customer> getAlternativeDetails() {
...
}
}
Just be careful to never use a different class as the parameter to SelfDefaultAlternativeDetailSupport. If you want to avoid the unchecked cast of this, you can use getThis methods, but I don't think it's really worth it.

Extending abstract method with generic parameter (that must extend generic class) in Java

Let's say I have a generic builder type:
public abstract class Builder<T> {
public abstract T build();
}
Then a Foo class and a builder for it, which extends Builder:
public class Foo {
// stuff
}
public class FooBuilder extends Builder<Foo> {
public Foo build() {
return new Foo();
}
}
I also have an abstract, generic Handler type:
public abstract class Handler<T> {
public abstract <U extends Builder<T>> void handle(U builder);
}
and finally a FooHandler:
public class FooHandler extends Handler<Foo> {
#Override
public void handle(FooBuilder builder) {
// do something
}
}
The issue is that FooHandler's handle() is not recognized as overriding Handler's handle(): Method does not override method from its superclass. Is it possible to do this?
Move the type parameter to the class level
abstract class Handler<T, U extends Builder<T>> {
public abstract void handle(U builder);
}
class FooHandler extends Handler<Foo, FooBuilder> {
#Override
public void handle(FooBuilder builder) {
// do something
}
}

How to avoid the warning: return type requires unchecked conversion?

I have the following example:
class uncheckedreturn
{
static abstract class Abstract
{
abstract public <A extends Abstract> A make ();
}
static class Concrete extends Abstract
{
public Concrete make ()
{
return new Concrete();
}
}
public static void main (String[] args) {}
}
The Abstract class is requiring the definition of a make method and the Concrete class is extending the Abstract class and defining the make method. When I compile it, I get the following warning:
$ javac -Xlint:unchecked uncheckedreturn.java && java uncheckedreturn
uncheckedreturn.java:10: warning: [unchecked] make() in Concrete overrides <A>make() in Abstract
public Concrete make ()
^
return type requires unchecked conversion from Concrete to A
where A is a type-variable:
A extends Abstract declared in method <A>make()
1 warning
I do not understand which conversion takes place here and why it is unchecked. The abstract method make is specified for a type extending Abstract. And Concrete is exactly doing this: extending Abstract. So why is Concrete differing from A?
How to change the code to get rid of the warning?
Update
I think I am a step further in understanding what the problem in the code is. The generic abstract method make allows the following implementation with is obviously not what I want to allow:
class uncheckedreturn
{
static abstract class Abstract
{
abstract public <A extends Abstract> A make ();
}
static class Concrete extends Abstract
{
#Override
public OtherConcrete make ()
{
return new OtherConcrete();
}
}
static class OtherConcrete extends Abstract
{
#Override
public Concrete make ()
{
return new Concrete();
}
}
public static void main (String[] args) {}
}
Maybe there is no way to keep just the method generic.
As others have pointed out, the requirement hardly makes any sense (apart from looking like an attempt to emulate a clone() method).
Initially, you said that the return type of the make method should be "any" subtype of Abstract. This usually simply means to use covariant return types, like in this example:
class uncheckedreturn
{
static abstract class Abstract
{
abstract public Abstract make();
}
static class ConcreteA extends Abstract
{
#Override
public ConcreteA make()
{
return new ConcreteA();
}
}
static class ConcreteB extends Abstract
{
#Override
public ConcreteB make()
{
return new ConcreteB();
}
}
public static void main(String[] args)
{
ConcreteA a0 = new ConcreteA();
ConcreteA ma0 = a0.make();
ConcreteB b0 = new ConcreteB();
ConcreteB mb0 = b0.make();
}
// This is possible, but you'd like to not allow this
static class ConcreteC extends Abstract
{
#Override
public ConcreteA make()
{
return new ConcreteA();
}
}
}
As mentioned in the comment (and emphasized in your EDIT) this does not prevent a class from returning subtype of Abstract that is not its "own" type, and you made clear that you essentially are looking for a "this-type" that could allow you to write something like
class Concrete {
public <SameAsThis> make() {
return new Concrete();
}
}
but something like this does not exist in Java. It could, to some extent, be achieved with the Curiously recurring template pattern: You can specify a type parameter for the class that determines the return type of the method, and make sure that this type matches the class:
class uncheckedreturn
{
static abstract class Abstract<A extends Abstract<?>>
{
abstract public A make();
}
static class ConcreteA extends Abstract<ConcreteA>
{
#Override
public ConcreteA make()
{
return new ConcreteA();
}
}
static class ConcreteB extends Abstract<ConcreteB>
{
#Override
public ConcreteB make()
{
return new ConcreteB();
}
}
// // Now, this is no longer possible:
// static class ConcreteB extends Abstract<ConcreteB>
// {
// #Override
// public ConcreteA make()
// {
// return new ConcreteA();
// }
// }
// But this still IS possible, but may also not be desired...
static class ConcreteC extends Abstract<ConcreteA>
{
#Override
public ConcreteA make()
{
return new ConcreteA();
}
}
public static void main(String[] args)
{
ConcreteA a0 = new ConcreteA();
ConcreteA ma0 = a0.make();
ConcreteB b0 = new ConcreteB();
ConcreteB mb0 = b0.make();
}
}
But again, there is a case where the type of the class type parameter may be "wrong", which would allow it to implement the method with a "wrong" return type.
Additionally, you said that you'd like to "keep just the method generic", but there simply is no type information at this point. There are basically two things that can determine the compile-time type of a returned value:
The type of the object that the method is called on (including covariance)
The type parameters of a generic method
But neither of them can fulfill the requirements that you stated:
The return type, even if it is covariant, can be any subtype of the return type
The type parameters of the generic method can be equipped with lower bounds (like Abstract, in your case) but not with upper bounds or a concrete type
From a more high-level point of view, there may be alternatives for this method. It could be more appropriate to use a Factory here, once as Factory<ConcreteA> and once as Factory<ConcreteB> (or simply a Java 8 Supplier). But this depends on the overall goal and the intended usage of these classes.
It seems like you want the make method to be able to return an object of a type that varies in subclasses, so you should make a generic type parameter for that type, and the concrete implementation can apply the appropriate type argument for the type it makes:
static abstract class Abstract<A> {
abstract public A make();
}
static class Concrete extends Abstract<Concrete> {
public Concrete make() {
return new Concrete();
}
}

Java: How to return declared type in interface hierarchy?

I have an interface hierarchy similar to -
interface Type
{
Type copy();
};
interface SubType extends Type
{
};
interface SubSubType extends SubType
{
};
And a concrete class
public class Concrete implements SubSubType
{
#Override public Concrete copy() { return new Concrete(); }
}
I would like to be able to call copy() on a Type and get a Type back, call copy() on a SubType and get a SubType back, etc. Is this achievable? Possibly with generics?
Thanks in advance.
Like so:
public interface Type {
public Type copy();
}
public interface SubType extends Type {
public SubType copy();
}
public class Concrete implements Type {
#Override
public Concrete copy() {
return new Concrete();
}
}
public class SubConcrete implements SubType {
#Override
public SubConcrete copy() {
return new SubConcrete();
}
}
public static void main(String[] args) {
Type type = new Concrete();
SubType subType = new SubConcrete();
Type newType = type.copy();
SubType newSubType = subType.copy();
}
I think you could go
interface <T extends Type> Type {
T copy();
}
interface SubType extends Type<SubType> {
// any extra methods here
}
then, the implementations will be
public class Concrete implements SubType {
public SubType copy() {
// code here
}
}
For the record, calling the method copy() when it doesn't copy anything is a very bad idea.
EDIT: Corrected code below. For simplicity, the SubXXX interfaces are put in as inner classes, in practice this is unlikely to make sense. Obviously I needed to switch the order. Duh!
public interface Type<T extends Type<?>> {
T copy();
public interface SubType<T extends SubType<?>> extends Type<T> {
}
public interface SubSubType extends SubType<SubSubType> {
}
}
and, an implementation might look like:
class Concrete implements SubType<Concrete> {
#Override
public Concrete copy() {
return new Concrete();
}
}
This does look pretty messy, and I prefer (and just voted for) #Tim Pote answer.

Categories

Resources