1

Looking at the Crud object code below, what I'm expecting is an array of Field objects for type T. What I appear to actually get is an empty array of of Field objects for type Object. My test class is called Timezone. So, when I instantiate the Crud object it looks like...

Crud<Timezone> tz = new Crud<Timezone>();

But as I said this isn't working. Help appreciated.

import java.util.*;
import java.lang.reflect.*;
public class Crud<T> {

    public T getInstance()
    {
        @SuppressWarnings("unchecked")
        T object = (T) new Object();
        return object;
    }

    public ArrayList<String> getMembers() {
        ArrayList<String> retval = new ArrayList<String>();
        try {
            T object = this.getInstance();
            Field[] fields = object.getClass().getDeclaredFields(); //Always empty
            for (Field field : fields) {
                retval.add(field.getName());
            }
        } catch (Exception e) {
            System.out.println(e);
        }

        return retval;
    }

}
Ronald Weidner
  • 690
  • 5
  • 15

5 Answers5

2

Even without generics, you cannot do anything like this:

Timezone object = (Timezone) new Object();

new Object() will create an object whose runtime type is Object. This will have all the fields and methods an Object has, but no others. Once the Object is created, a cast cannot be used to magically convert the object to some other type; that would involve adding all the new fields and methods a Timezone has, and Java can't do that.

So this can't possibly work either:

T object = (T) new Object();

Unfortunately, Java won't let you do this either:

T object = new T();

because of "type erasure". Please see Create instance of generic type in Java? for some ideas for working around this (unless the solution without generics works for you).

Community
  • 1
  • 1
ajb
  • 31,309
  • 3
  • 58
  • 84
2

No, due to type erasure, you can't access the type at runtime.

However, there is a pattern to solve the problem of creating an instance of the generic type; you must pass a type token to the constructor:

public class Crud<T> {
    private Class<T> clazz;
    public Crud(Class<T> clazz) {
        this.clazz = clazz;
    }

    public T getInstance() {
        return clazz.newInstance();
    }
Bohemian
  • 412,405
  • 93
  • 575
  • 722
1

If what you want is wrapping an instance and getting its fields, there's no need for generics. You can use Object as a base class to allow any kind of objects in your wrapper. For example

public class Crud {

    private final Object object;

    public Crud(final Object someObject) {
        this.object = someObject;
    }

    public ArrayList<String> getMembers() {
        ArrayList<String> retval = new ArrayList<String>();
        try {
            Field[] fields = this.object.getClass().getDeclaredFields();
            for (Field field : fields) {
                retval.add(field.getName());
            }
        } catch (Exception e) {
            System.out.println(e);
        }

        return retval;
    }

}

Then you just do

Crud tz = new Crud(new Timezone());
m0skit0
  • 25,268
  • 11
  • 79
  • 127
0

You should probably implement the method getDeclaredFields() specifically for Timezone, in class Timezone.

La-comadreja
  • 5,627
  • 11
  • 36
  • 64
  • I don't really understand your answer. And no need to implement `getDeclaredFields()`, all `Class` objects have this method. – m0skit0 Feb 25 '14 at 00:30
0

We can define the generic class like so:

public class Crud<T> {

    private final Class<T> mClass;

    public Crud(Class<T> tClass)
    {
        mClass = tClass;
    }

    public T getInstance() throws Exception
    {
        T object = mClass.newInstance();
        return object;
    }

    ...
}

And then we can use it like this:

try
{
    Date tDate = new Crud<Date>(Date.class).getInstance();
    System.out.println("Date: " + tDate);
}
catch(Exception e)
{
    System.out.println("Error: " + e);
}

Output: Date: Mon Feb 24 21:00:04 PST 2014

Ionoclast Brigham
  • 1,703
  • 1
  • 12
  • 19