1

I have the following DataSet class where we hold any kind of object. Mostly to transfer objects from the server to the client. The contents variable can hold any serializable object. It could be custom written class Objects or java classes like Integer, String etc.

I'm trying to convert this into generics. How should we go about converting this into Generics at the same time, I would like to make sure that I don't have to change all the containing object class code, since we are even using String and Integer classes within the contents.

I have simplified the class to only show some relevant fields and methods.

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.Hashtable;
import java.util.Vector;

public class DataSet implements Serializable, PropertyChangeListener{

    Hashtable contents = new Hashtable();

    @Override
    public void propertyChange(PropertyChangeEvent arg0) {
        // TODO Auto-generated method stub

    }

    public void addObject(Object obj){
        Vector vector = (Vector)contents.get(obj.getClass());
        if (vector == null){
            vector = new Vector();
            vector.add(obj);
            contents.put(obj.getClass(), vector);
        }
    }

    public Vector getObjects(Class objType){
        if (contents.contains(objType)){
            return (Vector)contents.get(objType);
        }
        else{
            return new Vector();
        }
    }
}

Appreciate your prompt replies. But, after reviewing the three answers below, I felt like I didn't convey the problem correct.

To make this the way I want, if I invoke dataset.getObjects(of E type), I should be getting a vector of E type. I shouldn't be casting into (Vector). Because I want the contents to be holding Class<E>, and Vector<E> of key value pairs. If we can do that, then only I could say that this is safe.

DataSet ds = new DataSet();
Vector<String> strings = ds.getObjects(String.class);
Vector<Integer> integer = ds.getObjects(Integer.class);
Vector<Employee> employees = ds.getObjects(Employee.class);

3 Answers 3

2

First of all, stay away from class Vector, it's obsolete; use ArrayList instead.

Here's a simple way to store heterogeneous objects while avoiding explicit casting when retrieving objects. I'm sure you can work this model into your solution.

UPDATED, thanks to advice from Paul Bellora.

public class DataSet { 

    private Map<Class<?>, List<?>> contents;

    public DataSet(){
       contents = new HashMap<Class<?>, List<?>>();  
    } 

    @SuppressWarnings(value = { "unchecked" })
    public <T> void addObject(Class<T> klass, T object){
        List<T> objectsList = (List<T>)contents.get(klass);
        if (objectsList == null){
            objectsList = new ArrayList<T>();            
            contents.put(klass, objectsList);
        }
        objectsList.add(object);
    }

    @SuppressWarnings(value = { "unchecked" })
    public <T> List<T> getObjects(Class<T> klazz) {
        return contents.containsKey(klazz) ? 
                contents.get(klazz) : Collections.EMPTY_LIST;
    }

    public static <S, T extends Iterable<S>> void print(T list){
        for (Object element : list){
            System.out.println(element);
        }
    }

    public static void main(String[] o){
       DataSet ds = new DataSet();
       ds.addObject(String.class, "save the earth!");
       ds.addObject(String.class, "firing now!");       
       ds.addObject(Integer.class, new Integer(100));
       ds.addObject(Boolean.class, new Boolean(true));

       print(ds.getObjects(String.class));
       print(ds.getObjects(Boolean.class));
       print(ds.getObjects(Integer.class));      
    }
 }

Hope it helps.

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

4 Comments

I Like this better. I wasn't aware of the syntax "public <T> T getObject(Class<T> klass)" that you have used. Only thing is, I would like to hold a Class<T> as the key and Vector<T> of that type of the value. Not an Object. Object is too generic for me and considered not safe. If we can get that done, I'm good. This is part of a huge framework that we have in our local environment and it is not easy to change all the other referring classes. I agree that we can have ArrayList. It wouldn't make a difference for me in converting into Generics.
What do you mean "hold a Class<T> as the key"? The class name, hash code of the object, what?
Hashtable will hold key value pairs, in such away that key will be of certain type and the value will be a Vector of that type. For example, Hashtable will have 1. java.lang.String as the key and Vector<String> as the value. 2. custom.pkg.Employee as the key and the Vector<custom.pkg.Employee> as the value. I hope you understand. As you clearly identified, this Hashtable will have more than a single type of key value pairs.
I would just use Class<?> as the key - that's what the type-safe heterogenous container pattern usually looks like. Allowing other strings besides the class names seems problematic anyway.
0

If I am not mistaken ,your Hashtable contents variable hold the class of a Serializable Object as key and the Serializable Vector List as value

   import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.io.Serializable;
    import java.util.Hashtable;
    import java.util.Vector;

    public class DataSet implements Serializable, PropertyChangeListener{

        Hashtable<Class,Vector<Serializable> contents = new Hashtable<Class,Vector<Serializable>();

        @Override
        public void propertyChange(PropertyChangeEvent arg0) {
            // TODO Auto-generated method stub

        }

        public void addObject(Serializable obj){

            Vector<Serializable> vector = contents.get(obj.getClass());
            if (vector == null){
                vector = new Vector<Serializable>();
                vector.add(obj);
                contents.put(obj.getClass(), vector);
              }
            else{
              vector.add(obj);
               }
        }

        public Vector<Serializable> getObjects(Class objType){
            if (contents.contains(objType)){
                return (Vector<Serializable>)contents.get(objType);
            }
            else{
                return new Vector<Serializable>();
            }
        }
    }

5 Comments

Your "Hashtable<Class,Vector<Serializable> contents = new Hashtable<>();" @"Kumar Abhinav" is giving me a compilation issue.
@user3656845 Its a diamind operator,newly introduced in Java 7 only..Read Diamond operator
@user3656845 You can use the normal inference type on both sides.
I modified the question a little bit. When I invoke getObjects(Class<E>), I should be getting Vector<E>.
@user3656845 I think my program works perfectly fine for the above case
0

Perhaps this would be sufficient:

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.Map;
import java.util.List;

public class DataSet implements Serializable, PropertyChangeListener{

    Map<Class<?>, Vector<Serializable>> contents = new HashMap<Class<?>, Vector<Serializable>>();

    @Override
    public void propertyChange(PropertyChangeEvent arg0) {
        // TODO Auto-generated method stub
    }

    public void <T extends Serializable> addObject(T obj){
        Vector<T> vector = (Vector<T>)contents.get(obj.getClass());
        if (vector == null){
            vector = new Vector<T>();
            contents.put(obj.getClass(), vector);
        }
        vector.add(obj);
    }

    public <T extends Serializable> Vector<T> getObjects(Class<T> objType){
        if (contents.contains(objType)){
            return (Vector<T>)contents.get(objType);
        }
        else{
            return new Vector<T>();
        }
    }
}

I've edited my original post. Indeed, as pointed by Duncan in his comments, a DataSet structure has no point of being generic itself. Still, some generics could still add some syntax sugar in attempt to avoid casting

6 Comments

I don't think DataSet should be generic, since the intention is to store objects of all types. FWIW, I'm not your down-voter.
contents should hold Vector list if Serializable objects,wildcard does not solve it.See OP
@KumarAbhinav, you have a point, wildcard is not helpful there.
Duncan is right. I cannot make the dataset generic. Because it can hold any kind of object. Again, I have modified the question. To make this the way I want, if I invoke dataset.getObjects(of E type), I should be getting a vector of E type. I shouldn't be casting into (Vector). Because I want the contents to be holding Class<E>, and Vector<E> of key value pairs. If we can do that, then only I could say that this is safe. Am I expecting too much or trying to do impossible ??
@Duncan, Indeed you are correct. I've taken your point and removed the generic on the class-level. It seems it fits better on a method level, where the consumer would benefit from an avoided type-casts
|

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.