Search code examples
javainterfaceabstractapi-design

How to force an implementation for an API Java


We had this question on API design. and its drilling a hole in my head and can't figure this one out.

say for example I have an interface with one method, to read a file but you need some sort of credentials passed, so the object here could be any pojo really.

public interface Reader(){
     public void read(String identifier, Object credentials);
}

The question was how do I force a developer if they extend this to implement the credentials, to make sure that it is valid credentials and not just bypass it. Here are my suggested solutions:

public boolean authenticate(Object credentials);

OR, it could be something like this

 public Object authenticate(Object credentials);

I also tried this way, so it gives a default authentication

public interface Auth {
    default boolean authenticate() {
        //do real authentication
        return true;
    }
}

and the response I would pass to the Reader interface, they came back to me saying the developer could always ignore this as well, and say just return true. and that all of this was wrong.

They hinted that the answer had to do with Abstract classes, but I was thinking if it was an abstract class, wouldn't it mean that if I had extended wouldn't mean I could still override this method? and say return true still?

abstract class Auth {
    public boolean authenticate(Object o) {
        //some real authentication
        return boolean ;
    }
}
//developer implementation
class extends AuthImpl extends Auth{
        public boolean authenticate(Object o){
            return true;
        }
}

It was a panel discussion, and they were all in agreement that there is a way so that the developer couldn't do just return true with abstracts. What am I missing here? How do I enforce that the developer does implement actual authentication properly rather than just returning true? please help can't seem to figure this one out


Solution

  • After giving it some thought and based on all the answers here, I think this is what they meant. Thanks to @Kayaman's answer for leading to the right direction.

    through abstract this is the way, since you have imposed that Reader have 1 parameter constructor he cannot instantiate it, and he is forced to put a super call in his implementation.

    abstract class Reader {
        protected Object authentication;
        ReaderImpl(Object authentication) throws Exception{
            if(null == authentication){
                throw new Exception();
            }else{
                this.authentication = authentication;
            }
        }
        public void reader(String x, Object authentication) {
            System.out.println("Reader Implemented");
        }
    
    }
    
    class DevReader extends Reader{
        public DevReader(Object authentication) throws Exception{
            super(authentication);
        }
        @Override
        public void reader(String x, Object authentication) {
            System.out.println("Dev Implemented");
        }
    }