Dynamic Generic Typing in Java

Dynamic Generic Typing in Java

Java generics are not C++ Templates.

Java generics are a compile time feature, not a run time feature.

Here is a link to the Java generics Tutorial.

This can never work with Java:

new Record<object.getClass()>(object);

You must either use polymorphism (say, each object implements a known interface) or RTTI (instanceof or Class.isAssignableFrom()).

You might do this:

     class Record
{
public Record(String blah) { ... }
public Record(Integer blah) { ... }
... other constructors.
}

or you might use the Builder pattern.

Static method in a generic class?

You can't use a class's generic type parameters in static methods or static fields. The class's type parameters are only in scope for instance methods and instance fields. For static fields and static methods, they are shared among all instances of the class, even instances of different type parameters, so obviously they cannot depend on a particular type parameter.

It doesn't seem like your problem should require using the class's type parameter. If you describe what you are trying to do in more detail, maybe we can help you find a better way to do it.

How to change an object's generic type dynamically in Java?

How to change an object's generic type dynamically in Java?

Generics are compilation features to improve the code typesafety.

so it is just not possible.

The cleaner way would be to declare distinct FlatFileItemReader beans with the generic it needs.

The @Bean annotation may be helpful there.

@Bean
public FlatFileItemReader<Foo> readerFoo(){
return new FlatFileItemReader<>();
}

@Bean
public FlatFileItemReader<Bar> readerBar(){
return new FlatFileItemReader<>();
}

And now inject them where you need :

@Autowired
FlatFileItemReader<Bar> readerBar;

@Autowired
FlatFileItemReader<Foo> readerFoo;

Dynamically return with the type of calling class using generics in Java

There are two ways to do this, but I don't recommend either.

Approach one: generics

Specifically, recursive ones (that refer back to the generic class itself):

public class ClassA<R extends ClassA<R>> { // note the recursive nature
public ArrayList<String> v1 = new ArrayList<>();

@SuppressWarnings("unchecked")
protected R self() {
return (R) this;
}

public R addOnce(String s1) {
v1.add(s1);
return self();
}
}

If you don't like that SuppressWarnings (and you shouldn't! they can hide bugs), you can get around this by making an abstract class AbstractClassA, with a protected abstract R self() every subclass overrides:

// AbstractClassA looks like ClassA above; it contains addOnce
class ClassA extends AbstractClassA<ClassA> {
@Override
public ClassA self() {
return this;
}
}

class ClassB extends AbstractClassA<ClassB> {
ClassB addTwice(String s2) {
...
return this;
}
}

That does mean that most of your use cases will use a wildcarded AbstractClassA<?> type. Besides that ugliness, this gets hairy if you try to serialize these instances. AbstractClassA.class returns a Class<AbstractClassA>, not a Class<AbstractClassA<?>>, which can force you to do more unchecked casts.

Also, subclasses of AbstractClassA don't inherit that <R> type, so if you want to define new methods that keep the pattern (in ClassB, for instance), you'll have to repeat the pattern with a new generic parameter in each one. My prediction is that you'll regret it.

Approach two: override each method

The other way is to manually override all of the methods in the base class. When you override a method, you can have it return a subclass of the original method's return type. So:

public class ClassA {

public ArrayList<String> v1 = new ArrayList<>();

public ClassA addOnce(String s1) {
v1.add(s1);
return this;
}

}
public class ClassB extends ClassA {

public ClassB addOnce(String s2) {
super.addOnce(s2);
return this; // same reference as in the super method, but now typed to ClassB
}
...

}

This method doesn't have any hidden gotchas, like the first approach does. It works just like you think it would. It's just a pain, and it means that every time you add a method to ClassA, you have to add that method to ClassB (and ClassC, etc) as well, if you want things to keep working. If you don't have control over ClassB/C/etc (for instance, if you're publishing an API), then that could present a problem, and make your API feel half-baked.

Approach three: Chain from more-specific subclasses first

This one isn't really an answer to your question, but rather a pattern that gets at the same problem. The idea is to keep ClassA and ClassB just as you have them, but always call ClassB's methods first:

new ClassB().addTwice("2").addOnce("1");

This approach works fine, but it's a bit awkward. Most of the time, people think in terms of first setting things on the base class, and then setting subclass-specific things on subclasses. If you you're okay with reversing that, and you really want these chained methods, this is probably the approach I would pick. But my real suggestion is:

My suggestion: forget it

Java just doesn't handle these kinds of method chains well. I would suggest you just forget the whole thing, and don't try to fight the language on this point. Make the methods return void and put each call on its own line. Having worked with code that's tried the first and third approaches, I found the ugliness around it gets old really quickly, and is generally more of a pain than it's worth. (I've never seen the second approach works, because it's such a pain off the bat that nobody wants to even try it. :) )

Java Generics- Can I create a list dynamically based on variable type

You can do this:

Cacheable instance = getCacheable(someInput);
List<? extends Cacheable> l = new ArrayList<>();
l = Collections.checkedList(l, instance.getClass());

Because of type erasure, all information accessible at compile time is lost at runtime.
The checkedList method will ensure that your list will receive only instances of the class of instance variable.

UPDATE:
You can do this also:

public static <T extends Cacheable> MyOwnCustomGeneric<T> createMyOwnCustomGeneric(Class<T> type) {
return new MyOwnCustomGeneric<T>();
}

// ...
IMyOwnCustomGeneric foo = createMyOwnCustomGeneric(instance.getClass());


Related Topics



Leave a reply



Submit