A way to create matched pairs of generic classes without warnings? - java

I wonder if there is a way to eliminate the rawtypes warning when I use generic classes that refer to each other:
public class DummyDeleteMe {
abstract class RightSide<L extends LeftSide>{ //Can I use a type parameter here?
L getLeftSide() {return _mate;}
void setLeftSide(L mate) {_mate = mate;}
L _mate;
void connectToMate(){
getLeftSide().setRightSide(this);//warning:
/** [unchecked] unchecked call to setRightSide(R) as a member of the raw type DummyDeleteMe.LeftSide
where R is a type-variable: * **/
}
}
abstract class LeftSide<R extends RightSide>{// And here?
R getRightSide(){return _mate;}
void setRightSide(R mate) {_mate = mate;}
R _mate;
}
class RightSideSub extends RightSide<LeftSideSub>{
void connectToMate(){
getLeftSide().setRightSide(this);//No warning
}
}
class LeftSideSub extends LeftSide<RightSideSub>{}
}
The compiler warning is because the LeftSide in the parameter bound is a raw type. Replacing it with LeftSide<?> causes an error in connectToMate. Overriding connectToMate in RightSideSub, the same code does not generate a warning.
I guess I'm looking for some kind of second type parameter, that is self referential:
abstract class RightSide<R extends RightSide<R,L>, L extends LeftSide<L,R>>{}
But that causes other type mis-match errors in the R variables and methods that return R.

I know this may not be exactly what you are looking for, but it may solve your problem. Based only on what you've shown in your code sample, there is no need for a generic at all. It's over complicating the issue. That is, if your example is a fairly close match for what you need.
Assuming it is, how about something like this.
public interface Half{
public Half getOtherHalf();
}
public class RightSide implements Half{
private LeftSide leftSide;
public void setLeftSide(LeftSide leftSide){
this.leftSide = leftSide;
}
#Override
public LeftSide getOtherHalf() {
return leftSide;
}
}
public class LeftSide implements Half{
private RightSide rightSide;
public void setRightSide(RightSide rightSide){
this.rightSide = rightSide;
}
#Override
public RightSide getOtherHalf(){
return rightSide;
}
}

Here is one solution. I have removed references to L for "left side" and R for "right side" and replaced them with T for "this side" and O for "other side"
public class Solution1 {
abstract static class Side<T extends Side<T, O>, O extends Side<O, T>> {
Side<O, T> _mate = null;
Side<O, T> getOtherSide() {
return _mate;
}
void setOtherSide(Side<O, T> mate) {
_mate = mate;
}
void connectToMate() {
getOtherSide().setOtherSide(this);
}
}
//You concrete implementations can replace This and Other
//with Right and Left as you see fit.
static class RightSideSub extends Side<RightSideSub, LeftSideSub> {
}
static class LeftSideSub extends Side<LeftSideSub, RightSideSub> {
}
}
However, I would suggest another, simpler solution at the cost of loosing connectToMate() method and replacing it with code in main() method below:
class OtherSolution{
abstract static class Side<O>{
O _mate = null;
void setOtherSide(O mate){
_mate = mate;
}
}
static class RightSideSub extends Side<LeftSideSub> {
}
static class LeftSideSub extends Side<RightSideSub> {
}
public static void main(String[] args) {
RightSideSub rs = new RightSideSub();
LeftSideSub ls = new LeftSideSub();
//do the connectToMate() operation externally like this:
rs.setOtherSide(ls);
ls.setOtherSide(rs);
}
}

Related

How to structure code to prevent incompatible capture of ? extends _?

