Generics class cast in Java - java

Hi I have very similar classes (Cars, Clients, Reservations). In those classes i have the same functions like ( add, delete, getItem, getAll and sort).
public class Clients {
List<Client> persons = new ArrayList<Client>();
public void add (Client k) {
persons.add(k);
}
public void delete (Client k) {
persons.remove(k);
}
public Client getKlienet(int id) {
for ( Client k: persons) {
if ( k.getId() == id)
return k;
}
return null;
}
public List<Client> getAllClients() {
List<Client> temp = new ArrayList<Client>();
temp.addAll(persons);
return temp;
}
public List<Client> sortujKontakty() {
Collections.sort(persons);
return persons;
}
I'd like to do with these classes one generic class. But i have a lot of problems..
First with function getId() (this function simply returns value of Id), and with sort() method. Compareto() methods are different for other classes.
So, i done interface:
public interface ManagerInterface <T> {
public void add (T t );
public void delete ( T t);
public T getRecord(int id);
public List<T> getAll();
public List<T> sort();
}
And class:
public class RecordManager<T> implements RecordManagerInterface <T> {
private T id;
public T getId() {
return id;
}
public ArrayList<T> record = new ArrayList<T>();
#Override
public void add(T t) {
record.add(t);
}
#Override
public void delete(T t) {
record.remove(t);
}
#Override
public T getRecord(int id) {
for ( T k: record) {
if ( ((Client) k).getId() == id)
return k;
else if ( ((Person) k).getId() == id)
return k;
else if ( ((Reservation) k).getId() == id)
return k;
}
return null;
}
#Override
public List<T> getAll() {
List<T> temp = new ArrayList<T>();
temp.addAll( record);
return temp;
}
#Override
public List<T> sort() {
Collections.sort(record);
return record;
}
Please for any help.

if you have similar classes, try to create common interface for them,
ie
interface HasId {
int getId();
}
then all what you need is make your classes to implement it, and change your RecordManager to be
public class RecordManager<T extends HasId> implements RecordManagerInterface <T> {
...
}
that means your T has to implement your interface,
so your get getRecord method will be much simpler
public T getRecord(int id) {
for ( T k: record) {
if (k.getId() == id)
return k;
}
return null;
}
EDIT
Lets say your common interface will be
interface CommonInterface<T> extends Comparable<T> {
public int getId();
}
then definition of your class will be, ie
Person implements CommonInterface<Person> {
...
}
your RecordManager
class RecordManager<T extends CommonInterface<T>> implements
RecordManagerInterface<T>{
}
and that should fix all your problems with sort

This is what is called "coding to the interface". Then when you instantiate the objects, make your reference to the interface and the object to the specific class you want to instantiate.
Ex:
Interface example = new Class();
Then use example.getMethod(), example.setMethod(). This will actually call the Class.getMethod() if it has one, as per inheritance.

Related

Java method returning two or more generic types

There are a lot of questions regarding Java methods returning generic types, but none of them helped me out so far.
So here's my code:
interface DAO<K, T> {
void insert(T t);
void update(K k, T t);
void delete(K k);
void delete();
T select(K k);
List<T> select();
}
public class CourseDAO implements DAO<String, Course> {
public void insert(Course t) {}
public void update(String k, Course t) {}
public void delete(String k) {}
public void delete() {}
public Course select(String k) {}
public List<Course> select() {}
}
public class StudentDAO implements DAO<Long, Student> {
public void insert(Student t) {}
public void update(Long k, Student t) {}
public void delete(Long k) {}
public void delete() {}
public Student select(Long k) {}
public List<Student> select() {}
}
public enum EntityType { COURSE, STUDENT }
Now I want a factory method which accepts an EntityType parameter and return an instance of CourseDAO or StudentDAO depending on the parameter value.
I tried the code below without success:
public <K,T> DAO<K,T> createDAOFactory(EntityType type) {
switch (type) {
case COURSE : return (K,T) new CourseDAO(); break;
case STUDENT : return (K,T) new StudentDAO(); break;
}
return null;
}
Could anyone help me in writing and invoking this method???
Cheers,
Romualdo.
The cast you're looking for is (DAO<K,T>). But you'll get a warning because generic type erasure makes it unsafe. Another inherent risk in the switch factory is that you might forget to create a corresponding case when you add a new EntityType. A safer alternative would be to redefine EntityType with generic types, and let it be the factory. Unfortunately, this isn't possible with proper enums, but you can simulate it like this:
abstract class EntityType<K, T> {
public abstract DAO<K, T> createDAO();
public static final EntityType<String, Course> COURSE = new EntityType<String, Course>() {
#Override
public DAO<String, Course> createDAO() {
return new CourseDAO();
}
};
public static final EntityType<Long, Student> STUDENT = new EntityType<Long, Student>() {
#Override
public DAO<Long, Student> createDAO() {
return new StudentDAO();
}
};
}
Or you can use lambdas to reduce the boilerplate:
class EntityType<K, T> {
private final Supplier<DAO<K, T>> constructor;
private EntityType(Supplier<DAO<K, T>> constructor) {
this.constructor = constructor;
}
public DAO<K, T> createDAO() {
return constructor.get();
}
public static final EntityType<String, Course> COURSE = new EntityType<>(CourseDAO::new);
public static final EntityType<Long, Student> STUDENT = new EntityType<>(StudentDAO::new);
}
Now, instead of calling createDAOFactory(EntityType.COURSE), you would just call EntityType.COURSE.createDAO().
maybe you can do like this?
public class StudentDAO<Long,Student> implements DAO<Long, Student> {
public void insert(Student t) {}
public void update(Long k, Student t) {}
public void delete(Long k) {}
public void delete() {}
public Student select(Long k) {return null;}
public List<Student> select() {return null;}
}
public <K,T> DAO<K,T>createDAOFactory(EntityType type) {
switch (type) {
case COURSE : return new CourseDAO();
case STUDENT : return new StudentDAO();
}
return null;
}
first answer
you do not need use generics,because Implementation class has specified the type.
public DAO createDAOFactory(EntityType type) {
switch (type) {
case COURSE : return new CourseDAO();
case STUDENT : return new StudentDAO();
}
return null;
}

How to instantiate this class parametrized by bonded interface?

I've got 3 interfaces:
public interface IAggregable<TElement extends IAggregable<TElement, TResult>, TResult> {
TResult aggregate(TResult intermediateResult);
}
public interface IDeeplyCloneable<TElement extends IDeeplyCloneable<TElement>> {
TElement deepClone();
}
public interface IContainer<TElement extends IAggregable<TElement, TResult> & IDeeplyCloneable<TElement>, TResult> {
TResult aggregateAllElements();
TElement cloneElementAtIndex(int index);
}
Then there are two classes that implement those 2 first interfaces:
public class Person implements IAggregable<Person, Integer>, IDeeplyCloneable<Person> {
private int age;
public Integer aggregate(Integer intermediateResult) {
if (intermediateResult == null) {
return age;
}
return age + intermediateResult;
}
public Person deepClone() {
Person clone = new Person();
clone.age = age;
return clone;
}
#Override
public String toString() {
return "Person [age=" + age + "]";
}
}
and almost exactly the same
public class Car implements IAggregable<Car, Integer>, IDeeplyCloneable<Car> {
private int horsepower;
public Integer aggregate(Integer intermediateResult) {
if (intermediateResult == null) {
return horsepower;
}
return horsepower + intermediateResult;
}
public Car deepClone() {
Car clone = new Car();
clone.horsepower = horsepower;
return clone;
}
#Override
public String toString() {
return "Car [horsepower=" + horsepower + "]";
}
}
then there's finally UselessContainer which suppose to implement IContainer and be able to hold both Person and Car and any other objects of any other class that implements IAggregable and IDeeplyCloneable.
public class UselessContainer<TElement extends IAggregable<TElement, TResult> & IDeeplyCloneable<TElement>, TResult> implements IContainer<TElement, TResult> {
private ArrayList<TElement> list;
public UselessContainer() {
this.list = new ArrayList<>();
}
public void add(TElement element) {
list.add(element);
}
#Override
public TResult aggregateAllElements() {
return null;
}
#Override
public TElement cloneElementAtIndex(int index) {
return null;
}
#Override
public String toString() {
return list.toString();
}
}
Question : How to create object of class UselessContainer?
I've tried that: UselessContainer<? extends IAggregable<?, Integer> & IDeeplyCloneable<?>, Integer> container;
You have marked your UselessContainer to be bound BOTH to IAggregable and IDeeplyCloneable. Please look at the & sign which indicates both of the interfaces must be implemented by business entity to be added to the list.
In order to use it in code - just create instance of UselessContainer without specyfing concrete generics types:
UselessContainer uc = new UselessContainer();
uc.add(new Person()); // works!
uc.add(new Integer(1)); // won't compile
uc.add(new Car()); // works!
I just tried it in my Editor and it works (JDK8).
EDIT:
You may create wrapping class:
class SimpleContainer {
public <TElement extends IAggregable<TElement, TResult> & IDeeplyCloneable<TElement>, TResult> void add(TElement el) {
UselessContainer<TElement, TResult> uc = new UselessContainer<>();
uc.add(el);
}
}
and use it:
SimpleContainer sc = new SimpleContainer();
sc.add(new Person());
You have 2 conditions you want to meet for UselessContainer<A, B> (well shorten this to U<A,B>):
(1) Cars can be added to U<A, B>
(2) Persons can be added to U<A, B>
Fulfilling both (1) and (2) is impossible, which can be proven using a indirect proof:
Assume fulfilling both conditions was possible.
The signature of add is add(TElement element) method and TElement extends IAggregable<TElement, TResult>.
From (1) and Car implements IAggregable<Car, Integer> we can therefore deduce A=Car.
And from (2) and Person implements IAggregable<Person, Integer> we can therefore deduce A=Person.
Combining those 2 results we get Car=Person which is obviously wrong. This contradiction concludes the proof.
This means you have to modify the restrictions on the type parameters or use the raw type.

Java - How to call a method of my class T in a generic class

I've an issue with my class ListFromFile<T> which extends ArrayList<T>.
In that class, i would like to make a method that finds an element by its id attribute and returns it.
The T could be an object from the classes Student, Teacher etc. All these classes have a equals method that tests the id.
My problem is that i can't use the equals method which test the id in ListFromFile.
Here is my code :
public class ListFromFile<T> extends ArrayList<T> implements Serializable {
public T getElement(int id) {
for ( T o : this ) {
if ( o.equals((int)id) ) {
return o;
}
}
return null;
}
}
Even if i specify in the equals method i'm working with an id which is an int, getElement() doesn't find the element ...
After some searches, it seems that i have to extend T by Student, Teacher etc., but how to extends multiples classes ?
Thank you
You should use an interface or an abstract class with a getId() method. Bind T to be a subtype of either the interface or the abstract class. Using an interface, it might look like this.
public interface ObjectWithId {
int getId();
}
public class Student implements ObjectWithId {
// ...
}
public class Teacher implements ObjectWithId {
// ...
}
public class ListFromFile<T extends ObjectWithId> extends ArrayList<T> {
public T getElement(int id) {
for ( T o : this ) {
if ( o.getId() == id ) {
return o;
}
}
return null;
}
}
Here is sample application which shows how you can solve this problem:
import java.io.Serializable;
import java.util.ArrayList;
public class test2 {
// define basic interface for all objects
interface ObjectWithID {
public int getId();
}
public static class Teacher implements ObjectWithID {
private final int id;
public Teacher(final int id) {
this.id = id;
}
#Override
public int getId() {
return this.id;
}
}
public static class Student implements ObjectWithID {
private final int id;
public Student(final int id) {
this.id = id;
}
#Override
public int getId() {
return this.id;
}
}
// note T extends syntax
public static class ListFromFile<T extends ObjectWithID> extends ArrayList<T> implements Serializable {
public T getElement(final int id) {
for (final T o : this)
if (o.getId() == id)
return o;
return null;
}
}
public static void main(final String[] args) {
final ListFromFile list = new ListFromFile<>();
list.add(new Teacher(1));
list.add(new Teacher(2));
list.add(new Teacher(3));
list.add(new Student(4));
list.add(new Student(5));
list.add(new Student(6));
System.out.println(list.getElement(1)); // print teacher
System.out.println(list.getElement(4)); // print student
}
}

How to implement a generic wrapper for a ResultSet-like API?

I have an third-party RPC-API that provides an interface similar to that of java.sql.ResultSet (for reading values) and java.sql.PreparedStatement (for writing values). Assume it looks something like this:
public interface RemoteDeviceProxy {
public void setBoolean(Boolean value);
public void setInteger(Integer value);
// ...
public Boolean getBoolean();
public Integer getInteger();
// ...
}
I want to write a wrapper for this API that uses generics to create instances of specific types:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
public RemoteVariable(RemoteDeviceProxy wrappedDevice) {
this.wrappedDevice = wrappedDevice;
}
public T get() {
// should call wrappedDevice.getBoolean() if T is Boolean, etc.
// how to implement?
}
public void set(T newValue) {
// should call wrappedDevice.setBoolean(newValue) if T is Boolean, etc.
// implement using instanceof
}
}
How can I implement the getter in my generic wrapper? I have found this answer which explains a similar scenario in depth, but I am not able to transfer this to my problem. Specifically, when I write this:
public T get() {
Type[] actualTypeArguments = ((ParameterizedType) getClass())
.getActualTypeArguments();
}
I get a compiler error saying I cannot cast to ParameterizedType, and I do not understand why. Can anyone explain how to achieve this?
Here is one way:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
private final Class<T> clazz;
public RemoteVariable(RemoteDeviceProxy wrappedDevice, Class<T> clazz) {
this.wrappedDevice = wrappedDevice;
this.clazz = clazz;
}
public T get() {
if(clazz == Boolean.class){return clazz.cast(wrappedDevice.getBoolean());}
else if(clazz == Integer.class){return clazz.cast(wrappedDevice.getInteger());}
// ...
}
// ...
}
I thought over this quite a while and finally came up with a different approach:
First I added a getter to you RemoteVariable class:
protected RemoteDeviceProxy getWrappedProxy() {
return wrappedProxy;
}
Second I created a builder interface that will be used by a factory later:
public interface RemoteVariableBuilder {
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy);
}
Then I created non generic sub classes for Boolean...
public class RemoteBooleanVariable extends RemoteVariable<Boolean> implements RemoteVariableBuilder {
public RemoteBooleanVariable(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteBooleanVariable(wrappedProxy);
}
#Override
public Boolean get() {
return getWrappedProxy().getBoolean();
}
#Override
public void set(Boolean value) {
getWrappedProxy().setBoolean(value);
}
}
... and Integer ...
public class RemoteIntegerBuilder extends RemoteVariable<Integer> implements RemoteVariableBuilder {
public RemoteIntegerBuilder(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteIntegerBuilder(wrappedProxy);
}
#Override
public Integer get() {
return getWrappedProxy().getInteger();
}
#Override
public void set(Integer value) {
getWrappedProxy().setInteger(value);
}
}
actually eclipse created most of the code once it knew base class and interface.
The final step was to create a factory
public class RemoteVariableFactory {
private static final Map<String, RemoteVariableBuilder> BUILDERS = new HashMap<>();
static {
BUILDERS.put(Boolean.class.getName(), new RemoteBooleanVariable(null));
BUILDERS.put(Integer.class.getName(), new RemoteIntegerBuilder(null));
// add more builders here
}
public static <T> RemoteVariable<T> getRemoteVariable(RemoteDeviceProxy wrappedProxy, Class<T> typeClass) {
RemoteVariableBuilder remoteVariableBuilder = BUILDERS.get(typeClass.getName());
if (remoteVariableBuilder == null) {
return null; // or throw an exception whichever is better in your case
}
return remoteVariableBuilder.buildNewVariable(wrappedProxy);
}
}
Now we are ready to create new RemoteVariables...
RemoteVariable<Boolean> var1 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Boolean.class);
RemoteVariable<Integer> var2 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Integer.class);
To conclude this let's do a quick comparison to the answer of Eng.Fouad:
Disadvantage:
you need to create a new class for every datatype you provide
Advantage:
you only have to add one line to the static block of the factory and not two new if blocks to the getter and setter in RemoteVariable
get and set do not have to work through the if-else-blocks every time

