Java - Bounds on class public API - java

I have a ModelDecorator helper. I want it to have the following public API
class ModelDecorator<T>{
public static <T> ModelDecorator<T> create(Class<T> clazz);
public <SUPER> T from(SUPER fromInstance);
}
So, given classes A, B extends A, it can be used like this:
A a = new A();
B b = ModelDecorator.create(B.class).from(a);
But I want to have bounds on T and SUPER, so I make sure that only subclases can be instantiated using the API. At this moment, I can do:
C c = new C();
B b = ModelDecorator.create(B.class).from(c);
Where B DOES not inherit from C.
Any ideas? Thanks

The only way I see for constraining your type parameter T to extend the type parameter S is to put those definitions into the class definition:
public class ModelDecorator<S, T extends S> {
public static <S, T extends S> ModelDecorator<S, T> create(Class<T> clazz) { ... }
public T from(S instance) { ... }
}
With these classes
class A {}
class B extends A {}
class C {}
you now can write the following code:
A a = new A();
B b1 = ModelDecorator.<A, B> create(B.class).from(a); // compiles fine
C c = new C();
B b2 = ModelDecorator.<C, B> create(B.class).from(c); // bound mismatch here
The second B creation now has a compiler error.
Unfortunately you now must explicitely provide the type parameters because the compiler is not able to infer the type A or C from a simple method call create(B.class).

Related

How is it possible that a method with generic return type with a bound can be assigned to a variable outside of that bound?

Suppose I have the following structure:
public interface A {
}
public interface B {
}
public interface B1 extends B {
}
public interface B2 extends B {
}
public class C implements A, B1 {
private final String s;
public C(final String s) {
this.s = s;
}
}
public class D implements A, B2 {
private final Exception e;
public D(final Exception e) {
this.e = e;
}
}
public class SomeClass<T> {
private final T t;
private final Exception e;
public SomeClass(final T t, final Exception e) {
this.t = t;
this.e = e;
}
public <U extends B> U transform(final java.util.function.Function<T, ? extends U> mapper1, final java.util.function.Function<Exception, ? extends U> mapper2) {
return t == null ? mapper2.apply(e) : mapper1.apply(t);
}
}
When now we do the following in another class:
public class AnotherClass {
public static void main(final String[] args) {
SomeClass<String> someClass = new SomeClass<>("Hello World!", null);
// this line is what is bothering me
A mappedResult = someClass.transform(C::new, D::new);
}
}
The code compiles without any problems. Why does the code compile? How is it possible that the type of 'mappedResult' can be A, even though the generic U in the method is declared to be a subtype of B?
Ok, so based on the comments on the question and some discussion with other people, there was a major point that I missed that might need addressing and that actually explains the answer given in the comments.
It's clear that the following compiles:
Object mappedResult = someClass.transform(C::new, D::new);
And yet Object is not a subclass of B, of course. The bound will ensure that the the types of C and D (in this case) will be a subtype of B, but they can be other types as well due thanks to other interfaces both C and D implement. The compiler will check what types they are and look at the most specific type(s) that they have in common. In this case, that is both A and B, so the type is derived to be A & B. Therefore, assigning this result to A is possible, because the compiler will derive the result to be an A as well.
The bound does provide some restrictions regarding the input, but not regarding the output and not regarding to the types of variables to which you can assign the result. That is what I was confused about before.
Another way to see this is the following: if the method had been defined as follows:
public <U> U transform(final java.util.function.Function<T, ? extends U> mapper1, final java.util.function.Function<Exception, ? extends U> mapper2) {
return t == null ? mapper2.apply(e) : mapper1.apply(t);
}
then the result can still be assigned to an A or a B when calling it as before. The bound had no influence on that. All it ensures here is that both mapper functions need to map to a result that is a subtype of U. With the bound, that becomes a subtype of U which is a subtype of B. But the fact that the result is a subtype of A doesn't change the fact that it is also a subtype of B. Therefore, the result can be assigned to either type.

class contains one element of subclasses

