CRTP and double inheritance - java

I have the following sets of classes:
public abstract class GSObject<T extends GSObject<T>> {
public abstract boolean matches(String toMatch);
//Other functions
public static <T extends GSObject<T>> T findMatch(List<T> objects, String toMatch){
//Code that iterates through the list, seeing if one matches;
}
}
public abstract class Phrase extends GSObject<Phrase> {
//More code
}
public class Request extends Phrase{
#Override
public boolean matches(String toMatch){
//Implementation of matches()
}
}
Running the following command: Request.findMatch(allRequests,chat); gives the following error:
Bound mismatch: The generic method findMatch(List<T>, String) of type GSObject<T> is not applicable for the arguments (List<Request>, String). The inferred type Request is not a valid substitute for the bounded parameter <T extends GSObject<T>>
If I do Phrase.findMatch(allPhrases, chat); it does not throw an error, meaning that this has to do with double inheritance. Do I have to write another static function that works with a Class that extends a Class that extends GSObject?
I've looked into making GSObject an interface, but it has some classes that I would like to define (not abstractly) in the class.
Is there something I am missing (in any of the three classes), or do I need to create an interface that defines the function matches() (What I am trying to avoid)?

One option is to make Phrase generic in the same way that GSObject is:
public abstract class Phrase<T extends Phrase> extends GSObject<T> {
public class Request extends Phrase<Request> {
This way, Request extends GSObject<Request> (unlike in your code, where Request extends GSObject<Phrase>).
Another option might be to decouple some of these dependent types by using wildcards, e.g. by one of these:
public static <T extends GSObject<T>> T findMatch(List<? extends T> objects, String toMatch){
public static <U extends GSObject<?>> U findMatch(List<U> objects, String toMatch){
though this can be tricky to get right. Note that with this approach, Request will still advertise that it can handle any List<? extends Phrase>, so you lose some of the benefit of the static type system. (In other words, these versions make your classes more permissive than they're really supposed to be.)
A third option is to do both of the above. It does make sense, after all, for Request.findMatch to take a List<? extends Request>.
Without seeing more of your code, it's hard to know which of these makes most sense for your case.

Related

Java - Get instance of each subclass

I have an abstract class Command. The constructor looks like this:
public Command(String cmd, String helpMsg, String... args) {
this.command = cmd;
this.helpMsg = helpMsg;
this.args = args;
}
Whenever a certain condition is met, I want to be able to print out each command, it's help message and arguments.
If I could loop through the instances of the subclasses of Command, I could call the getter functions for these attributes. However, I don't know how I could store instances like this. I've been reading about generics but haven't been able to solve this problem yet.
Right now I have another class with this code:
private static Map<Class<? extends Command>, ? extends Command> instances;
public static <T extends Command> void addInstance(Class<T> tClass, T tInstance) {
instances.put(tClass, tInstance);
}
But it gives me this error:
Required type:
capture of ? extends Command
Provided:
T
It would also be nice if I were able to get instances to individual subclasses with getInstance(subclass.class)
If you want to ensure that the class and object are of the same type, you’re going to need to make your own mapping class which enforces that, or use an existing one like Guava’s ClassToInstanceMap.
If it’s sufficient for you to simply put and get a Command instance out of your map given a class, then I’d recommend simply dropping the second wildcard:
private static Map<Class<? extends Command>, Command> instances;
There are a lot of great existing answers which explain the behavior of the extends wildcard and why you’re getting the warning that you are when attempting to insert one of your command instances. I definitely recommend giving them a read: Difference between <? super T> and <? extends T> in Java
This can be achieved by creating special kind of Map where keys type is bound to values type:
public class BoundMap<T> extends HashMap<Class<? extends T>, T> {
}
Then the code becomes:
private static BoundMap<Command> instances;
public static <T extends Command> void addInstance(Class<T> tClass, T tInstance) {
instances.put(tClass, tInstance);
}

Java parameterize class warning

I want to parametirize class with two other params, so that I can provide one of them independently, AdGroupIdentifier OR KeywordIdentifier. But I am getting following warning: The type parameter KeywordIdentifier is hiding the type KeywordIdentifier.
Do you think I am doing something wrong? What is a correct way of doing that?
Thanks for any help!
public class Metrics <T extends AdGroupIdentifier, KeywordIdentifier> {
public void addMetric(T identifier){ .... }
}
It seems that you have class named KeywordIdentifier. The class parameter named KeywordIdentifier does not relate to class with the same name but can confuse humans. This is exactly what the compilation warning mean.
BTW according to naming convention you should tend to call type parameter using one (or maximum 2) capital letter. In your case change the class definition to
public class Metrics <T extends AdGroupIdentifier, K>
or, if you want the seconds parameter to extend class KeywordIdentifier:
public class Metrics <T extends AdGroupIdentifier, K extends KeywordIdentifier>
Just remove the KeywordIdentifier. It seems that AdGroupIdentifier implements or extends KeywordIdentifier:
public class Metrics <T extends AdGroupIdentifier> {
public void addMetric(T identifier){ .... }
}
Normally generic types are given one letter names as they are parameterized.
The way you have it, you might confuse KeywordIndetifier which extends Object with your class KeywordIdentifer and while they have the same name, they are not related.

Intertwined java generic interfaces and classes

I have a very specific problem with java generics. The follwowing classes and interfaces have been predefined:
public interface IFirst<R, T> {...}
public abstract class AbstractFirst<T extends AbstractFirst, L extends IFirst<String, T>> {...}
public interface ISecond extends IFirst<String, AbstractSecond> {...}
public abstract class AbstractSecond extends AbstractFirst<AbstractSecond, ISecond> {...}
Now I've created a following repo definition which seems to be valid:
public abstract class AbstractRepo<T extends AbstractFirst<T, IFirst<String,T>>> {...}
But now that i want to extend it:
public class RepoFirst extends AbstractRepo<AbstractSecond> {...}
I get the following error:
Bound mismatch: The type AbstractSecond is not a valid substitute for the bounded parameter
<T extends AbstractFirst<T,IFirst<String,T>>> of the type AbstractRepo<T>
I cannot change the first four (at least not radically) beacuse they are too heavily ingrained with the rest of the application, but the second two are new and up for change if need be.
Also intrestingly it allows the following (with raw type warnings):
public class RepoFirst extends AbstractRepo {
...
#Override
AbstractFirst someAbstractMethod() {
return new AbstractSecond() {...};
}
...
}
But for code clarity I would like to implement it with clearly defining AbstractSecond as the generic type for Abstract Repo.
What am I missing?
Your AbstractRepo expects an instance of IFirst and not a subtype of IFirst. But your AbstractSecond is clearly not IFirst. (I mean it is, from a OO standpoint but for generics, List<Number> is not the same as List<Integer>). It's ISecond. It might work if you could change your AbstractRepo from IFirst to ? extends IFirst as you did for AbstractFirst.

Java Generic of Another generic

I have interface:
interface Identifable<T extends Serializable> {
T getID();
}
and class that implement this:
public class Cat implements Identifable<Long> {
public Long getID(){...};
}
everything works fine. so far. Now I want to create GenericDAO, why I cannot create this?:
public abstract GenericDAO<T extends Identifable<S>> {
T getByID(S id);
}
I can only declare my GenericDAO as this:
public abstract GenericDAO<T extends Identifable, S> {
T getById(S id);
}
And complete class:
public CatDAO extends GenericDAO<Cat, Long> {
Cat getById(Long id);
}
But i think it's useless, because I repeat information. I already declared, that Cat implements Identifable< Long >, so why do I must declare GenericDAO< Cat, Long >, not just GenericDAO< Cat > ?
In Java, every generic type must be specified. You can go without specifying any type, but you can't go without specifying just one.
Also, every generic type must be specified in the declaration. If you want to have class GenericDAO<T extends Identifable<U>>, you must add the generic type declaration for U to your class declaration like this (since U is actually a generic type here):
public abstract class GenericDAO<T extends Identifable<U>, U>
The following is partially off-topic, but you might find it useful.
I've noticed that in your definition of GenericDAO two generic types are not tied to each other. This might not be what you want.
What you have here is a particular case in which the two generics are matching (the Long type in the Cat and CatDAO definitions). Consider having these declarations:
public class Dog implements Identifable<Long>
public class DogDAO extends GenericDao<Dog, String>
This would force you to write the getById method in DogDAO method:
Dog getById(String id);
Your getId method in the Dog returns a Long so your getById method int DogDAO would have to compare Strings to Longs. This is valid thing to do, but it's a bit counter-intuitive. Having a getById method for DogDAO that takes a Long parameter makes more sense, since the Dogs IDs are actually Longs.
If you want to tie the two types together, you can define the GenericDAO class as:
public abstract class GenericDAO<T extends Identifable<S>, S>
You still have to specify the second parameter, but at least the compiler can help you make sure that the types are matching.
Try this:
public abstract class GenericDAO<S extends Serializable, T extends Identifable<S>> {
abstract T getByID(S id);
}

Bound mismatch with Java Generics "nesting"

I'm having difficulty using generics for a redesign/refactoring I'm doing on an existing design.
public interface DataDto {
// some data here
}
public interface SetDto<MyDataDto extends DataDto> {
List<MyDataDto> getData();
}
public interface Results<MySetDto extends SetDto<DataDto>> {
MySetDto getResults();
}
public interface MyProblemInterface<MyDataDto extends DataDto,
MySetDto extends SetDto<MyDataDto>,
MyResults extends Results<MySetDto>> {
// some stuff here
}
My problem is that I get the following error for MyProblemInterface:
Bound mismatch: The type MySetDto is not a valid substitute for the
bounded parameter <MySetDto extends SetDto<DataDto>> of the type
Results<MySetDto>
I admit my experience with generics is somewhat limited, but basically I'm trying to enforce that all three of the types in MyProblemInterface are the same "type". For example, if I have ADataDto, BDataDto, ASetDto<ADataDto>, BSetDto<BDataDto>, AResults<ASetDto>, BResults<BSetDto>, I want to ensure a class can't implement MyProblemInterface in a manner like AMyProblemInterface<ADataDto, ASetDto, BResults>. I would think that since MySetDto extends SetDto<MyDataDto> just fine, I could continue to take that further, but I'm apparently wrong.
Thank you for any help.
You want too much from Java generics.
It would be simpler to declare your interface as following:
public interface MyProblemInterface<MyDataDto extends DataDto>
And then force method to use SetDto<MyDataDto> and Results<MySetDto>.
By using generics in class/interface declaration you specify some kind of variety which is determined later in definition. But in your case you said that SetDto and Results will always have MyDataDto as parameter, so there is no variety.
Shouldn't it be something like this instead, and you add the actual classes only when implementing the interfaces.
Updated the code, because I forgot to add the right Results definition. This should work.
public interface DataDto {
// some data here
}
public interface SetDto<T extends DataDto> {
List<T> getData();
}
public interface Results<T extends SetDto<? extends DataDto>> {
T getResults();
}
public interface MyProblemInterface<T extends DataDto, E extends SetDto<T>, K extends Results<E>> {
// some stuff here
}

Categories

Resources