1

Given an object which stores values of different types,

public class Record {
    String  string;  
    Float   floot;
    Integer integer;
}

an object which stores values of one type in a data structure

public class GenericList<T> {
    private final List<T> genericList;

    public GenericList() {
        genericList = new ArrayList();
    }

    public void add(T element) {
        genericList.add(element);
    }
}

and an object which stores multiple instances of the above object (GenericList) in another data structure.

public class Structure {
    private final List<GenericList> structure;

    public Structure(Record record) {
        structure = createFrom(record);
    }

    private List<GenericList> createFrom(Record record) {
        List<GenericList> result = new ArrayList();
        // create one column for each field in record
        // with its corresponding type
        return result;
    }
}

How can we iteratively instantiate GenericList objects such that T is equal to the type of the current field in the given Record object?

Note:
The above code belongs to a system which pulls data from the internet every five minutes and stores them in the above shown data structure. This means that every five minutes the system creates a Record object (with a fixed number of fields) and either creates a new data structure from it or appends it to an existing one.

To be more precise:
In this example I want to create and store three GenericList objects:

GenericList<String>  stringList;
GenericList<Float>   floatList;
GenericList<Integer> integerList;

This can be done with the following code:

private List<GenericList> createFrom(Record record) {
    List<GenericList> result = new ArrayList();

    GenericList<String> stringList = new GenericList();
    stringList.add(record.string);
    structure.add(stringList);

    GenericList<Float> floatList = new GenericList();
    floatList.add(record.floot);
    structure.add(floatList);

    GenericList<Integer> integerList = new GenericList();
    integerList.add(record.integer);
    structure.add(integerList);

    return result;
}

But when the number of fields in the Record object increases, this method not only gets less readable and less maintainable but rather you have to expand the implementation to fit your requirements.
So to refactor this into solid, readable and maintainable code one would need to iterate over the fields in the Record object.
Reading through this post I have learned how to do just this. Applying the code given in the accepted answer to my problem, I expected the following code to work.

private List<GenericList> createFrom(Record record) {
    List<GenericList> result = new ArrayList();
    for (Field field : record.getClass().getDeclaredFields()) {
        // ERROR here
        GenericList<field.getType()> genericList = new GenericList();
        // IDE says: "> expected    not a statement"
        genericList.add(field.get(record));
        structure.add(genericList);
    }
    return result;
}

But as of this post I am stuck with manual instantiation and I am wondering if there is a way to implement what i want to do.

JaWo
  • 13
  • 4
  • I understand (mostly) way of thinking, see some errors in code... I had made few similar reflection solutions. What is main goal? Is this intellectual trenning, or practical object? – Jacek Cz Aug 15 '17 at 16:31
  • Maybe You want object strucure to describe types, ie String caption, Class for every columns??? Hard to guess. BTW Because generic type is erased, reflecion is possible only if at list record present (few programming technics exists) – Jacek Cz Aug 15 '17 at 16:32
  • The main goal of this code is to create a column major table from one given row of that table. In other words i want to convert a table row into several table columns. – JaWo Aug 15 '17 at 16:42
  • What if you add a `Column` class which can return a String representing its Type, then `Record` would just contain a `List`. – Sam Hazleton Aug 15 '17 at 17:00
  • Thanks for the idea @SamHazleton - But the problem is not _how_ data is stored in the Record object but rather the diamond operator of the GenericList object. What i mean by that is GenericList. Apparently in java I am not allowed to pass in a Type like this. – JaWo Aug 15 '17 at 18:01
  • One solution would be to use some *factory method*: `GenericList someMethod(Class foo) { return new GenericList() }` and call that with `field.getType()` as argument –  Aug 15 '17 at 18:44

1 Answers1

1

The short answer is you can't, and you don't need to.

A little more details: generics in Java are purely a compile-time construct, and are only used for compile-time type checking. When you create an ArrayList<String> what the compiler actually creates is an ArrayList<Object>, with appropriate type checks inserted when, for example, assigning an element from the list to a String variable.

What you can do with your example code is to just make genericList a GenericList<Object>, or leave out the type arguments like you did for the structure member in your Structure class. The generated code will be the same (as soon as you insert genericList into structure you drop the type information anyway).

Pezo
  • 1,458
  • 9
  • 15
  • Doing some primitive System.out.println testing, i realized that generic typing will eventually be erased to Object. Furthermore; whether i dont need to or not aside, the thing that interested me was _"can you implement this?"_. It would be pretty neat if you could. But i think i just realized what @SamHazleton meant with his suggestion. – JaWo Aug 15 '17 at 18:57
  • As I said and as you discovered, you can't. The keyword to look for would be *type erasure* btw. – Pezo Aug 16 '17 at 07:42
  • Yes i will look into this in more detail when i have more time. But for now i have reworked my code to just use Object typing. But what really bothers me is that i expected Generic Typing in java to be more usefull. As of my understanding now it is just not needed since everything gets erased to Object type. – JaWo Aug 16 '17 at 08:53