I was wondering what is the best way to structure code to ensure compiler knows in very simple cases that passed variable is of correct type. I have created very simple code where class O has its execute method execute that accepts some kind of payload (that extends class P) and performs some kind of operation. The thing is that I do not know how to structure my code to ensure that compiler knows what kind of specific payload I am passing to execute method.
First thing that came to my mind was to introduce method that would return classType of used payload just to came to realization that it is of no use because I am trying to pass some potentially different type of payload to execute method that accepts specific payload.
By the end of the day I could just use reflection but I was wondering how to solve this kind of problem without the use of reflection - whether there is some kind of pattern to solve this problem or some other way to structure my code,...
I know that this kind of simple in terms of printing payload can be solved by introducing method that would print desired payload,... but let's say that I would like to do something more than just printing to console.
Thanks in advance!
import java.util.List;
class Scratch {
public static abstract class O<I extends P> {
public abstract void execute(I payload);
}
public static class O1 extends O<P1> {
#Override
public void execute(P1 payload) {
System.out.println(payload.a);
}
}
public static class O2 extends O<P2> {
#Override
public void execute(P2 payload) {
System.out.println(payload.b);
}
}
public static abstract class P {
abstract Class<? extends P> getClassType();
}
public static class P1 extends P {
public String a = "a";
#Override
Class<? extends P> getClassType() {
return P1.class;
}
}
public static class P2 extends P {
public Integer b = 1;
#Override
Class<? extends P> getClassType() {
return P2.class;
}
}
public static void main(String[] args) {
List<O<? extends P>> os = List.of(new O1(), new O2());
List<P> ps = List.of(new P1(), new P2());
for (int i = 0; i < 2; i++) {
var p = ps.get(i);
// this line would prevent compilation
os.get(i).execute(p);
// this line would also prevent compilation
os.get(i).execute(p.getClassType().cast(p));
}
}
}
The problem with your current code is that you have a list of "any Os" and a list of "any Ps" that aren't related in any way as far as the compiler is concerned. You seem to want to tell the compiler, that actually, os.get(i).execute accepts the same type as ps.get(i) for any valid index i.
To do that, you need to create another class that "groups" an O and a P together, then you can create one list containing these groups:
public static class OPGroup<PType extends P> {
private final O<? super PType> o;
private final PType p;
public OPGroup(O<? super PType> o, PType p) {
this.o = o;
this.p = p;
}
public O<? super PType> getO() {
return o;
}
public PType getP() {
return p;
}
}
List<OPGroup<?>> ops = List.of(
new OPGroup<>(new O1(), new P1()),
new OPGroup<>(new O2(), new P2())
);
for (int i = 0; i < 2; i++) {
var op = ops.get(i);
execute(op);
}
where execute can just be a static method declared anywhere you like:
// you can also make this an instance method of "OPGroup"
public static <PType extends P> void execute(OPGroup<PType> group) {
group.getO().execute(group.getP());
}
The purpose of this is to capture the wildcard in OPGroup<?>.
Anyway, if you can't introduce a new class for some reason, then your code is inherently unsafe. The contents of the lists can be literally any P and any O, so os.get(i).execute(p); could very well fail. If you are willing to accept that, you can do an unsafe (unchecked) cast:
((O<? super P>)os.get(i)).execute(p);

How to get a class instance of type Foo<T> (Foo<T>.class not work) [duplicate]

This question already has answers here:
Java: how do I get a class literal from a generic type?
(8 answers)
Closed 4 years ago.
I would like to get the class of Foo< T >.class (exactly Foo < T>, neither T.class nor Foo.class)
public class A extends B<C<D>>{
public A() {
super(C<D>.class); // not work
}
}
On StackOverflow has a instruction for obtaining generic class by injecting into constructor but it's not my case because C< D>.class (e.g List<
String>.class) is syntax error. At here it seems relate to syntax more than code structure.
To show more detail, higher level view, the original code is the following, its HATEOAS module in Spring framework:
public class CustomerGroupResourceAssembler extends ResourceAssemblerSupport<CustomerGroup, CustomerGroupResource>{
public CustomerGroupResourceAssembler() {
super(CustomerGroupController.class, CustomerGroupResource.class);
}
}
public class CustomerGroupResource extends ResourceSupport {
private CustomerGroup data;
}
But now I want to parameterize the CustomerGroupResource to
public class Resource<T> extends ResourceSupport {
private T data;
}
and then
public class CustomerGroupResourceAssembler extends ResourceAssemblerSupport<CustomerGroup, Resource<CustomerGroup>>{
public CustomerGroupResourceAssembler() {
super(CustomerGroupController.class, Resource<CustomerGroup>.class); // not work here, even Resource.class
}
}
Unfortunately what you are trying to do is impossible due to type erasure.
Information about generic types is only avalilable at compile time and not at run time. This is one of biggest limitations of using generics in Java. The reason why it was done like this is to preserve backwards compatibility.
See Java generics type erasure: when and what happens?
Due to type erasure, the generic only applies at compile time and doesn't mean anything at runtime. What you can do is
public class A extends B<C<D>>{
public A() {
super((Class<C<D>>) C.class);
}
}
However, you won't be able to determine the type of D at runtime. You can use reflection to get the super type however.
public class Main {
public static abstract class B<X> {
protected B() {
Type type = getClass().getGenericSuperclass();
System.out.println(type);
}
}
public static class A extends B<Supplier<String>> {
public A() {
}
}
public static void main(String[] args) {
new A();
}
}
prints
Main.Main$B<java.util.function.Supplier<java.lang.String>>
EDIT For your specific example you can do.
import java.lang.reflect.Type;
public interface Main {
class ResourceSupport {
}
class CustomerGroup {
}
public class Resource<T> extends ResourceSupport {
private T data;
}
abstract class ResourceAssemblerSupport<C, R> {
protected ResourceAssemblerSupport() {
Type type = getClass().getGenericSuperclass();
System.out.println(type);
ParameterizedType pt = (ParameterizedType) type;
Type[] actualTypeArguments = pt.getActualTypeArguments();
Class first = (Class) actualTypeArguments[0];
ParameterizedType second = (ParameterizedType) actualTypeArguments[1];
System.out.println(pt.getRawType() + " <" + first + ", " + second + ">");
}
}
public class CustomerGroupResourceAssembler extends ResourceAssemblerSupport<CustomerGroup, Resource<CustomerGroup>>{
public CustomerGroupResourceAssembler() {
}
}
public static void main(String[] args) {
new CustomerGroupResourceAssembler();
}
}
prints
Main.Main$ResourceAssemblerSupport<Main$CustomerGroup, Main.Main$Resource<Main$CustomerGroup>>
class Main$ResourceAssemblerSupport <class Main$CustomerGroup, Main.Main$Resource<Main$CustomerGroup>>
A generic way to do what you want is to use a helper function, however I think this isn't needed in your case.
public static void main(String[] args) {
System.out.println(new ClassType<List<String>>() {}.getType());
}
interface ClassType<T> {
default Type getType() {
ParameterizedType type = (ParameterizedType) getClass().getGenericInterfaces()[0];
return type.getActualTypeArguments()[0];
}
}
prints
java.util.List<java.lang.String>