Giving the diagram below, I want to know the following:
How to make sure that a class car can have a GPS of type A or B not both?
Because of the max multiplicity of 1, all your example diagram is missing is a generalization set that is {complete, disjoint}. Your diagram now says {incomplete, overlapping}, by default, which means an instance can be a member of both A and B, or just a member of GPS.
What about using generics like this:
public class A<T extends B> {
List<T> list = new ArrayList<>();
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
}
public class B {
}
public class C extends B {
}
public class D extends B {
}
Then you will instantiate class A with the desired subtype of B like this:
A<C> a = new A<>();
C c = new C();
D d = new D();
a.getList().add(c); //works fine
a.getList().add(d); //compile error
Taking the fruit basket from your comment, you need to specify a multiplicity for 0..n instead of the 1.
If you want all instances to be the same subclass you need to add a constraint in any way. If your tool does not permit it, just add a note with { all instances ofBmust have the same type } or the like.

Call generic method with interface constraints on objects who may implement that interface

This is my code:
interface a {}
class b{}
class c extends b implements a{}
class d extends b{}
class e{
public void makeItWork(){
b[] bees = new b[] {new c(), new d()};
for (b bee: bees){
if (bee instanceof a) {
a beeA = (a) bee;
//how to call the method test if object bee conforms the the interface?
test(beeA.getClass(), beeA);
//this goes wrong
}
}
}
public <T extends a> void test(Class<T> classType, T concrete){
}
}
Besides maybe the bad design, I would like to know if it is possible to call the method test on objects who implements the interface a.
your test method doesn't need a generic type parameter.
You can define it as:
public void test(Class<? extends a> classType, a concrete) {
}
P.S. please use capitalized class names.
You can actually get away without using generics at all here:
public void test(a concrete) {
}

Classcast exception for inherited classes

I have a class structure like this:
Interface A extends X
Class A_Impl implements A
Interface B extends A
Class B_Impl extends A_Impl implements B
My webservice client returns object of A and I need some parameters from B. So I do is this:
A myA = (A) webservice.getA();
B myB = (B) myA;
But this always throws the ClassCast exception:
java.lang.ClassCastException: A_Impl cannot be cast to B
Am I doing something wrong here ? How can I get some params from B class.
If you have a reference to an object that doesn't implement B, there is no way to cast it to a B. Full stop.
Imagine if it was possible. Then what would this print?
interface A {
int getNumberOfLives();
}
interface B extends A {
boolean isOrange();
}
class A_Impl implements A {
int getNumberOfLives() {return 9;}
}
public class Main {
public static void main(String[] args) {
A a = getA();
B b = (B)a;
System.out.println(b.isOrange() ? "Is orange" : "Is not orange");
}
static A getA() {return new A_Impl();}
}
You cannot get any properties of B when you have an instance of B's supertype A, or any subtype of that other than B. For example, if you wanted to get the value of a field x that is a member of B, but your object is only an A, the field is not even present in the object. So what would the value of it be? That is the reason you can't cast in this direction. If you wan't to access the object like an instance of B, you have to change your webservice.getA() to something that actually returns a B (or a B_Impl)

How to transfer bounded parameter using method super()

I have three classes: abstract A and two B and C which extends the A.
class A<T> {
ArrayList<T> someField;
A() {
someField = new ArrayList<T>();
}
ArrayList<T> getSomeField() { return someField; }
}
Now I have B and C
class B<T> extends A {
B() {
super();
}
}
class C<T> extends A{
C() {
super();
}
}
When I try to use getSomeField which is different type for B and C I have to specify which type it is. And my question is how to transfer the T parameter from B class to A to avoid specify the type of ArrayList using for example for each loop. If it is possible at all.
Example:
I wish:
B obj = new B<T>();
for (T item: B.getSomeField) {
do something
}
I have to:
B obj = new B<T>();
for (T item: (ArrayList<T>)B.getSomefield) {
do something
}
With your B and C definitions, you are extending the raw form of class A and creating each class's own T generic type parameter. The raw for of class A means that type erasure occurs on all generic in that class, and the casting becomes necessary.
You need to specify that your subclass's T is the same as the superclass's T:
class B<T> extends A<T> {
and
class C<T> extends A<T> {

Categories