Generic Method Type Safety - java

I have the concept of NodeTypes and Nodes. A NodeType is a bunch of meta-data which you can create Node instances from (a lot like the whole Class / Object relationship).
I have various NodeType implementations and various Node implementations.
In my AbstractNodeType (top level for NodeTypes) I have ab abstract createInstance() method that will, once implemented by the subclass, creates the correct Node instance:
public abstract class AbstractNodeType {
// ..
public abstract <T extends AbstractNode> T createInstance();
}
In my NodeType implementations I implement the method like this:
public class ThingType {
// ..
public Thing createInstance() {
return new Thing(/* .. */);
}
}
// FYI
public class Thing extends AbstractNode { /* .. */ }
This is all well and good, but public Thing createInstance() creates a warning about type safety. Specifically:
Type safety: The return type Thing for
createInstance() from the type
ThingType needs unchecked conversion
to conform to T from the type
AbstractNodeType
What am I doing wrong to cause such a warning?
How can I re-factor my code to fix this?
#SuppressWarnings("unchecked") is not good, I wish to fix this by coding it correctly, not ignoring the problem!

You can just replace <T extends AbstractNode> T with AbstractNode thanks to the magic of covariant returns. Java 5 added support, but it didn't receive the pub it deserved.

Two ways:
(a) Don't use generics. It's probably not necessary in this case. (Although that depends on the code you havn't shown.)
(b) Generify AbstractNodeType as follows:
public abstract class AbstractNodeType<T extends AbstractNode> {
public abstract T createInstance();
}
public class ThingType<Thing> {
public Thing createInstance() {
return new Thing(...);
}
}

Something like that should work:
interface Node{
}
interface NodeType<T extends Node>{
T createInstance();
}
class Thing implements Node{}
class ThingType implements NodeType<Thing>{
public Thing createInstance() {
return new Thing();
}
}
class UberThing extends Thing{}
class UberThingType extends ThingType{
#Override
public UberThing createInstance() {
return new UberThing();
}
}

Related

Why cast is needed when returning this from self-bound generic in Java

In this case my IDE shows compilation error in return statement.
public class Base<T extends Base>{
public T get(){
return this;
}
}
When I add a typecast as in code bellow everything works fine, however I don't get why typecast is needed.
public class Base<T extends Base>{
public T get(){
return (T) this;
}
}
Doesn't Java replace all bounded generic occurrences with bounded type? Can someone explain what is going on under the hood and why typecast is needed?
Edit 1.
Thanks to Lothars and algrid answers it is now clear that this standalone case can cause ClassCastException. This is not safe so Base should probably be abstract.
The intent of this is to create a base class for Builder classes so that extended methods would return the type of the extending class. This is needed for method chaining. In the example bellow the return type of child.setParamOne(1) will be Child despite the fact that it is defined above in the inheritance hierarchy.
Is this code safe? Do you have any suggestions or alternatives for approaching this problem?
public abstract class Base<T extends Base>{
int paramOne;
public T setParamOne(int param){
this.paramOne = param;
return (T) this;
}
}
public final class Child extends Base<Child> {
int paramTwo;
public Child setParamTwo(int param){
this.paramTwo = param;
return this;
}
}
public static void main(String[] args) {
Child c = new Child()
.setParamOne(1)
.setParamTwo(1);
}
Why do you think that your this is of the type T? It's of the type Base<T>.
Try to run the following code and you'll get ClassCastException:
public class Main {
public static void main(String[] args) {
Base<Child> b = new Base<>();
// b.get() returns an instance of Base, not Child (however it's mistakenly cast to Child)
Child1 c = b.get();
}
public static class Base<T extends Base>{
public T get(){
return (T) this;
}
}
public static class Child extends Base {
}
}
The reason for this error is the same as the error being created for code like this:
public void myMethod(InputStream is) {
ByteArrayInputStream bais = is;
}
Just with generics. To get rid of the complier error you can do the cast as you did in your code:
public void myMethod(InputStream is) {
ByteArrayInputStream bais = (ByteArrayInputStream) is;
}
But this will fail during runtime if the passed inputstream is not a ByteArrayInputStream or a class derived from it. The same will happen with your code. Unless you only create instances of Base<Base> the cast will lead to an error when calling get.
In your example:
public class Base<T extends Base>{
public T get(){
return this;
}
}
the return statement is incorrect, because this is an instance of Base<T> and not T.
If your aim is to return the instance itself (by the way, I'm not sure why you would be doing this), the code should look like this:
public class Base<T extends Base>{
public Base<T> get(){
return this;
}
}
If your aim is to return the parameterized type, then you will probably not be able to do that. The parameterized type itself is not an instance within the Base class, but, again, just the parameterized type. If that is what you need, you can get the parameterized type class using reflection.
The conversion is unsafe because this (which has type Base<T>) may not be a T. We only know that T is a Base, but not the other way around.
There is no way to represent a "self type" in Java. So what you want to do is impossible. Instead, you can make an abstract method that forces implementing subclasses to provide a way to return a T:
public class Base<T> {
public abstract T get();
}
public final class Child extends Base<Child> {
public Child get() {
return this;
}
}

Subclasses with generics of subclasses

I have some issues with generics. I have a BaseObject with multiple sub-classes as well as a BaseContainer<T extends BaseObject> with sub-classes that correspond with BaseObject sub-classes.
public class TestClass extends BaseClass<BaseContainer<BaseObject>> {
// method signature tied to BaseClass generic
#Override
private BaseContainer<BaseObject> createContainer() {
BaseContainer<BaseObject> container;
// example logic here to determine which container to use
if (Math.random() < 0.5) {
container = new Parent1Container(); // incompatible types
} else {
container = new Parent2Container(); // incompatible types
}
return container;
}
abstract static class BaseObject {}
static class Parent1Object extends BaseObject {}
static class Parent2Object extends BaseObject {}
abstract static class BaseContainer<T extends BaseObject> {
public abstract void foo(T object);
}
static class Parent1Container extends BaseContainer<Parent1Object> {
public void foo(Parent1Object object) {}
}
static class Parent2Container extends BaseContainer<Parent2Object> {
public void foo(Parent2Object object) {}
}
}
public class BaseClass<T extends BaseContainer> {
public abstract T createContainer();
}
I have a method that returns BaseContainer<BaseObject>. Unfortunately, instantiating sub-classes of BaseContainer results in incompatible types error.
I have tried adding casts to the container instantiation, but it leaves ugly unchecked warnings that make me feel like I'm just missing something. I'd like to avoid those and suppress warnings.
If possible, how can I re-write the any of the classes to make the createContainer() method work?
As written here,
Neither List<Number> nor List<Integer> is a subtype of the other, even though Integer is a subtype of Number. So, any method that takes List<Number> as a parameter does not accept an argument of List<Integer>. If it did, it would be possible to insert a Number that is not an Integer into it, which violates type safety.
Since BaseClass is in a library and you cannot modify it, this case cannot be handled cleanly, i.e. as you expected.
Since Parent1Container and Parent2Container are not exactly BaseContainer<BaseObject> but BaseContainer<? extends BaseObject>
you need to change the signatures accordingly:
public class TestClass extends BaseClass<BaseContainer<? extends BaseObject>> {
...
public BaseContainer<? extends BaseObject> createConstructor() {
if (Math.random() < 0.5) {
return new Parent1Container();
} else {
return new Parent2Container();
}
}
...
}
BaseContainer<BaseObject> makes reference to all those BaseContainer (including extending classes) instances that are able to "handle" any BaseObject, where handle is a blanket-term for all the operations it may do with that type-argument.
In contrast BaseContainer<? extends BaseObject> refer to those BaseContainer instances that are meant to handle a subset of all BaseObject where the top parent class is unknown (thus the ?). It that ? happens to be BaseObject then these two sets would be equivalent.
If your case ? can be either Parent1Object or Parent2Object and so you cannot do better than just leave it as ?.

Force a generic type to be an interface?

It looks like this is impossible to do, but does anyone have a clever way around this problem?
public class SomeClassIterableWrapper<S, T extends SomeClass & S> implements Iterable<S>
Where S is supposed to be an interface of some unknown type and SomeClass is a 2D array with a row index, similar in functionality to a bidirectional JDBC resultset. Subclasses of SomeClass have custom getters and setters for each column. I want to be able to iterate through this structure like I would a List. I want to implement a common interface between my SomeClass and Bean to have access to the getters and setters. As such S needs to be that interface. However the declaration I provided does not work. Is there a way to work around this?
edit to show my desired implementation:
public class SomeClassIterableWrapper<S, T extends SomeClass & S> implements Iterable<S>{
T object;
public SomeClassWrapper(T object){
this.object = object;
}
#Override
public Iterator<S> iterator() {
object.setIndex(-1);
return new SomeClassIterator<S>();
}
private class SomeClassIterator<S> implements Iterator<S> {
#Override
public boolean hasNext() {
return object.index() < object.rowSize() - 1;
}
#Override
public S next() {
object.next();
//safe because only interface methods allowed, can't further manipulate index
return object;
}
#Override
public void remove() {
object.deleteRow();
}
}
Can't you parameterize SomeClass with S? Then you could have
public class SomeClassIterableWrapper<S, T extends SomeClass<S>>
implements Iterable<S>{
I think the S in extends SomeClass & S
public class SomeClassIterableWrapper
has to be a definite class because in this context,
S has to be a class that is extending something.
Is there a way you can narrow down what the
potential classes that are used in place of S are?
You could use multiple ampersands if you have multiple
classes that T should extend
I confess that I don't fully comprehend the problem but this is what I suggest:
Create an interface of S. It contains one method ad it returns the S object.
public interface SWrapper<S> {
S getS();
}
Then create an implementation:
public class SImpl implements SWrapper<SImpl> {
#Override
public SImpl getS() {
return this;
}
}
You can now create:
public class SomeClass<T extends SomeClass & SWrapper<T>> {
private final T object;
public SomeClass(T object) {
this.object = object;
}
}
You will have to modify your usage a bit but perhaps it works.

Is it possible declare and implement a method once, but vary the return type to match subinterfaces in a robust manner?

First off, I want to say there is no use case for this. The only thing I am trying to do is explore if this is possible.
What I am trying to do is "rebrand" the return signature of a method in the base interface to that of a child interface.
The goal: declare and implement a method once, but vary the return type to match subinterfaces. I have figured out how to achieve this in some cases, but it breaks down in certain situations.
Imagine if I have base interface B and it has a method B doWork(). Also, there is an implementation of B that implements doWork(). Due to the nature of doWork(), this implementation should be the only one that exists.
Now, this is pretty easy to do with Generics. For the above example:
interface B<T extends B> {
T doWork();
}
class BImpl<T extends B> implements B<T> {
#Override
public T doWork() { return something; }
}
And the child interface/impl would look like this maybe:
interface C extends B<C> {
void somethingCSpecific();
}
class CImpl extends BImpl<C> implements C {
#Override
public void somethingCSpecific() { }
}
Anyone constructing CImpl would see that doWork() returns a C.
C obj = new CImpl().doWork() // The money shot. No casting needed.
And here is where it breaks down... Imagine B now looks like this:
public interface B<T extends B> {
T thisOrThat(T that);
boolean something();
}
And I want to do this in BImpl:
class BImpl<T extends B> implements B<T> {
#Override
public T thisOrThat(T that) {
if (that.something())
return that;
return this; // Error!! _this_ might be a different T than _that_.
}
#Override
public boolean something() { return whatever; }
}
Note where the error happens.
Obviously, this can't work without an unsafe and dubious cast. But if I knew that the implementation of this in the above thisOrThat method was the same as the implementation of that, everything would be ok.
So, to my question. Is there a way to restrict this and that to the same type, without knowing that type a priori?
Or maybe is there a different way to go about doing this, but having the same result? Namely only having to declare AND implement thisOrThat() just once, yet have the return type adapt to the subinterface?
Thanks.
Make your class BImpl abstract and add a view method to it which is implemented by the specific classes extending your abstract base class:
public abstract class BImpl<T extends B<T>> implements B<T> {
#Override
public T thisOrThat(T that) {
if (that.something())
return that;
return this.asT();
}
#Override
public boolean something() {
// TODO Auto-generated method stub
return false;
}
protected abstract T asT();
}
Every of your classes still needs to implement T asT() then, but this is simple and compiles without warning:
public class C extends BImpl<C> implements B<C> {
#Override
protected C asT() {
return this;
}
}
If I understand your problem correctly, then the way to solve it is with a sort of self-referential generic: B<T extends B<T>>.
I think what you want is class BImpl implements B<BImpl>, in which case everything type checks normally.

Returning an objects subclass with generics

With an abstract class I want to define a method that returns "this" for the subclasses:
public abstract class Foo {
...
public <T extends Foo> T eat(String eatCake) {
...
return this;
}
}
public class CakeEater extends Foo {}
I want to be able to do things like:
CakeEater phil = new CakeEater();
phil.eat("wacky cake").eat("chocolate cake").eat("banana bread");
Arguably banana bread would throw an IllegalArgumentException with the message "Not a cake!"
public abstract class Foo<T extends Foo<T>> // see ColinD's comment
{
public T eat(String eatCake)
{
return (T)this;
}
}
public class CakeEater extends Foo<CakeEater>
{
public void f(){}
}
Edit
There is no problem to require subclass behave in a certain way that's beyond what static typing can check. We do that all the time - pages and pages of plain english to specify how you write a subclass.
The other proposed solution, with covariant return type, must do the same - asking subclass implementers, in plain english, to return the type of this. That requirement cannot be specified by static typing.
The tasteful approach from the client point of view (which is usually the one you want to take) is to use covariant return types which was added to support generics, as Michael Barker points out.
The slightly less tasteful, but more tasteful that a cast is to add a getThis method:
public abstract class Foo<T extends Foo<T>> {
protected abstract T getThis();
public T eat(String eatCake) {
...
return getThis();
}
}
public class CakeEater extends Foo<CakeEater> {
#Override protected CakeEater getThis() {
return this;
}
}
I don't think you need generics Java 5 (and later) has covariant return types, e.g.:
public abstract class Foo {
...
public Foo eat(String eatCake) {
...
return this;
}
}
public class CakeEater extends Foo {
public CakeEater eat(String eatCake) {
return this;
}
}
An approach I've used before to achieve similar behaviour is to have the subclass pass its type into a constructor of the (generified) parent type. By way of disclaimer I was generating the subclasses on the fly and inheritence was a bit of a cheat to keep my code generation simple, as always my first instinct is to try to remove the extends relationship altogether.

Categories