Java - Instantiating generic typed class - java

I have a class for example
public class Example<T> {...}
I would like to instantiate class Example with a specific type class which I know. Pseudocode would look something like that
public Example<T> createTypedExample(Class exampleClass, Class typeClass) {
exampleClass.newInstance(typeClass); // made-up
}
So that this would give me same result
Example<String> ex = new Example<String>();
ex = createTypedExample(Example.class, String.class);
Is it possible in Java?

Since, the return type i.e. the class of the new instance is fixed; there's no need to pass it to the method. Instead, add a static factory method to your Example class as
public class Example<T> {
private T data;
static <T> Example<T> newTypedExample(Class<T> type) {
return new Example<T>();
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
Now, here's how you would create generic Example instances.
// String
Example<String> strTypedExample = Example.newTypedExample(String.class);
strTypedExample.setData("String Data");
System.out.println(strTypedExample.getData()); // String Data
// Integer
Example<Integer> intTypedExample = Example.newTypedExample(Integer.class);
intTypedExample.setData(123);
System.out.println(intTypedExample.getData()); // 123

Related

Trying to write a generic enum util class in groovy

Problem
We have multiple enum types that have some public static EnumType valueOfText(String text), for the purpose of mapping the contents of a data file cell to enum.
I'm trying to write a generic enum util that takes a comma-separated string and return multiple enum values. For example, we have the following enum:
public enum Frequency {
SEMI_ANNUAL("S"), MONTHLY("M"), QUARTERLY("Q"), ANNUAL("A")
public final String textValue;
public Frequency(String textValue) {
this.textValue = textValue;
}
public static Frequency valueOfText(String textValue) {
for (Frequency frequency : values()) {
if (frequency.textValue.equals(textValue))
return frequency;
}
return null;
}
}
and string "A,S" which we want to convert to [Frequency.ANNUAL, Frequency.SEMI_ANNUAL].
Attempted solution
I create some EnumUtils like so:
import java.util.stream.Collectors
public final class EnumUtils {
public static final String LIST_SEPARATOR = ",";
public static <E extends Enum<E>> List<E> CreateFromText(String text) {
List<String> textList = text.split(this.LIST_SEPARATOR)
return textList.stream()
.map { txt ->
E.valueOfText(txt)
}
.collect(Collectors.toList())
}
}
What happen after said solution
We go to use it, like this:
EnumUtils.CreateFromText<Frequency>(row[3])
and the IDE compain, immediately, about the <>.
How can we specify enum type in this?
In Groovy you can do it if you pass the actual Class instead of just using a type parameter.
enum Frequency {
SEMI_ANNUAL("S"), MONTHLY("M"), QUARTERLY("Q"), ANNUAL("A")
final String textValue;
Frequency(String textValue) {
this.textValue = textValue;
}
static Frequency valueOfText(String textValue) {
return values().find { it.textValue == textValue }
}
}
final class EnumUtils {
static <E extends Enum<E>> List<E> createFromText(Class<E> clazz, String text) {
return text.split(",").collect { clazz.valueOfText(it) }
}
}
EnumUtils.createFromText(Frequency, "S,M")
The same idea won't work in Java, since clazz won't have valueOfText at compile time.
Perhaps the Util class doesn't save you much typing, though:
"S,M".split(",").collect(Frequency.&valueOfText)

Using generics and Class of an object in map

I have following class/interface structure (can't modify the source):
public interface Car {}
public class CarA implements Car{
public String getASpecifics() {...}
}
public class CarB implements Car{
public String getBSpecifics() {...}
}
public class Summary {...}
I want to have a generic way of creating Summray for concrete implementations of Car interface which will be open to adding new implementations. My approach is following:
public CarSummarizer {
public interface SummaryGenerator<T extends Car> {
Summary generateSummary(T car);
}
static {
SummaryGenerator<CarA> aGen = c -> {... c.getASpecifics(); ...}
SummaryGenerator<CarB> bGen = c -> {... c.getBSpecifics(); ...}
}
}
Now I'd like to store aGen and bgen in a Map. I want to parametrize it so that I can offer one only public static method which accepts Car car and based on it's class object (car.getClass()) uses correct SummaryGenerator implemenation. That should look something like following:
public static Summary getSummaryForCar(Car car) {
return map.get(car.getClass()).generateSummary(car);
}
I don't know how to declare and instantiate that Map so that it's fully type-safe (i.e. doesn't allow inserting pair (CarC.class, SummaryGenerator<CarD>)). I'd like something like this:
public static <T extends Car> Map<Class<T>, SummaryGenerator<T>> map = new LinkedHashMap<>();
static {
// after instantiation
map.put(CarA.class, aGen);
map.put(CarB.class, BGen);
}
// also support following
public static <T extends Car> void addSummaryGenerator(T car, SummaryGenerator<T> sg) {
map.put(car.getClass(), sg);
}
That doesn't work because generics can't be declared on variables like they can be on functions.
I guess I could define new class public class SummarizerStorage<T extends Car> and the place map inside and just delegate calls. That seems like an overkill and ugly. I feel like it should be done somehow directly.
Declaring map like Map<Class<? extends Car>, SummaryGenerator<? extends Car>> would allow paring of Class<> and SummaryGenerator<> of sibling types. I want to allow only same type pairs.
You can do this with compile-time safety if you wrap your map and only allow to put entries of which the value SummaryGenerator<T> matches a key of Class<T>. To get the SummaryGenerator you need to cast but since you ensured that you only added entries that actually can be cast to SummaryGenerator<T>, this is safe to do. If you try to add an incompatible SummaryGenerator for a given implementation of Car, it would result in a compile error.
public class SummaryGeneratorStorage {
private static final Map<Class<? extends Car>, CarSummarizer.SummaryGenerator<? extends Car>> map = new HashMap<>();
// provides type safety to only add a SummaryGenerator<T> for a key of Class<T>
public static <T extends Car> void add(Class<T> clazz, CarSummarizer.SummaryGenerator<T> sg) {
map.put(clazz, sg);
}
#SuppressWarnings("unchecked")
public static <T extends Car> CarSummarizer.SummaryGenerator<T> get(T car) {
// this cast is safe since the add-method only
// allows a SummaryGenerator<T> to be added for a key of Class<T>
return (CarSummarizer.SummaryGenerator<T>) map.get(car.getClass());
}
private SummaryGeneratorStorage() { }
}
In order to get a Summary, you retrieve the registered SummaryGenerator for the Car and call the implemented generateSummary method. If no SummaryGenerator is found for the passed implementation of Car, just throw an exception or handle it a different way. Note that the signature of add takes a Class and not a Car object since we don't need an instance at this point to make the reference to an implementation of Car.
public class CarSummarizer {
public interface SummaryGenerator<T extends Car> {
Summary generateSummary(T car);
}
static {
// here you cannot pass incompatible implementations of Car (compile-time safety)
SummaryGenerator<CarA> aGen = c -> new Summary(c.getASpecifics());
SummaryGeneratorStorage.add(CarA.class, aGen); // with variable
SummaryGeneratorStorage.add(CarB.class, c -> new Summary(c.getBSpecifics())); // direct
}
public static <T extends Car> Summary getSummary(T car) {
SummaryGenerator<T> generator = SummaryGeneratorStorage.get(car);
if (generator != null) {
return generator.generateSummary(car);
} else {
throw new IllegalArgumentException("no summary generator found");
}
}
}
Here is a test class for the above code. A simple Summary containing a name-field was used and the implementations of Car return A, B or C in their getXSpecifics() methods:
public class CarSummarizerTest {
#Test
public void testCarA() {
CarA car = new CarA();
Summary summary = CarSummarizer.getSummary(car);
Assert.assertEquals(car.getASpecifics(), summary.getName());
}
#Test
public void testCarB() {
CarB car = new CarB();
Summary summary = CarSummarizer.getSummary(car);
Assert.assertEquals(car.getBSpecifics(), summary.getName());
}
#Test
public void testCarC() {
CarC car = new CarC();
Assert.assertThrows(IllegalArgumentException.class, () -> {
CarSummarizer.getSummary(car);
});
}
}
For completeness the other classes:
public class CarA implements Car {
public String getASpecifics() { return "A"; }
}
public class CarB implements Car {
public String getBSpecifics() { return "B"; }
}
public class CarC implements Car {
public String getCSpecifics() { return "C"; }
}
public class Summary {
private final String name;
public Summary(String name) { this.name = name; }
public String getName() { return name; }
}

Lambda representing a getter method from either a parent class or a child class

I have some code below representing a parent and child Pojo, and a simple validator that pulls two values off them representing ranges, to verify that start < end. I want to validator to be generic enough that it can accept two field getter methods at construction time, and then be able to be passed a POJO to perform the range check on. However, I have been unable to get this to type check properly. I have tried having the validator constructor taking all of the following:
Function<Pojo, Integer> //Fails on constructing vlad2 - "Incompatible types in lambda expression: Expected Pojo but found ExtendedPojo".
Function<? extends Pojo, Integer> //Fails on getRangeStart.apply(pojo) - "(capture<? extends Pojo>) in Function cannot be applied to Pojo"
Function<Object, Integer> //Fails on constructing both vlad and vlad2 - "Incompatible types in lambda expression: Expected Object but found ExtendedPojo"
Code:
import java.util.function.Function;
class Pojo {
private Integer rangeOneStart;
private Integer rangeOneEnd;
public Pojo(Integer rangeOneStart, Integer rangeOneEnd) {
this.rangeOneStart = rangeOneStart;
this.rangeOneEnd = rangeOneEnd;
}
public Integer getRangeOneStart() {
return rangeOneStart;
}
public Integer getRangeOneEnd() {
return rangeOneEnd;
}
}
class ExtendedPojo extends Pojo {
private Integer rangeTwoStart;
private Integer rangeTwoEnd;
public ExtendedPojo(Integer rangeOneStart, Integer rangeOneEnd, Integer rangeTwoStart, Integer rangeTwoEnd) {
super(rangeOneStart, rangeOneEnd);
this.rangeTwoStart = rangeTwoStart;
this.rangeTwoEnd = rangeTwoEnd;
}
public Integer getRangeTwoStart() {
return rangeTwoStart;
}
public Integer getRangeTwoEnd() {
return rangeTwoEnd;
}
}
interface SomeValidatorInterface<T> {
boolean isValid(T obj);
}
class MyValidator implements SomeValidatorInterface<Pojo> {
private Function<Pojo, Integer> getRangeStart;
private Function<Pojo, Integer> getRangeEnd;
MyValidator(Function<Pojo, Integer> getRangeStart, Function<Pojo, Integer> getRangeEnd) {
this.getRangeStart = getRangeStart;
this.getRangeEnd = getRangeEnd;
}
#Override
public boolean isValid(Pojo pojo) {
Integer start = getRangeStart.apply(pojo);
Integer end = getRangeEnd.apply(pojo);
return end > start;
}
}
class Main {
public static void main(String args[]) {
ExtendedPojo pojo = new ExtendedPojo(1,2,3,4);
MyValidator vlad = new MyValidator(Pojo::getRangeOneStart, Pojo::getRangeOneEnd);
System.out.println(vlad.isValid(pojo));
MyValidator vlad2 = new MyValidator(ExtendedPojo::getRangeTwoStart, ExtendedPojo::getRangeTwoEnd);
System.out.println(vlad2.isValid(pojo));
}
}
Since the validator is being used per instance just provide a specific instance method as Supplier<Integer>
MyValidator(Supplier<Integer> getRangeStart, Supplier<Integer> getRangeEnd) {
this.getRangeStart = getRangeStart;
this.getRangeEnd = getRangeEnd;
}
// ...
ExtendedPojo pojo = new ExtendedPojo(1,2,3,4);
MyValidator vlad = new MyValidator(pojo::getRangeOneStart, pojo::getRangeOneEnd);
If you don't want to use such specific construction you need to move the range getter to the common interface or at least the Pojo class and override this in ExtendedPojo

Java Generic type flexibility

So, lets say I have an enum, "Data".
public enum Data {
FIRSTNAME(String.class, "John");
private final Class<?> defaultClass;
private final Object defaultData;
Data(Class<?> clazz, Object data) {
this.defaultClass = clazz;
this.defaultData = data;
}
public Class<?> getDataClass() {
return this.defaultClass;
}
}
Would it be possible to create a method that gets its return type based on the passed Data enum's getDataClass() response? Ie like this:
//This code obviously won't work, it's just another way of showing this.
public [data.getDataClass()] getData(Data data) {
//Return the data.
}

'X.class' to get it's 'X' type?

I have written simple container that registers a class and it's interface and has a method to create object from that information like this:
public class DIContainer {
protected static DIContainer instance;
protected Hashtable<Class<?>, Class<?>> classMap;
protected DIContainer(){
this.classMap = new Hashtable<Class<?>, Class<?>>();
}
public static DIContainer getInstance(){
if (DIContainer.instance == null)
DIContainer.instance = new DIContainer();
return DIContainer.instance;
}
public void regClass(Class<?> interf, Class<?> classToReg){
this.classMap.put(interf, classToReg);
}
public Object create(Class<?> interf) throws Exception{
if(!this.classMap.containsKey(interf))
throw new Exception("No such class registered with "+interf.getName()+" interface");
return this.classMap.get(interf).newInstance();
}
}
But I want before creating new instance to bypass it to proxy, for it to create, so I have this proxy class:
public class MyProxy implements InvocationHandler
{
private Map map;
private Object obj;
public static Object newInstance(Map map, Object obj, Class[] interfaces)
{
return Proxy.newProxyInstance(map.getClass().getClassLoader(),
interfaces,
new MyProxy(map, obj));
}
public MyProxy(Map map, Object obj)
{
this.map = map;
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws
Throwable
{
try {
return m.invoke(obj, args);
} catch (NoSuchMethodError e)
{
//Object result;
String methodName = m.getName();
if (methodName.startsWith("get"))
{
String name = methodName.substring(methodName.indexOf("get")+3);
return map.get(name);
}
else if (methodName.startsWith("set"))
{
String name = methodName.substring(methodName.indexOf("set")+3);
map.put(name, args[0]);
return null;
}
else if (methodName.startsWith("is"))
{
String name = methodName.substring(methodName.indexOf("is")+2);
return(map.get(name));
}
return null;
}
}
}
But for proxy class I need to provide type of class and it's interface, but I only have it's information with X.class. Can get the type (for example if it's class X) X, when I have X.class? Maybe I'm doing this the wrong way and I need to change something in order for it to work, but right now I figured I need to get that class type, so then I could provide it for proxy?
Because if I would right something like this:
X.class x;
I would get error. So I need to write like this X x;, but I only have X.class
Update:
To explain it simply, is it possible to get this:
X obj;
when you only have X.class (with X.class.newInstance it would instantiate it (like with new?), but I need not instantiated obj yet).
Update2
I tried this:
Object x = (Object) MyProxy.newInstance(map, this.classMap.get(interf).newInstance(), new Class[] {this.classMap.get(interf)});
But then I get this error:
Exception in thread "main" java.lang.IllegalArgumentException: class lab.X is not visible from class loader
My class X looks like this:
public class X implements I{
String name;
X(){}
#Override
public String getName() {
return name;
}
#Override
public void setName(String name) {
this.name = name;
}
}
and it's interface looks like this:
public interface I {
public String getName();
public void setName(String name);
}
If I understand correctly, you are trying to instantiate an element of the class X.class? If that is the case, all you need to do is call X.class.newInstance().
java.lang.IllegalArgumentException: class lab.X is not visible from
class loader
Isn't this error message quite clear? You need to make sure that the same class loader is being used.
In here:
public static Object newInstance(Map map, Object obj, Class[] interfaces)
{
return Proxy.newProxyInstance(map.getClass().getClassLoader(),
interfaces,
new MyProxy(map, obj));
}
you shouldn't be using the class loader of the map, I'd think you should use class loader of the target object or pass the proper class loader as a separate argument.
I think there are other problems in your approach as well, such as not synchronizing your container creation and not using generics for your proxy type.
For the first part, class DIContainer, it would be better to use:
protected final Map<Class<?>, Class<?>> classMap;
protected DIContainer() {
classMap = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>());
}
public <I> void regClass(Class<I> interf, Class<? extends I> classToReg) {
this.classMap.put(interf, classToReg);
}
public <T> T create(Class<T> interf) throws Exception {
Class<?> implClass = classMap.get(interf);
if (implClass == null) {
throw new Exception("No such class registered with " + interf.getName()
+ " interface");
}
Constructor<?> c = implClass.getConstructor();
c.setAccessible(true); // If default constructor not public
return interf.cast(c.newInstance());
}
Safe typing, though still partly at run-time.
More or less obsolete Hashtable replaced by equivalent
Calling newInstance on the class bypasses exceptions thrown on getting the default constructor and doing that one's newInstance.
The second part of the question: I fail to understand it; the interface class(es) is what is proxied. In the create above you could easily proxy Class<T> and yield a (seemingly) T object. And you could delegate in the proxy class to an T object created as in the create above.

Categories

Resources