Java Interface with Inheritance - java

I'm looking for assistance on how to implement this Repository. Here's what I have so far:
public interface IEntity {
int getId(); //would rather not depend on int. fix later.
}
public interface IRepository<T extends IEntity> {
Collection<T> findAll();
T find(T t);
T findById(int id); //would rather not depend on int. fix later.
void add(T t);
void remove(T t);
}
public interface ISurveyRepository extends IRepository<Survey> {
}
The problem I'm running into is that I need for T in the IRepository signature to extend IEntity, but I don't need IRepository in the ISurveyRepository signature to have a bounded type parameter. I would like for the signature to just be
public interface ISurveyRepository extends IRepository { }
so that I could create a concrete class that just implements ISurveyRepository
public class MySurveyRepository extends ISurveyRepository { }
How can I go about doing that?

You can do better than this.
Fix that int problem now. Use a generic DAO interface, like this:
public interface Repository<T, K extends Serializable> {
List<T> find();
T find(K id);
K save(T value);
void update(T value);
void delete(T value);
}
Lose that Hungarian notation in disguise: no "I" for "interface".
You can write a generic implementation, too.

If you want to create a class like:
public class MySurveyRepository extends ISurveyRepository {}
Then your existing interface (with the use of generics) will do just fine. Your implementing class will 'inherit' the definition by design, and will be (effecticely) completely unaware that it's descended from a previously-generic interface.
If you're using one of the modern editors, like Eclipse, to write your code, when you ask it to fill in the missing inherited methods it won't give you T - it'll give you Survey.

Related

Nested Parameterized types in interface

