Search code examples
javaspringtapestry

Tapestry5 compiling error returning service interface in service locator method


I have a service locator class called DMSServiceLocator.class, I have a method within it called getParser() with a return type called Parser. I'm trying to return a service called AutoMateParser with an Impl that extends Parser, however I'm getting a compiling error saying Parser is required, found AutoMateParser. When I return new AutoMateServiceImpl() rather than my service interface, I receive no compiling errors. It doesn't appear my getParser() method realizes autoMateParser is of the same type. I tried casting AutoMateParser with Parser, "return (Parser) autoMateParser;" which resolved compiling errors, but received a cast exception. I'm wondering if anybody knows how to do this. Thanks in advance.

below is a sample of my code.

AppModule.class

public static void bind(ServiceBinder binder) {
        binder.bind(AutoMateParser.class, AutoMateParserImpl.class);
}

DMSServiceLocator.class

public class DMSServiceLocator {

    @Inject
    private AutoMateParser autoMateParser;

    public Parser getParser() {
        if(automate) {
        return autoMateParser();
        } else {
           //Different data scrubber, but also extends Parser
           return homenetParser();
        }
    }

}

AutoMateParserImpl.class

public class AutoMateParserImpl extends Parser implements AutoMateParser {
    protected Vehicle parseCar(String vehicleData) {
        //some data scrubbing code
    }
}

Parser.class

public abstract class Parser {
    //some csv line reader code
    protected abstract Vehicle parseCar(String carData);
}

Solution

  • You are trying to return an object of type AutoMateParser. That interface is not a sub-type of Parser (only AutoMateParserImpl is), hence the compiler complains. You'll need to re-think your class hierarchy.

    You could extract a Parser interface with the parseCar method, have AutoMateParser extend that interface, create an abstract ParserImpl class implementing the Parser interface, and have your service locator return the Parser interface type instead of the abstract implementation.

    Edit: The types could look something like this:

    public interface Parser {
       //public methods that you need to call
    }
    
    public interface AutoMateParser extends Parser {
        //any extra or overriden method declarations
    }
    
    public abstract class AbstractParser implements Parser {
        //common code and implemented methods
        protected abstract Vehicle parseCar(String carData);
    }
    
    public class AutoMateParserImpl extends AbstractParser implements AutoMateParser {
        //any extra or overriden method implementations defined in AutoMateParser
        protected Vehicle parseCar(String vehicleData) {
            ...
        }
    }
    
    public class DMSServiceLocator {
    
        @Inject
        private AutoMateParser autoMateParser;
        //more services
    
        public Parser getParser() {
            if(automate) {
               return autoMateParser();
            } else {
               //Different data scrubber, but also extends Parser
               return homenetParser();
            }
        }
    
    }