1

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....

3
  • Why did you modify the signature of createUser to take a MyCredentials type instead of the base type? Commented Dec 5, 2013 at 20:58
  • @MadConan because I'm a noob at Java and I needed to pass more data contained in MyCredentials. To my knowledge, that was the way. Commented Dec 5, 2013 at 21:01
  • That isn't necessary. Because MyCredentials extends Credentials it IS a Credentials type. Generics is the way to go (see Sotirios's answer), but you can also just check the type within the method so you don't have to change the signature. Commented Dec 5, 2013 at 21:04

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Eclipse has stopped complaining... need to compile and test now.
just wondering if you could comment on my update. Essentially, an implementation needs to deal with the two types of Credentials... is there a better way than copying the existing method and simply changing the parameter to MyCredentials?
@TekiusFanatikus I'll take a look when I get home.
I'll create another question as it's a different problem than this, and this has been resolved already.
I actually figured everything out. And was also able to revert my code back to its original state. Everything works now, by simply doing Credentials c = new MyCredentials()...
1

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){
        ...
    }
}

2 Comments

+1, but generic approach as suggested by @SotiriosDelimanolis is preferable.
Yes, but the OP said he could not change the interface. The generic approach suggested would be changing the interface. I think the generic interface presented is nice, but the original one can be worked with just fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.