1

i got multiple classes which do basicly the same. I pass a JSONObject in the constructor an it sets some variabes.

Now i got some other classes which create those first classes and add them to a ArrayList. Now i want to merge the second classes to one using generics.

This is what I want to do:

 public class Data<T> {
     public ArrayList<T> data;

     public Data(String response1) {
         data = new ArrayList<T>();
         JSONArray ja;

         try {
              ja = new JSONArray(response1);
              for (int i = 0; i < ja.length(); i++) {
                  JSONObject jo = (JSONObject) ja.get(i);
                  data.add(new T(jo));
              }
         } catch (JSONException e) {
              e.printStackTrace();
         }
     }
 }

but it doesnt let me create an Instance of T with

new T(jo);

Would be nice if someone can help me

Cheetah
  • 506
  • 5
  • 16
  • 1
    Just a question: if the "T" generic type is an interface in runtime, on a specific Data instance, like say Data how should "new T(something)" work? – ppeterka Feb 26 '13 at 14:58
  • It is a very strange. You even did not specify a superclass of generic type `T`. How it could understand such construction? – Andremoniy Feb 26 '13 at 14:59
  • See this: http://stackoverflow.com/questions/182636/how-to-determine-the-class-of-a-generic-type – Christophe Roussy Feb 26 '13 at 15:00

2 Answers2

3

There is a standard trick for this situations: pass Class<T> along with the String data into the call, and add a setter for the JSONObject. This would let you call a parameterless constructor, like this:

interface WithJson {
    void setJson(JSONObject jo);
}

public class Data<T extends WithJson> {
    public Data(String response1, Class<T> type) {
        data = new ArrayList<T>();
        JSONArray ja;
        try {
             ja = new JSONArray(response1);
             for (int i = 0; i < ja.length(); i++) {
                 JSONObject jo = (JSONObject) ja.get(i);
                 T obj = type.newInstance();
                 object.setJson(jo);
                 data.add(obj);
             }
        } catch (JSONException e) {
             e.printStackTrace();
        }
    }
}

The Class<T> has been modified in Java 5 to let you use it as a factory for the instances of that class. The call of type.newInstance is checked statically for type safety. The addition of the interface WithJson lets you call setJson method on the instances of T in a way that the compiler can check statically.

When you construct Data<T>, you need to pass the class being created, like this:

Data<MyContent> d = new Data(jsonString, MyContent.class);
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • If I create a new instance of Data what do i have to pass beside the String – Cheetah Feb 26 '13 at 15:26
  • @Cheetah That's an important thing that I missed in the original response. I edited the answer to show what to do. I also fixed a copy-paste error (I pasted `Class type` into a wrong place). – Sergey Kalinichenko Feb 26 '13 at 15:30
0

Use a generic factory interface.

public interface Factory<T>
{
    public T createFromJSONObject( JSONObject jo );
}

And now a modified constructor:

 public Data(
   String response1,
   Factory<T> factory
 ) {
     data = new ArrayList<T>();
     JSONArray ja;

     try {
          ja = new JSONArray(response1);
          for (int i = 0; i < ja.length(); i++) {
              JSONObject jo = (JSONObject) ja.get(i);
              data.add( factory.createFromJSONObject( jo ) );
          }
     } catch (JSONException e) {
          e.printStackTrace();
     }
 }
Alexander Pogrebnyak
  • 44,836
  • 10
  • 105
  • 121