Java Inheritance without casting

public class BinaryVertex {
public BinaryVertex parent,left,right;
}
public class BSTVertex extends BinaryVertex {
public void foo() {
left = new BSTVertex();
if(Math.floor(Math.random()*2) == 0) left.foo();
}
}
I'm making a tree / graph api for school, approaching it from a oop standpoint. But im trying to figure out a way for the inherited class to treat some of its base class variables as its own type (i.e. parent,left,right should be treated as BSTVertex when called from BSTVertex but treated as BinaryVertex when called from BinaryVertex) without casting.
I'm thinking of generics but I'm not sure how to implement that in this situation.
UPDATE
Nice, didnt know you could use extend in generics. But I'm getting a BSTVertex<T> cannot be converted to T error with this:
public class Test {
public static void main(String[] args) {
new AVLVertex();
BSTVertex<BSTVertex> v = new BSTVertex<BSTVertex>();
v.foo();
}
class BinaryVertex<T extends BinaryVertex> {
public T parent, left, right;
}
class BSTVertex<T extends BSTVertex> extends BinaryVertex<T> {
public T foo() {
return this; //error here
}
}
class AVLVertex extends BSTVertex<AVLVertex> {
// this might probably end up being abstract too
}
foo needs to return a vertex of the same type as caller, i.e. if AVLVertex calls foo its expecting to get AVLVertex not BSTVertex
Yes, you can use generics like this:
public class BinaryVertex<T extends BinaryVertex<T>> {
public T parent, left, right;
}
public class BSTVertex extends BinaryVertex<BSTVertex> {
public void foo() {
left = new BSTVertex();
if(Math.floor(Math.random()*2) == 0) left.foo();
}
}
The same way the Comparable interface implemented, so subclasses receive the same type to compareTo method. For example, Integer implements Comparable<Integer>, so its compareTo method receives Integer argument.
Also please note the it would be better to create your own random number generator like this:
public class BSTVertex extends BinaryVertex<BSTVertex> {
private static final Random r = new Random();
public void foo() {
left = new BSTVertex();
if(r.nextBoolean()) left.foo();
}
}
UPDATE
In your updated code (in future please ask new question instead) you cannot safely cast, because you can potentially write later:
class RBVertex extends BSTVertex<RBVertex>{}
class AVLVertex extends BSTVertex<RBVertex>{}
This is ok from the compiler's point of view, but your AVLVertex generic argument is actually not an AVLVertex. That's why you have a compilation error in foo() method: your class can be later possibly extended in the way that would make your T incompatible with this.
You can fix this problem by doing an unchecked cast:
#SuppressWarnings("unchecked")
public T foo() {
return (T) this;
}
In this way if you mistakenly create class AVLVertex extends BSTVertex<RBVertex>{}, it will still compile, but upon calling AVLVertex.foo() you may have a runtime ClassCastException.

Java Generics and unchecked cast

I'm struggling with this aspect of Generics in Java. Hopefully someone can help me see the ways.
I have a class that holds a List of objects. This code works, but I want to get rid of the cast. How can I make this more generic?
public class Executor {
List<BaseRequest<BaseObj>> mRequests = new ArrayList<BaseRequest<BaseObj>>();
public Executor() {
}
#SuppressWarnings("unchecked")
public <T extends BaseObj> void add(final BaseRequest<T> request) {
mRequests.add((BaseRequest<BaseObj>) request);
}
public void execute() {
for (BaseRequest<BaseObj> r : mRequests) {
// DO SOMETHING WITH r
}
}
}
In the posted snippet you need the cast because BaseRequest<? extends BaseObj> is not a subtype of BaseRequest<BaseObj>, and the cast can't be checked at runtime because of type erasure, and that's why the compiler warns you. But if you change the declaration of mRequests:
public class Executor {
List<BaseRequest<? extends BaseObj>> mRequests = new ArrayList<>();
public Executor() {
}
public <T extends BaseObj> void add(final BaseRequest<T> request) {
mRequests.add(request);
}
public void execute() {
for (BaseRequest<? extends BaseObj> r : mRequests) {
// DO SOMETHING WITH r
}
}
}
class BaseRequest<T> {}
class BaseObj {}
Let's resolve the problem step-by-step. You want to be able to call
req.add(new BaseRequest<ExtObj1>());
req.add(new BaseRequest<ExtObj2>());
req.add(new BaseRequest<ExtObj3>());
where ExtObj[1|2|3] extends BaseObj. Given the List interface:
List<T> {
void add(T el);
}
we need to find a common supertype for BaseRequest<ExtObj1>, BaseRequest<ExtObj2> and BaseRequest<ExtObj3>. One supertype is BaseRequest<?> and another one is BaseRequest<? extends BaseObj>. I picked the second one because it's the most restrictive possible. You should know that in Java BaseRequest<ExtObj1> is not a subtype of BaseRequest<BaseObj> because generics are invariant.
Now that we have the right declaration for mRequests, finding the API for Executor.add() is straightforward. BTW, if the method body you need is really that simple, you don't even need the type parameter:
public void add(BaseRequest<? extends BaseObj> request) {
mRequests.add(request);
}
Warnings are not errors. Warnings are there so you check if you have an error because it may not be checked automatically. You should check it and then use the annotation to note that warning was already checked.
In your case it warns BaseRequest<T> is not equivalent to BaseRequest<BaseObj>.
Example:
public class NumberWrapper<N extends Number> {
private N value;
public void setValue(N value) {
this.value = value;
}
}
public class MainClazz {
private NumberWrapper<Integer> wrappedNumber = new NumberWrapper<Integer>();
public void run() {
Number n = externalSource.getNumber();
wrappedNumber.setValue(n); // <-- Error. What if getNumber returns a double?
}
}
You can have this error ir not depending on how you complete/integrate the code you are showing.

How does Subclassing for Lists work?

I asked a similiar question 10 minutes ago, but pasted the wrong code snippet. I'm really sorry about that.
I'm currently facing an issue with base and subclasses.
While having a single object as parameter (method single) the compiler doesn't complain.
But if it comes to lists the compiler forces me to declare the list as <? extends Base>
After that I'm no longer allowed to add objects of the base type to that list.
The error message: "The method list(List<Generics.Base>) in the type Generics.C is not applicable for the arguments (List<Generics.Sub>)"
public class Generics {
class Base { }
class Sub extends Base{ }
interface I {
public void list( List<Base> list );
public void single( Base list );
}
class C implements I {
public void list( List<Base> b) { }
public void single( Base p) { }
}
void test() {
C c = new C();
c.single( new Sub() );
List<Sub> b = new ArrayList<Sub>();
c.list( b ); // error message as above
}
public static void main( String[] args) {
Generics g = new Generics();
g.test();
}
}
Is there any other way but declaring the list-methods argument as type <? extends Base> ?
Below are the 2 ways to do it....
public void list(List<? extends Base> list){
}
Or
public <T extends Base> void list(List<T> list){
}

Categories

Resources