2

There are two entities classes:

public class Base {
    private String provider;
}

public class SuperClass extends Base {
    private String trunk;
}

and main class:

public class Test {
    public static <T extends Base> List<T> getDetailedReport(Class<T> clazz, String providerName) {
        List<T> list = new ArrayList<>();
        T entity = new Base(); // this is wrong, of course.
        return list;
    }

    public static void main(String[] args) {
        Base base = new Base();
        ​SuperClass superClass = new SuperClass();
        List<Base> baseList = getDetailedReport(Base.class, "Telia");
        List<SuperClass> superClassList = getDetailedReport(SuperClass.class, "Globalcom");
    ​}
​}

I'm trying to create generic method getDetailedReport which returns list of entities. Type of entity is passed through clazz variable. My question is: How to create entity of necessary type?

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
harp1814
  • 1,494
  • 3
  • 13
  • 31
  • Duplicate? https://stackoverflow.com/questions/75175/create-instance-of-generic-type-in-java – Lii May 27 '21 at 08:08
  • You could use reflection, i.e. the `newInstance()` method on `Class` or one of the constructors. However, you seem to need parameters (like provider for both and trunk for `SuperClass`) so some kind of factory might be better suited here. – Thomas May 27 '21 at 08:09
  • https://stackoverflow.com/questions/67529555/how-do-i-pass-in-a-type-as-an-argument-in-java/67529730#67529730 – Shaan K May 27 '21 at 08:13

1 Answers1

0

Reflection API is your friend here. To use the following implementation, you need to make sure the following conditions:

  1. The Base and all the derived objects have no-args constructor (i.e. new Base() or new SuperClass()).
  2. You need deal with 4 thrown exceptions: NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException.

Minimal sample (using Lombok):

@Data
@NoArgsConstructor
public static class Base {
    private String provider;
}
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@NoArgsConstructor
public static class SuperClass extends Base {
    private String trunk;
}
@SneakyThrows
static <T extends Base> List<T> getDetailedReport(Class<T> clazz, String provider) {
    List<T> list = new ArrayList<>();
    T entity = clazz.getDeclaredConstructor().newInstance();
    entity.setProvider(provider);
    list.add(entity);
    return list;
}
List<Base> baseList = getDetailedReport(Base.class, "Telia");
List<SuperClass> superClassList = getDetailedReport(SuperClass.class, "Globalcom");

System.out.println(baseList);
// [Main.Base(provider=Telia)]

System.out.println(superClassList); 
// [Main.SuperClass(super=Main.Base(provider=Globalcom), trunk=null)]
  • I made the data classes static in order to use in the class with the main method comfortably
  • I used @SneakyThrows for safe of answer clarity - you, however, need to handle these exceptions
  • Note that @NoArgsConstructor satisfies clazz.getDeclaredConstructor().newInstance().
  • You might need to modify the implementation as you need (I let the method pass String provider into a newly created instance through the Reflection API and returned it in the List as a demonstration).
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183