I have a DeclaredType of a field and I would like to get the fully qualified type (raw type?) of the field. For example if the field is:
public static Optional<String> foo;
I would like to get java.util.Optional.
Currently I can get the package name with:
env.getElementUtils().getPackageOf(declaredType.asElement());
I can get the type arguments of the type however I come back to the same problem I end up with a List of TypeMirror which I don't know how to get the qualified name of the types.
I have noticed that I can call TypeMirror#toString() and that will return (for the above) something like:
java.util.Optional<java.lang.String>
I guess I could then cut of everything in front of < but that feels like a hack.
For reference this is how I am getting the field:
private VariableElement getFieldWithName(DocletEnvironment environment, TypeElement classDoc, String fieldName) {
for(VariableElement e : ElementFilter.fieldsIn(environment.getElementUtils().getAllMembers(classDoc))) {
if(e.getSimpleName().toString().equals(fieldName)) {
return e;
}
}
return null;
}
TypeElement classElement = env.getElementUtils().getTypeElement(MyClass.class.getCanonicalName());
VariableElement fieldDoc = getFieldWithName(env, classElement, "foo");
DeclaredType declaredType = (DeclaredType) fieldDoc.asType();
I tested this code and it works on Apache Netbeans 10 and Jdk11.
Use ((DeclaredType) variableElement.asType()).asElement().toString():
DeclaredType declaredType = (DeclaredType) e.asType();//e is VariableElement from the loop
fullyQualifiedName = declaredType.asElement().toString();
Test Classes:
class MyClass1 {
public static Optional<String> foo;
public static List<String> newList;
public static MyClass2 obj;
public Media media;
public void calculate(Double dl) {
}}
class MyClass2 extends MyClass1{
public static Color cl;
}
And the Doclet implementation:
public class TestVarElement implements Doclet {
public void testFields(DocletEnvironment env) {
TypeElement typeElement = env.getElementUtils().getTypeElement(MyClass1.class.getCanonicalName());
System.out.println("Test for 'foo': "+getFieldWithName(env,typeElement,"foo"));
System.out.println("Test for 'newList': "+getFieldWithName(env,typeElement,"newList"));
System.out.println("Test for 'obj': "+getFieldWithName(env,typeElement,"obj"));
System.out.println("Test for 'media': "+getFieldWithName(env,typeElement,"media"));
}
private String getFieldWithName(DocletEnvironment env, TypeElement classDoc, String fieldName) {
String fullyQualifiedName = "";
for (VariableElement e : ElementFilter.fieldsIn(env.getElementUtils().getAllMembers(classDoc))) {
if (e.getSimpleName().toString().equals(fieldName)) {
DeclaredType declaredType = (DeclaredType) e.asType(); //The type of the VariableElement
fullyQualifiedName = declaredType.asElement().toString(); //Get the fqn
break;
}
}
return fullyQualifiedName;
}
#Override
public boolean run(DocletEnvironment docEnv) {
testFields(docEnv);
return true;
}
... Other Overrids
}
Debug/Run the program:
public class NewClass {
public static void main(String[] args) {
ToolProvider javadoc=ToolProvider.findFirst("javadoc").orElseThrow();
int result=javadoc.run(System.out, System.err, new String[]{"-doclet",TestVarElement.class.getName(),"C:\\Users\\Super3\\Documents\\NetBeansProjects\\Myproject\\src\\pk\\TestVarElement.java"});
//The following is for java 8 or older, the implementation is diferent where `start` method is used instead of `run`.
//Main.execute (new String[]{"-doclet",TestVarElement.class.getName(),"C:\\Users\\Super3\\Documents\\NetBeansProjects\\Myproject\\src\\pk\\TestVarElement.java"});
}
}
Output
Test for 'foo': java.util.Optional
Test for 'newList': java.util.List
Test for 'obj': pk.MyClass2
Test for 'media': javax.print.attribute.standard.Media
To convert a Generic type to its raw base, resolve it without any type arguments. See Types#getDeclaredType which can be called without specifying any types:
If zero, and if the type element is generic, then the type element's raw type is returned
DeclaredType rawType = env.getTypeUtils().getDeclaredType(typeElement);
I have a situation like this:
I have a class which looks like:
public class TestClass<T> {
// class body here...
}
And I have a method that looks like this:
public class AnotherTestClass<K> {
private TestClass<K> testClass;
public AnotherTestClass(TestClass<K> testClass) {
this.testClass = testClass;
}
public K testMethod() {
//call methods on param object and pass a value of the same type as testClass.
K returnVal = this.testClass.doSomething();
return returnVal;
}
}
Now I have a factory method which returns an object of type TestClass<?>
public TestClass<?> sampleFactory(int i) {
if( i==1 )
return new TestClass<Integer>();
if( i==2 )
return new TestClass<Double>();
if( i==3 )
return new TestClass<String>();
}
But I cant use that method to pass parameter to my testMethod. Whats the solution for this?
Currently I am writing if else chain blocks to get correct instance. I know its not correct as its impractical to write if else blocks when there are multiple parameters like the one above.
Please suggest an elegant way for this.
EDIT: Sample usage:
package my;
import java.util.ArrayList;
import java.util.List;
public class GenericsSpike {
public static void main( String[] args ) {
TestClass1< ? > tc1 = new TestClass1<Integer>( 123 );
TestClass2< ? > tc2 = new TestClass2<Integer>( 123 );
AnotherTestClass< ? > atc = new AnotherTestClass<Integer>( tc1, tc2 );
atc.testMethod();
}
}
class TestClass1<T> {
private T value;
TestClass1( T val ) {
value = val;
}
// class body here...
public T getValue() {
return value;
}
}
class TestClass2<T> {
private T value;
TestClass2( T val ) {
value = val;
}
// class body here...
public T getValue() {
return value;
}
}
class AnotherTestClass<K> {
public TestClass1<K> testClass1, testClass2;
public AnotherTestClass( TestClass1<K> testClass, TestClass2<K> testClass2 ) {
this.testClass1 = testClass;
}
public K testMethod() {
//Any logic can come here.
System.out.println( testClass1.getValue() );
System.out.println( testClass2.getValue() );
return testClass1.getValue();
}
}
In this case, if tc1 and tc2 are coming from a factory which creates these objects, I want to know whats the decent way to create instance of AnotherClass
Your problem is with this method:
public TestClass<?> sampleFactory(int i) {
The ? wildcard type means "some type, but I don't know what". So you can get a value of type TestClass<?>, but it's not useful to you, because you can't meaningfully interact with the type ? -- you can't create values of type ? (except for null) and you can't call methods on type ? (except methods of java.lang.Object).
What you really want is something like:
public <T> TestClass<T> sampleFactory(TypeToken<T> typeToken) {
That is, if you want your factory to give you back values parameterized by different types, you need to give it something that tells it what type you want. Unfortunately, int isn't enough -- you may know that i==1 means the type will be Integer, but the compiler doesn't know that.
Your description of your problem is a bit too vague for me to understand what you're really trying to achieve, but my guess is that what you really need is either something like super type tokens or maybe something like Guava's ClassToInstanceMap.
One possible solution is to use raw AnotherTestClass type
public class A {
public static void main(String[] args) {
TestClass<?> tc = new TestClass<Integer>();
AnotherTestClass atc = new AnotherTestClass();
atc.testMethod(tc);
}
}
class TestClass<T> {
// class body here...
}
class AnotherTestClass<K> {
public void testMethod(TestClass<K> param) {
}
}
compiles fine. But it's not good idea to use raw types in general case
Java Doc says:
The type of a constructor, instance method, or non-static field M of a raw type C that is not
inherited from its superclasses or superinterfaces is the erasure of its type in the generic
declaration corresponding to C. The type of a static member of a raw type C is the same as its
type in the generic declaration corresponding to C.
Type erasure comes into picture even though the method's type signature doesn't use any type parameters of the class itself,
This is what your method becomes,
public method testMethod(TestClass param) {
}
Your factory method which returns an object of type TestClass<?>, cannot be accomodated in above method.
Using this one you'll be able to pass parameter to your testMethod:
package stackoverflow;
public class Func {
static class TestClass<T> {
}
static class AnotherTestClass {
public <K> TestClass<K> testMethod(TestClass<K> param) {
return param;
}
}
static class Factory {
public static <E> TestClass<E> sampleFactory(int i) {
if (i == 1)
return (TestClass<E>) new TestClass<Integer>();
if (i == 2)
return (TestClass<E>) new TestClass<Double>();
if (i == 3)
return (TestClass<E>) new TestClass<String>();
throw new IllegalArgumentException();
}
}
public static void main(String[] args) {
new AnotherTestClass().testMethod(Factory.sampleFactory(1));
}
}
The code:
interface Property<T>
{
T get();
}
class BoolProperty implements Property<Boolean>
{
#Override
public Boolean get()
{
return false;
}
}
class StringProperty implements Property<String>
{
#Override
public String get()
{
return "hello";
}
}
class OtherStringProperty implements Property<String>
{
#Override
public String get()
{
return "bye";
}
public String getSpecialValue()
{
return "you are special";
}
}
is used by my class:
class Result<P extends Property<X>, X>
{
P p;
List<X> list;
}
As you see it has two type parameters P and X. Despite of that the X can always be deduced from P but the language requires me to supply both:
Result<BooleanProperty, Boolean> res = new Result<BooleanProperty, Boolean>();
Is there any trick to get rid of the X type parameter? I want just use
Result<BooleanProperty> res = new Result<BooleanProperty>();
Also, I don't want lose type information and use it as:
Result<OtherStringProperty> res = new Result<OtherStringProperty>();
String spec = res.p.getSpecialValue();
String prop = res.list.get(0);
I would change Result class to be something like
class Result<X> {
Property<X> property;
List<X> list;
}
I don't think the compiler can infer X from Property, as your Result class is waiting two definitions for the two generics.
You can't infer the type, but you can add an extra level of indirection:
class BoolProperty implements Property<Boolean>
{
#Override
public Boolean get()
{
return false;
}
}
class Sub<X, P extends Property<X>> {
P p;
List<X> list;
}
class Result<X> extends Sub<X, Property<X>> {
}
Result<Boolean> res = new Result<Boolean>();
List<Boolean> list = res.list;
Boolean b = res.p.get();
List<String> res2 = res.list; // compilation error
There is a similar question whose answer you might find interesting: https://stackoverflow.com/a/4452268/247763
Essentially, there's no real way to get around including the extra generic type, because the compiler can't know what type you're using without it. I'm guessing this defeats the purpose of your approach, but you could try extending Result while specifying the types - something like this:
class BoolResult extends Result<BoolProperty, Boolean> {
// Do stuff
}
Have you tried using the wildcard generic?
class Result<? extends Property<X>>
{
// stuff
}
I am refactoring some legacy code and have come across a problem which I'm sure has a elegant solution - but I can't quite get there.
Initially there were a load of classes which extended an abstract class BaseType. Each of these classes has a enum - XmlElementTag - with values specific to the class:
enum XmlElementTag {value1, value2, value3}
They each also have a method :
private XmlElementTag getTag(String s){
XmlElementTag ret = null;
try {
ret = XmlElementTag.valueOf(s);
} catch (Exception e) {
Log.e(this, s+" is not supported tag");
}
return ret;
}
Every class has this exact same getTag method, but obviously they are all referring to the XmlElementTag enum specific to the class they are in. So, I'd like to get rid of this code duplication if I can.
I thought that maybe I could use a marker interface to solve this problem, so created one as which each XmlElementTag enum now inherits and rewrote the getTag method and put it in the super class.
So I have this in each class:
private XmlElementTag implements GenericTag {value1, value2, value3};
And this in the BaseType superclass:
public interface GenericTag {}
protected GenericTag getTag(String tagName){
XmlElementTag tag = null;
try {
tag = XmlElementTag.valueOf(tagName);
} catch (Exception e) {
Log.e(this, tagName+" is not supported tag");
}
return tag;
}
But again this doesn't work as the BaseType super class doesn't know what XmlElementTag is; Java doesn't allow abstract class variables; and creating this element in the BaseType won't work, as the getTag code will always refer to this enum, rather than the one in the class which extends BaseType.
Can anyone point me in the correct direction?
I guess you could write a static generic helper method that did what getTag does. It would need to use reflection under the hood, and would most likely require you to pass the enumeration's Class object as a parameter.
But IMO, you shouldn't. The getTag() method is kind of wrong-headed. It is turning what is effectively bad input into a null. That's wrong from two perspectives:
In most contexts, "you gave me bad stuff" should not be treated as "you gave me nothing".
If you are not scrupulously careful, those null values are going to come back to bite you as NullPointerExceptions.
So really, your application code should either catch and deal with the IllegalArgumentException that arises when the conversion goes wrong, or it should allow the exception to bubble up to the top where it can be reported as (for instance) an error parsing the input stream.
(I don't think that an enum can either extend or be extended, so I don't think your enums can inherit a generic version of this class.)
You might be able to coalesce the XmlElementTag elements into a single enum and establish an EnumSet apropos to each derived type. There's an example here.
Addendum: In this scheme, getTag() would then become a single method of the combined enum. Each derived class would invoke getTag() using the Set that it considers valid. The method might have a signature such as this:
public static XmlElementTag getTag(Set valid, String s) { ... }
Unfortunately Java enums don't come with a good meta-class (Class is evil). However, all you really need here is the list (array) of the enum values.
As it's a private method, you might as well use composition.
import static java.util.Objects.requireNonNull;
/* pp */ class EnumFinder<E extends Enum<E>> {
private final E[] tags;
protected BaseType(E[] tags) {
this.tags = requireNonNull(tags);
}
public E getTag(String name) {
requireNonNull(name);
for (E tag : tags) {
if (name.equals(tag.name())) {
return tag;
}
}
Log.e(this, name+" is not supported tag"); // (sic)
return null; // (sic)
}
...
}
public class DerivedType {
private static final EnumFinder<XmlElementType> finder = // note, shared
new EnumFinder<>(XmlElementType.values());
...
finder.getTag(name)
...
}
(Create a Map<String,E> if you really want to. Unnecessary for reasonably sized enums.)
If you really want to use inheritance, then that is much the same. (Unfortunately as we are using an array, unless you add more boilerplate to your code, this code will create an unnecessary extra array per instance - probably not a significant issue, but may be.):
/* pp */ abstract class BaseType<E extends Enum<E>> {
private final E[] tags;
protected BaseType(E[] tags) {
this.tags = requireNonNull(tags);
}
public E getTag(String name) {
requireNonNull(name);
for (E tag : tags) {
if (name.equals(tag.name())) {
return tag;
}
}
Log.e(this, name+" is not supported tag"); // (sic)
return null; // (sic)
}
...
}
public class DerivedType extends BaseType<XmlElementType> {
public DerivedType() {
super(XmlElementType.values());
}
...
this.getTag(name)
...
}
You could use generics for that:
The Base is
public abstract class Base {
protected static <T extends Enum<T>> T getTag(Class<T> enumType, String s) {
T ret = null;
try {
ret = Enum.valueOf(enumType, s);
} catch (Exception e) {
System.err.println(s + " is not supported tag");
}
return ret;
}
protected abstract <T extends Enum<T>> T getTag(String s);
}
Your numerous classes have a shorter getTag() (and all the logic is in the Base)
public class ClassA extends Base {
enum XmlElementTag {
UL, LI
}
#Override
protected XmlElementTag getTag(String s) {
return Base.getTag(XmlElementTag.class, s);
}
}
(same thing for ClassB)
I think that you wanted to achieve something like this (correct me if I'm wrong):
interface GenericTag {
public GenericTag fromString(String str) throws IllegalArgumentException;
}
class BaseType {
protected GenericTag getTag(String tagName) {
GenericTag tag = null;
try {
tag = tag.fromString(tagName);
} catch (Exception e) {
Log.e(this, tagName+" tag is not supported");
}
return tag;
}
}
class ConcreteTypeA extends BaseType {
enum XmlElementTag implements GenericTag {
TAG1, TAG2;
public GenericTag fromString(String str) throws IllegalArgumentException {
return XmlElementTag.valueOf(str);
}
}
}
However, that will never work. You would need the fromString method to return an instance of appropriate class (in this case, enum) implementing the GenericTag, but the fromString method has to be performed by that concrete class, which you don't have yet, so you'll get a NullPointerException.
It's a sort of Chicken and Egg Problem! :)
Is it possible to create an instance of a generic type in Java? I'm thinking based on what I've seen that the answer is no (due to type erasure), but I'd be interested if anyone can see something I'm missing:
class SomeContainer<E>
{
E createContents()
{
return what???
}
}
EDIT: It turns out that Super Type Tokens could be used to resolve my issue, but it requires a lot of reflection-based code, as some of the answers below have indicated.
I'll leave this open for a little while to see if anyone comes up with anything dramatically different than Ian Robertson's Artima Article.
You are correct. You can't do new E(). But you can change it to
private static class SomeContainer<E> {
E createContents(Class<E> clazz) {
return clazz.newInstance();
}
}
It's a pain. But it works. Wrapping it in the factory pattern makes it a little more tolerable.
In Java 8 you can use the Supplier functional interface to achieve this pretty easily:
class SomeContainer<E> {
private Supplier<E> supplier;
SomeContainer(Supplier<E> supplier) {
this.supplier = supplier;
}
E createContents() {
return supplier.get();
}
}
You would construct this class like this:
SomeContainer<String> stringContainer = new SomeContainer<>(String::new);
The syntax String::new on that line is a constructor reference.
If your constructor takes arguments you can use a lambda expression instead:
SomeContainer<BigInteger> bigIntegerContainer
= new SomeContainer<>(() -> new BigInteger(1));
I don't know if this helps, but when you subclass (including anonymously) a generic type, the type information is available via reflection. e.g.,
public abstract class Foo<E> {
public E instance;
public Foo() throws Exception {
instance = ((Class)((ParameterizedType)this.getClass().
getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
...
}
}
So, when you subclass Foo, you get an instance of Bar e.g.,
// notice that this in anonymous subclass of Foo
assert( new Foo<Bar>() {}.instance instanceof Bar );
But it's a lot of work, and only works for subclasses. Can be handy though.
You'll need some kind of abstract factory of one sort or another to pass the buck to:
interface Factory<E> {
E create();
}
class SomeContainer<E> {
private final Factory<E> factory;
SomeContainer(Factory<E> factory) {
this.factory = factory;
}
E createContents() {
return factory.create();
}
}
package org.foo.com;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Basically the same answer as noah's.
*/
public class Home<E>
{
#SuppressWarnings ("unchecked")
public Class<E> getTypeParameterClass()
{
Type type = getClass().getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) type;
return (Class<E>) paramType.getActualTypeArguments()[0];
}
private static class StringHome extends Home<String>
{
}
private static class StringBuilderHome extends Home<StringBuilder>
{
}
private static class StringBufferHome extends Home<StringBuffer>
{
}
/**
* This prints "String", "StringBuilder" and "StringBuffer"
*/
public static void main(String[] args) throws InstantiationException, IllegalAccessException
{
Object object0 = new StringHome().getTypeParameterClass().newInstance();
Object object1 = new StringBuilderHome().getTypeParameterClass().newInstance();
Object object2 = new StringBufferHome().getTypeParameterClass().newInstance();
System.out.println(object0.getClass().getSimpleName());
System.out.println(object1.getClass().getSimpleName());
System.out.println(object2.getClass().getSimpleName());
}
}
If you need a new instance of a type argument inside a generic class then make your constructors demand its class...
public final class Foo<T> {
private Class<T> typeArgumentClass;
public Foo(Class<T> typeArgumentClass) {
this.typeArgumentClass = typeArgumentClass;
}
public void doSomethingThatRequiresNewT() throws Exception {
T myNewT = typeArgumentClass.newInstance();
...
}
}
Usage:
Foo<Bar> barFoo = new Foo<Bar>(Bar.class);
Foo<Etc> etcFoo = new Foo<Etc>(Etc.class);
Pros:
Much simpler (and less problematic) than Robertson's Super Type Token (STT) approach.
Much more efficient than the STT approach (which will eat your cellphone for breakfast).
Cons:
Can't pass Class to a default constructor (which is why Foo is final). If you really do need a default constructor you can always add a setter method but then you must remember to give her a call later.
Robertson's objection... More Bars than a black sheep (although specifying the type argument class one more time won't exactly kill you). And contrary to Robertson's claims this does not violate the DRY principal anyway because the compiler will ensure type correctness.
Not entirely Foo<L>proof. For starters... newInstance() will throw a wobbler if the type argument class does not have a default constructor. This does apply to all known solutions though anyway.
Lacks the total encapsulation of the STT approach. Not a big deal though (considering the outrageous performance overhead of STT).
You can do this now and it doesn't require a bunch of reflection code.
import com.google.common.reflect.TypeToken;
public class Q26289147
{
public static void main(final String[] args) throws IllegalAccessException, InstantiationException
{
final StrawManParameterizedClass<String> smpc = new StrawManParameterizedClass<String>() {};
final String string = (String) smpc.type.getRawType().newInstance();
System.out.format("string = \"%s\"",string);
}
static abstract class StrawManParameterizedClass<T>
{
final TypeToken<T> type = new TypeToken<T>(getClass()) {};
}
}
Of course if you need to call the constructor that will require some reflection, but that is very well documented, this trick isn't!
Here is the JavaDoc for TypeToken.
From Java Tutorial - Restrictions on Generics:
Cannot Create Instances of Type Parameters
You cannot create an instance of a type parameter. For example, the following code causes a compile-time error:
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
As a workaround, you can create an object of a type parameter through reflection:
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.getDeclaredConstructor().newInstance(); // OK
list.add(elem);
}
You can invoke the append method as follows:
List<String> ls = new ArrayList<>();
append(ls, String.class);
Think about a more functional approach: instead of creating some E out of nothing (which is clearly a code smell), pass a function that knows how to create one, i.e.
E createContents(Callable<E> makeone) {
return makeone.call(); // most simple case clearly not that useful
}
When you are working with E at compile time you don't really care the actual generic type "E" (either you use reflection or work with base class of generic type) so let the subclass provide instance of E.
abstract class SomeContainer<E>
{
abstract protected E createContents();
public void doWork(){
E obj = createContents();
// Do the work with E
}
}
class BlackContainer extends SomeContainer<Black>{
protected Black createContents() {
return new Black();
}
}
Here is an option I came up with, it may help:
public static class Container<E> {
private Class<E> clazz;
public Container(Class<E> clazz) {
this.clazz = clazz;
}
public E createContents() throws Exception {
return clazz.newInstance();
}
}
EDIT: Alternatively you can use this constructor (but it requires an instance of E):
#SuppressWarnings("unchecked")
public Container(E instance) {
this.clazz = (Class<E>) instance.getClass();
}
If you want not to type class name twice during instantiation like in:
new SomeContainer<SomeType>(SomeType.class);
You can use factory method:
<E> SomeContainer<E> createContainer(Class<E> class);
Like in:
public class Container<E> {
public static <E> Container<E> create(Class<E> c) {
return new Container<E>(c);
}
Class<E> c;
public Container(Class<E> c) {
super();
this.c = c;
}
public E createInstance()
throws InstantiationException,
IllegalAccessException {
return c.newInstance();
}
}
Java unfortunatly does not allow what you want to do. See the official workaround :
You cannot create an instance of a type parameter. For example, the following code causes a compile-time error:
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
As a workaround, you can create an object of a type parameter through reflection:
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance(); // OK
list.add(elem);
}
You can invoke the append method as follows:
List<String> ls = new ArrayList<>();
append(ls, String.class);
You can use:
Class.forName(String).getConstructor(arguments types).newInstance(arguments)
But you need to supply the exact class name, including packages, eg. java.io.FileInputStream. I used this to create a math expressions parser.
Hope this's not too late to help!!!
Java is type-safe, meaning that only Objects are able to create instances.
In my case I cannot pass parameters to the createContents method. My solution is using extends unlike the answer below.
private static class SomeContainer<E extends Object> {
E e;
E createContents() throws Exception{
return (E) e.getClass().getDeclaredConstructor().newInstance();
}
}
This is my example case in which I can't pass parameters.
public class SomeContainer<E extends Object> {
E object;
void resetObject throws Exception{
object = (E) object.getClass().getDeclaredConstructor().newInstance();
}
}
Using reflection create run time error, if you extends your generic class with none object type. To extends your generic type to object convert this error to compile time error.
Use the TypeToken<T> class:
public class MyClass<T> {
public T doSomething() {
return (T) new TypeToken<T>(){}.getRawType().newInstance();
}
}
I thought I could do that, but quite disappointed: it doesn't work, but I think it still worths sharing.
Maybe someone can correct:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface SomeContainer<E> {
E createContents();
}
public class Main {
#SuppressWarnings("unchecked")
public static <E> SomeContainer<E> createSomeContainer() {
return (SomeContainer<E>) Proxy.newProxyInstance(Main.class.getClassLoader(),
new Class[]{ SomeContainer.class }, new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?> returnType = method.getReturnType();
return returnType.newInstance();
}
});
}
public static void main(String[] args) {
SomeContainer<String> container = createSomeContainer();
[*] System.out.println("String created: [" +container.createContents()+"]");
}
}
It produces:
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
at Main.main(Main.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Line 26 is the one with the [*].
The only viable solution is the one by #JustinRudd
An imporovement of #Noah's answer.
Reason for Change
a] Is safer if more then 1 generic type is used in case you changed the order.
b] A class generic type signature changes from time to time so that you will not be surprised by unexplained exceptions in the runtime.
Robust Code
public abstract class Clazz<P extends Params, M extends Model> {
protected M model;
protected void createModel() {
Type[] typeArguments = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
for (Type type : typeArguments) {
if ((type instanceof Class) && (Model.class.isAssignableFrom((Class) type))) {
try {
model = ((Class<M>) type).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
Or use the one liner
One Line Code
model = ((Class<M>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]).newInstance();
what you can do is -
First declare the variable of that generic class
2.Then make a constructor of it and instantiate that object
Then use it wherever you want to use it
example-
1
private Class<E> entity;
2
public xyzservice(Class<E> entity) {
this.entity = entity;
}
public E getEntity(Class<E> entity) throws InstantiationException, IllegalAccessException {
return entity.newInstance();
}
3.
E e = getEntity(entity);
Here's an implementation of createContents that uses TypeTools (which I authored) to resolve the raw class represented by E:
E createContents() throws Exception {
return TypeTools.resolveRawArgument(SomeContainer.class, getClass()).newInstance();
}
This approach only works if SomeContainer is subclassed so the actual value of E is captured in a type definition:
class SomeStringContainer extends SomeContainer<String>
Otherwise the value of E is erased at runtime and is not recoverable.
As you said, you can't really do it because of type erasure. You can sort of do it using reflection, but it requires a lot of code and lot of error handling.
If you mean
new E()
then it is impossible. And I would add that it is not always correct - how do you know if E has public no-args constructor?
But you can always delegate creation to some other class that knows how to create an instance - it can be Class<E> or your custom code like this
interface Factory<E>{
E create();
}
class IntegerFactory implements Factory<Integer>{
private static int i = 0;
Integer create() {
return i++;
}
}
return (E)((Class)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
You can achieve this with the following snippet:
import java.lang.reflect.ParameterizedType;
public class SomeContainer<E> {
E createContents() throws InstantiationException, IllegalAccessException {
ParameterizedType genericSuperclass = (ParameterizedType)
getClass().getGenericSuperclass();
#SuppressWarnings("unchecked")
Class<E> clazz = (Class<E>)
genericSuperclass.getActualTypeArguments()[0];
return clazz.newInstance();
}
public static void main( String[] args ) throws Throwable {
SomeContainer< Long > scl = new SomeContainer<>();
Long l = scl.createContents();
System.out.println( l );
}
}
Here is an improved solution, based on ParameterizedType.getActualTypeArguments, already mentioned by #noah, #Lars Bohl, and some others.
First small improvement in the implementation. Factory should not return instance, but a type. As soon as you return instance using Class.newInstance() you reduce a scope of usage. Because only no-arguments constructors can be invoke like this. A better way is to return a type, and allow a client to choose, which constructor he wants to invoke:
public class TypeReference<T> {
public Class<T> type(){
try {
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
if (pt.getActualTypeArguments() == null || pt.getActualTypeArguments().length == 0){
throw new IllegalStateException("Could not define type");
}
if (pt.getActualTypeArguments().length != 1){
throw new IllegalStateException("More than one type has been found");
}
Type type = pt.getActualTypeArguments()[0];
String typeAsString = type.getTypeName();
return (Class<T>) Class.forName(typeAsString);
} catch (Exception e){
throw new IllegalStateException("Could not identify type", e);
}
}
}
Here is a usage examples. #Lars Bohl has shown only a signe way to get reified geneneric via extension. #noah only via creating an instance with {}. Here are tests to demonstrate both cases:
import java.lang.reflect.Constructor;
public class TypeReferenceTest {
private static final String NAME = "Peter";
private static class Person{
final String name;
Person(String name) {
this.name = name;
}
}
#Test
public void erased() {
TypeReference<Person> p = new TypeReference<>();
Assert.assertNotNull(p);
try {
p.type();
Assert.fail();
} catch (Exception e){
Assert.assertEquals("Could not identify type", e.getMessage());
}
}
#Test
public void reified() throws Exception {
TypeReference<Person> p = new TypeReference<Person>(){};
Assert.assertNotNull(p);
Assert.assertEquals(Person.class.getName(), p.type().getName());
Constructor ctor = p.type().getDeclaredConstructor(NAME.getClass());
Assert.assertNotNull(ctor);
Person person = (Person) ctor.newInstance(NAME);
Assert.assertEquals(NAME, person.name);
}
static class TypeReferencePerson extends TypeReference<Person>{}
#Test
public void reifiedExtenension() throws Exception {
TypeReference<Person> p = new TypeReferencePerson();
Assert.assertNotNull(p);
Assert.assertEquals(Person.class.getName(), p.type().getName());
Constructor ctor = p.type().getDeclaredConstructor(NAME.getClass());
Assert.assertNotNull(ctor);
Person person = (Person) ctor.newInstance(NAME);
Assert.assertEquals(NAME, person.name);
}
}
Note: you can force the clients of TypeReference always use {} when instance is created by making this class abstract: public abstract class TypeReference<T>. I've not done it, only to show erased test case.
Note that a generic type in kotlin could come without a default constructor.
implementation("org.objenesis","objenesis", "3.2")
val fooType = Foo::class.java
var instance: T = try {
fooType.newInstance()
} catch (e: InstantiationException) {
// Use Objenesis because the fooType class has not a default constructor
val objenesis: Objenesis = ObjenesisStd()
objenesis.newInstance(fooType)
}
Withou default constructor
Objenesis
I was inspired with Ira's solution and slightly modified it.
abstract class SomeContainer<E>
{
protected E createContents() {
throw new NotImplementedException();
}
public void doWork(){
E obj = createContents();
// Do the work with E
}
}
class BlackContainer extends SomeContainer<Black>{
// this method is optional to implement in case you need it
protected Black createContents() {
return new Black();
}
}
In case you need E instance you can implement createContents method in your derived class (or leave it not implemented in case you don't need it.
As you mentioned, you can't get an instance from generics. IMO, you have to change the design and make use of FACTORY METHOD design pattern. In this manner you don't need your class or method to be generics:
class abstract SomeContainer{
Parent execute(){
return method1();
}
abstract Parent method1();
}
class Child1 extends Parent{
Parent method1(){
return new Parent();
}
}
class Child2 extends Parent{
Parent method1(){
return new Child2();
}
}
You can with a classloader and the class name, eventually some parameters.
final ClassLoader classLoader = ...
final Class<?> aClass = classLoader.loadClass("java.lang.Integer");
final Constructor<?> constructor = aClass.getConstructor(int.class);
final Object o = constructor.newInstance(123);
System.out.println("o = " + o);