3

I have some classes that look like this:

MODEL

public abstract class BaseEntity<O extends Object> { ... }

public class Person extends BaseEntity<Person> { ... }

COMMAND

public abstract class BaseCommand<BE extends BaseEntity<BE>> { ... }

public class PersonCommand extends BaseCommand<Person> { ... }

SERVICE

public interface BaseService<BE extends BaseEntity<BE>> {
    public BE create(BaseCommand<BE> command);
}

public interface PersonService extends BaseService<Person> { ... }

SERVICE IMPL

public abstract class BaseServiceImpl<BE extends BaseEntity<BE>> implements BaseService<BE> { }

public class PersonServiceImpl extends BaseServiceImpl<Person> implements PersonService {
    public Person create(PersonCommand personCommand) { ... }
}

The PersonServiceImpl class won't compile. It's not recognizing that the create() method is implementing the create() method from the BaseService interface. Can anyone tell why PersonCommand isn't being recognized as a BaseCommand<BE> (in the parameter list)?

6
  • I don't understand why you're parametrizing the class with itself... public class Person extends BaseEntity<Person> { ... } Commented Aug 10, 2011 at 1:59
  • they don't have the same return type maybe? Commented Aug 10, 2011 at 1:59
  • Basically I do it so that methods in BaseEntity can refer to the type. public BE method(); etc Commented Aug 10, 2011 at 2:01
  • The return type is correct. When I use Eclipse to override/implement, it uses Person as the return and it works correctly. It won't accept PersonCommand instead of BaseCommand<Person>. Commented Aug 10, 2011 at 2:02
  • @Rachel: Correct, it shouldn't accept a PersonCommand instead of BaseCommand<Person>. (See my answer for more details. :-)) Commented Aug 10, 2011 at 2:03

1 Answer 1

7

When overriding, method parameters are not covariant (that is, subclasses have to accept a type that the superclass also accepts, not anything narrower).

This is because people can use your PersonServiceImpl via the PersonService interface, which will accept an argument of type BaseCommand<Person> that is not necessarily a PersonCommand (imagine if you created a second class that extended BaseCommand<Person>).

If you make your method take a parameter of type BaseCommand<Person>, your code should compile correctly.

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

2 Comments

Makes sense. The BaseServiceImpl class is forcing you to accept all BaseCommand<Person> objects. Thanks for the help. +1 for a good explanation and example.
Won't let me accept for 4 minutes apparently, but I will. Thanks again.

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.