Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generic type not working in this case

This class displays informations:

// display line numbers from a file 
display(getLineNumber(myFile));

// display users from DB
display(getUsersName(myDBRepository));

etc...

I wanted to make a generic interface, so I can externalize the code that display information.

Then I could do something like:

myInformationElements.stream().forEach(e -> display(e.getValue());

Here is what I have so far (not working):

public interface InformationElement {
    public <T> String getValue (T param);
}


public class NbFileLineInformationElement implements InformationElement{
    @Override
    public <File> String getValue(File param) {
          return *same code as in getLineNumber(myFile)*;
    }
}

public class UserInformationElement implements InformationElement{
      @Override
      public <UserRepository> String getValue(UserRepository param) {
         return *same code as in getUsersName(myDBRepository)*;
   }
}
  1. Here my generic type is not working: File is not reconize as java.io.File (same for my jpa repository) What am I doing wrong here ?
  2. Is this the best practice for my needs ?
like image 555
Tyvain Avatar asked Oct 17 '22 13:10

Tyvain


1 Answers

  1. You've defined type parameters File and UserRepository that are shadowing the class names File and UserRepository. This is one of the surprises of naming type parameters the same as existing classes. The type parameters don't represent the classes, and they don't have bounds, so the compiler can only assume they have Object methods.

  2. This is not the best practice. When implementing generic methods, the methods must remain generic and at least as wide-open with respect to bounds. To be able to restrict what the type parameter means later, define it on the class/interface, and let subclasses supply what it's supposed to mean for that specific implementation with a type argument.

The best solution here is to move InformationElement's type parameter to the class, and to supply type arguments in your subclasses. The methods are no longer generic, but they do use the type parameters defined on the interface/classes.

interface InformationElement<T> {
    public String getValue (T param);
}

class NbFileLineInformationElement implements InformationElement<File>{
    @Override
    public String getValue(File param) {
          return /*same code as in getLineNumber(myFile)*/;
    }
}

class UserInformationElement implements InformationElement<UserRepository>{
      @Override
      public String getValue(UserRepository param) {
         return /*same code as in getUsersName(myDBRepository)*/;
   }
}
like image 191
rgettman Avatar answered Nov 15 '22 04:11

rgettman