I have following interfaces:
CacheKey interface:
public interface CacheKey<K extends Serializable> extends Serializable {
K get();
}
CacheValue interface:
public interface CacheValue<V extends Serializable> extends Serializable {
V get();
}
Cache interface:
public interface Cache<CacheKey<K extends Serializable>, CacheValue<V extends Serializable>> {
}
Cache interface doesn't compile. Error I get is:
[13,35] > expected
i.e. after CacheKey compiler doesn't like another opening angle bracket:
public interface Cache<CacheKey<
^
Is this not possible in Java?
You're missing a crucial step here : the implementation.
It's usually in the implementation that you want to define what the type of ? extends Serializable will be. You don't need to implement this in the Cache interface.
The interface only needs to know what its generics types will be, not the generics of their child : this is for the implementation.
Take a look at the example here below to understand what I exactly mean by that.
Addition : When your define something like Cache<CacheKey, CacheValue> you're not referring to the classes, but you're creation a generic alias. CacheKey could easily be replaced by Blabla and continue to have the same behaviour. The solution is to use extends to make sure we're talking about the type.
This was also the reason why Cache<CacheKey<...>> did not compile, because CacheKey is not referring to the class but is used as an alias
public interface CacheKey<K extends Serializable> extends Serializable {
K get();
}
public interface CacheValue<V extends Serializable> extends Serializable {
V get();
}
public interface Cache<K extends CacheKey<? extends Serializable>, V extends CacheValue<? extends Serializable>> {
void put(K key, V value);
}
public class CacheImpl implements Cache<CacheKey<String>, CacheValue<String>> {
#Override
public void put(CacheKey<String> key, CacheValue<String> value) {
// do whatever
}
}
Using a wildcard-bounded generic type, as suggested in other answers, isn't a great idea.
If you declare your class like this:
public interface Cache<K extends CacheKey<?>, V extends CacheValue<?>> {
}
then you would never be able to usefully invoke get() on the key or value, because they would only ever return Serializable. And Serializable is a useless class (it's barely different to Object actually inside your code).
Instead, I would simply declare the class like:
public interface Cache<K extends Serializable, V extends Serializable> {
and then declare that the put method takes a CacheKey<K> and a CacheValue<V>:
void put(CacheKey<K> key, CacheValue<V> value);
because, ultimately, all implementations of CacheKey<K> and CacheValue<V> should be indistinguishable.
If you really want to force the CacheKey<K> and CacheValue<V> to be of specific types, you need to add more type variables:
public interface Cache<
K extends Serializable, CK extends CacheKey<K>,
V extends Serializable, CV extends CacheValue<V>> {
void put(CK key, CV value);
}
but this is really quite gross, as you would have to carry around all of these 4 type variables wherever you use a Cache type directly.
Of course, you can specialize the interface to hide some of these type variables:
interface StringKey extends CacheKey<String> {}
interface IntegerValue extends CacheValue<Integer> {}
interface StringIntegerCache extends Cache<String, StringKey, Integer, IntegerValue> {}
and then just use StringIntegerCache. The usefulness of doing so depends on your application.

Confused with Spring Data JPA and generic types

Tables:
StudentHistory 1--->n Student
TeacherHistory 1--->n Teacher
I try to regroup the JPA behaviour of History because they do the same thing (retrieve the students/teacher from a given history for example).
Entities with generic types:
// Entities
public abstract class AbstractHistory <T> {}
public class StudentHistory extends AbstractHistory<Student> {}
public class TeacherHistory extends AbstractHistory<Teacher> {}
Repositories with genric types:
// repositories
public interface IHistoryRepository<T> extends CrudRepository<AbstractHistory<T>, Long> {
public AbstractHistory<T> findFirst();
}
public interface StudentHistoryRepository extends IHistoryRepository<Student> {}
public interface TeacherHistoryRepository extends IHistoryRepository<Teacher> {}
I though I could do:
StudentHistory stuHisto = new StudentHistoryRepository().findFirst();
But I get this error:
// err -> Type mismatch: cannot convert from AbstractHistory<Student> to StudentHistory
1/ Why can't I retrieve a 'StudentHistory' from my 'StudentHistoryRepository' ?
2/ How should I deal whith that?
You have this problem because your method explicitly returns an AbstractHistory and not the subtype.
You would need to cast...
... if only your repository implementation understood that each T you get a specific history.
You may try adding another type but I fear that it'll fail:
public interface IHistoryRepository<
T,
H extends AbstractHistory<T>
> extends CrudRepository<H, Long> {
public H findFirst();
}
public interface StudentHistoryRepository extends IHistoryRepository<Student, StudentHistory> {}
public interface TeacherHistoryRepository extends IHistoryRepository<Teacher, TeacherHistory> {}
I don't know what framework you are using, probably Spring Data from the names; while I had used it in the past, I don't know if it is able to do that.
After all, it needs to get the concrete class and since it is generics, type erasure may interfere (if the information about the concrete type representing H is lost in reflection then Spring Data won't probably be able to do much here, unless you help it with an annotation or something else).
Another solution that should work is to do that per each child interface instead:
public interface StudentHistoryRepository extends CrudRepository<StudentHistory, Long> {
StudentHistory findFirst();
}
Or with another interface:
public interface FindFirst<T> {
T findFirst();
}
public interface StudentHistoryRepository extends CrudRepository<StudentHistory, Long>, FindFirst<StudentHistory> {}

Generic function names in java 8

I have few entities in my app and I want to have a functionality where I can generically set few properties on them when user tries to save them.
For this, I have attempted writing a utility class as follows:
public class IrisUserUtil<T> {
IrisUserRepository irisUserRepository;
public IrisUserUtil(IrisUserRepository irisUserRepository){
this.irisUserRepository = irisUserRepository;
}
public <S extends T> S populate(S entity) {
//IrisUser irisuser = irisUserRepository.findOne(entity.getIrisUserId());
//entity.setFirstName(irisuser.getFirstName());
//entity.setLastName(irisuser.getLastName());
return entity;
}
}
This I will call just before my repository.save() ; Here I am looking for correct way to call functions like entity.getIrisUserId() etc on the passed parameter that is "entity". Of course, this is not working.
please suggest why?
maybe with <S extends Entity> and not T what is T here ?
How the compilater know that S is something extending the Entity class (or an other base class) ?
public <S extends T> S populate(S entity)
In your code S and T are somethings extending Object, the compilater can't known your methods getIrisUserId(), getFirstName() etc...
I think you have to remove your generic T in the class and just do
public <S extends Entity> S populate(S entity)
or (but useless and more complicated)
public class IrisUserUtil<T extends Entity> {
and
public <S extends T> S populate(S entity)
or in a simple way no need to use generic types just do (but you have to cast the returned entity with the concrete type)
public Entity populate(Entity entity) {
...
return entity;
}
in my example Entity is your entities abstract base class

Java - Factory and Strategy Patterns with Generics

I'm trying to implement a Strategy + Factory pattern using generics. The goal is to return to a client class an implementation of the interface DocumentDao that can deal with a type T extends Document, so I've multiple Dao interface extending DocumentDao for different subtypes of Document.
Here is my code:
public class Document { ... }
public class DocumentA extends Document { ... }
public class DocumentB extends Document { ... }
public interface DocumentDao<T extends Document> {
public void update(T document);
}
public interface DocumentADao<DocumentA> {}
public interface DocumentDaoFactory {
public <T extends Document> DocumentDao<T> getDaoInstance(Class<T> clazz);
}
Then I try to use the Factory:
private <T extends Document> void someMethod(T document) {
...
DocumentDao<T> documentDao = this.documentDaoFactory.getDaoInstance(document.getClass());
documentDao.update(document);
...
}
But the compiler complaints about the getDaoInstance() call:
Type mismatch: cannot convert from DocumentDao<? extends AbstractGDriveDocument<?>> to DocumentDao<T>
How to deal with this situation?
How can I obtain a similar solution?
Thanks
The problem is that getClass is returning a Class<?>, which is appropriate for the API; it would not know what specific Class instance to bring back. Additionally, your type bound is incorrect and invalid in your method.
To fix this, you would need to change two things:
In your DocumentDaoFactory method, change the bound to be appropriate.
<T extends Document> DocumentDao<T> getDaoInstance(Class<T> clazz);
In your use of getDaoInstance, perform an unchecked cast to Class<T>.
DocumentDao<T> documentDao = this.documentDaoFactory.getDaoInstance((Class<T>) document.getClass());
The way that your types are bound should give you back the instances you care about, without getting any runtime errors.

How to define generics return in an interface?

My implementation looks like this.
#Override
public <T extends AlgorithmSuperType> T doSomethingSmart(){
//do this and that
}
How could I define the interface for this generic return value? Eclipse recommends this interface definition.
T doSomethingSmart();
When I accept the quick fix, Eclipse finds fault with it and recommends to prepend <T>.
<T> T doSomethingSmart();
None of these quick fixes of the interface resolve the conflict in the #Override implementation.
Any clue how to properly define the interface?
The interface would look something like this:
interface YourInterfaceName {
<T extends AlgorithmSuperType> T doSomethingSmart();
}
That defines an interface with a generic method, which is what your implementation defines.
Since T is a generic parameter, you need to declare it as a parameter, by making either the method or your class to be generic. Eclipse is suggesting the first alternative. Here's how to do the second:
public class<T extends AlgorithmSuperType> MyClass implements SomeInterface<T> {
#Override
public T doSomethingSmart(){
//do this and that
}
}
Note that the interface should be either
public interface<T extends AlgorithmSuperType> SomeInterface {
T doSomethingSmart();
}
or
public interface SomeInterface {
<T extends AlgorithmSuperType> T doSomethingSmart();
}
(In the latter, case, MyClass should be "implements SomeInterface" rather than implements SomeInterface<T>.
If it's interface then you could use:
AlgorithmSuperType fetchAlert();
But all other classes inheriting from this type will also be ok, not justT.

Categories