Generic Class and Method

I'm working on a pagination system for my java project, and I'd like to make it generic for my various JPA Models.
The problem (as far as I know) is that if I use generics, I will have to somehow cast the returned final value to work on it. How can I avoid that ?
Here's my code so far (absolutely not generic!) :
public interface Paginator {
public void setLimit(Integer limit);
public Page page(Integer page);
}
public class PicturesPaginator implements Paginator {
private Integer limit = 10;
private JPAQuery query;
private Long quantity;
public PicturesPaginator(String query, Object... params) {
this.query = Picture.find(query, params);
this.quantity = Picture.count(query, params);
}
#Override
public void setLimit(Integer limit) {
this.limit = limit;
}
#Override
public PicturesPage page(Integer page) {
if (page == null)
page = 1;
List<Picture> pictures = query.fetch(page, limit);
return new PicturesPage(pictures, quantity, page, limit);
}
}
public abstract class Page {
protected List<Picture> pictures;
protected Long quantity;
protected Integer page;
protected Integer limit;
public List<Picture> list() {
return pictures;
}
public Long count() {
return quantity;
}
public boolean hasNext() {
return (page * limit > quantity);
}
public boolean hasPrevious() {
return (page != 1);
}
public boolean hasOtherPages() {
return (hasNext() || hasPrevious());
}
public Integer nextPageNumber() {
if (!hasNext())
return null;
return (page + 1);
}
public Integer previousPageNumber() {
if (!hasPrevious())
return null;
return (page - 1);
}
public Integer currentPageNumber() {
return page;
}
}
public class PicturesPage extends Page {
public PicturesPage(List<Picture> pictures, Long quantity, Integer page, Integer limit) {
this.pictures = pictures;
this.quantity = quantity;
this.page = page;
this.limit = limit;
}
}
I would like to get rid of those PicturesPaginator and PicturesPage and make it generic, but the list() method from the abstract class Page would return a generic List (List<T> or List<GenericModel> since I use Play here).
What I would expect is this list() method to return the correct List, aka List<Picture> in my case. Is this possible ?
Note: I now there is a module for pagination in Play! Framework, my question is mainly for understanding more about java too :)
Thank you very much for your help, I really appreciate!
You can view my Play--Pagination module's source code to see how I handle this type of thing. I put my source on github.
What you want to do is make Page generic as well, and probably non-abstract:
public class Page<T> {
public List<T> list() {}
}
And instead of PicturesPage you could just do:
new Page<Picture>()
The Paginator interface would also need to be generified:
public interface Paginator {
public Page<T> page(Integer page);
}
Generifying PicturesPaginator would be harder since you invoke methods on the Picture class. Java's generics implementation erases types at runtime, so you'll have to deal with type tokens and reflection.
public abstract class GenericPaginator<T> {
public GenericPaginator() {
Class<T> typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
// use reflection to invoke the finders methods
}
}
public class PicturesPaginator extends GenericPaginator<Picture> {}
What I would expect is this list() method to return the correct List,
aka List in my case. Is this possible?
That's not just possible, that's what you automatically get if you use generics correctly. If you declare
public class Page<T extends GenericModel>{
protected List<T> items;
public List<T> list() {
return items;
}
}
and use it like this:
page = new Page<Picture>();
then page.list() will in fact return a List<Picture>, because T is a type parameter that is replaced by a concrete type when a Page is declared.
If I understand you correctly, the following may help:
Make Pace generic. Turn
public abstract class Page {
protected List<Picture> pictures;
public List<Picture> list() {
return pictures;
}
to:
public abstract class Page<Element> {
protected List<Element> elements;
public List<Element> list() {
return elements;
}
Than make PicturesPage concret:
public class PicturesPage extends Page<Picture> {
I'm not sure if this is what you require, but you can convert the Page class to this:
public abstract class Page<T> {
protected List<T> pictures;
protected Long quantity;
protected Integer page;
protected Integer limit;
public List<T> list() {
return pictures;
}
public Long count() {
return quantity;
}
public boolean hasNext() {
return (page * limit > quantity);
}
public boolean hasPrevious() {
return (page != 1);
}
public boolean hasOtherPages() {
return (hasNext() || hasPrevious());
}
public Integer nextPageNumber() {
if (!hasNext())
return null;
return (page + 1);
}
public Integer previousPageNumber() {
if (!hasPrevious())
return null;
return (page - 1);
}
public Integer currentPageNumber() {
return page;
}
If I understand you correctly, your problem with introducing generics here are lines like this:
this.query = Picture.find(query, params);
AFAIK you can't invoke static methods on generic types directly, so you'd have to use reflection here. In that case you might have to pass the class of the parameter type as a parameter (or get it from reflection data if it exists), find the method you want to invoke and invoke it.
It's something like this:
Class<T> clazz;
public Paginator (Class<T> clazz) {
this.clazz = clazz;
//note that you need to handle exceptions, I'll leave them out for brevity
Method findMethod = clazz.getMethod("find", String.class, Array.class );
this.query = findMethod.invoke(null, query, params);
}
Edit
As an alternative, pass a "finder" object to the generic Paginator and make it implement an interface that provides the find(...) and count(...) methods:
interface Finder<T> {
JPAQuery find( String query, Object... params);
Long count( String query, Object... params);
}
class Paginator<T, F extends Finder<T>> {
public Paginator(F finder, String query, Object... params) {
this.query = finder.find(query, params);
...
}
...
}

Categories

Resources