TechFanDan
TechFanDan

Reputation: 3482

Cannot implement inherited abstract method

The idea is from the SSO class invoke the method login with an instance of MyCredentials. The end results is that MyCredentials will be available in MyAuthentication.

Issue: MyAuthentication creates an error due to the interface expecting an instance of Credentials where I'm attempting to send an instance of MyCredentials. I'm not quite sure what to do at this point.

There are currently several implementation of interface Authentication. I cannot change it. Am I doomed?

public class Credentials{
     public Credentials(){
          ...   
     }
}

public class MyCredentials extends Credentials{

    public MyCredentials(){
         super();
         //extend Credentials here
    }
}

public interface Authentication{
    public User createUser(Credentials c){
        ...
    }
}

public class MyAuthentication implements Authentication{

    public User createUser(MyCredentials c){
        ...
    }
}

public class Context{

    ...

    //This was there already
    public login(String login, String password){
        Manager.get(new Credentials(login, password));
            //at some point, interacts with MyAuthentication
    }

    //I added this
    public login(MyCredentials c){
        Manager.get(c);
            //at some point, interacts with MyAuthentication
    }
}

public class SSO{
     Context ctx;

    public do(){
        MyCredentials c = new MyCredentials();
        ctx.login(c);       
    }
}

Update #1

What happens when an implementation has to deal with both Credentials and MyCredentials?

Should I follow the same as what I did with the Context class and duplicate the method with the different class? Or is there a better way?

public interface Manager<T extends Credentials> {

    Repository get(T credentials) throws RepositoryException;
}

public class LocalManager implements Manager {
    public Repository get(final Credentials credentials) throws Exception {
            AuthenticatedUser user = userAuthenticator.authenticate(credentials);
            return new RepositoryImpl(commonRepository, user);
        }

    //Add this new method?
    public Repository get(final MyCredentials credentials) throws Exception {
            AuthenticatedUser user = userAuthenticator.authenticate(credentials);
            return new RepositoryImpl(commonRepository, user);
        }

}

Update #2

Even with the two methods with different signatures, it's always the method with Credentials that fires....

Upvotes: 1

Views: 172

Answers (2)

bischoje
bischoje

Reputation: 197

You're not doomed. The interface looks fine.

I think what you need to do is change the implementation of MyAuthentication. You need a method in there that overrides the method in the interface (with the same exact signature). For example:

public class MyAuthentication implements Authentication{

    public User createUser(Credentials c)
    {
      if(c instancof MyCredentials)
      {
        MyCredentials myCredentials = (MyCredentials)c;
        createUser(myCredentials);
      }
      else
      {
        throw new RuntimeException("This implementation only handles Credentials of type MyCredentials");
      }
    }

    public User createUser(MyCredentials c){
        ...
    }
}

Upvotes: 1

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279930

Harness the power of generics

interface Authentication<T extends Credentials> {
    public User createUser(T c);
}


class MyAuthentication implements Authentication<MyCredentials> {

    @Override
    public User createUser(MyCredentials c) {
        // ...
    }
}

The type parameter T can be Credentials or any of its sub types. Your implementations will specify one of these. as a type argument.

Upvotes: 4

Related Questions