How to initializing Class<T> at interface default method? - java

I have an interface:
public interface ITransformer<S,T>{
public void transform(S source,T target);
default String getTransformerName(){
Class<S> s;
Class<T> t;
return s.getName() + t.getName(); //*********
}
}
the error message the starred line:
The local variable s may not have been initialized
The local variable t may not have been initialized
I would like to use this method to return a string with [S.classname][T.classname] . Please let me know how to achieve this or is this impossible to do at interface ?
Update: Jan 12
My purpose of doing this is due to the fact that this class will be in framework and I want to reduce the human error as much as possible.. I am changing the code as follows:
public interface ITransformer<S,T>{
public void transform(S source,T target);
public FieldEntry<S, T> getTransformerName();
}
public class FieldEntry<S,T> implements Comparable<FieldEntry> {
private Class<S> s;
private Class<T> t;
public FieldEntry(Class<S> s,Class<T> t){
this.s = s;
this.t = t;
}
public String getEntryName(){
return s.getName() + t.getName();
}
#Override
public int compareTo(FieldEntry entry) {
if(entry == null) throw new IllegalArgumentException("The argument to compare cannot be null!");
return entry.getEntryName().compareTo(this.getEntryName());
}
}

In order to demonstrate why this can’t work, you may change your class to
public interface ITransformer<S,T>{
public void transform(S source,T target);
static <In,Out> ITransformer<In,Out> noOp() {
return (source,target) -> {};
}
static void main(String... arg) {
ITransformer<String,Integer> t1 = noOp();
ITransformer<Long,Thread> t2 = noOp();
System.out.println(t1 == (Object)t2);
}
}
Running this will print true. In other words, both functions are represented by the same instances, so there can’t be and property allowing to recognize their different type.
Generally, when two functions (lambda expressions or method references) exhibit the same behavior, a JVM may represent them by the same implementation type or even the same instance.
Even for non-interface classes, this doesn’t work due to Type Erasure. It only works when you have a reifiable (i.e. non-generic) type extending or implementing a generic type.

It's a little bit dangerous and I wouldn't used this in production (because you should cover in your code all possible use cases of your interface), but you can use reflection for it:
public interface ITransformer<S, T> {
public void transform(S source, T target);
default String getTransformerName() {
Type[] genericInterfaces = this.getClass().getGenericInterfaces();
ParameterizedType parameterizedType = null;
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType paramInterface = (ParameterizedType) genericInterface;
if (paramInterface.getRawType().equals(ITransformer.class)) {
parameterizedType = paramInterface;
break;
}
}
}
if (parameterizedType == null) {
throw new IllegalStateException("!");
}
return parameterizedType.getActualTypeArguments()[0].getTypeName() + parameterizedType.getActualTypeArguments()[1].getTypeName();
}
}
public class StringToIntegerTransfomer implements ITransformer<String, Integer> {
#Override
public void transform(String source, Integer target) {
}
}
public interface StringToNumberTransfomer<T extends Number> extends ITransformer<String, T> {
}
public class StringToLongTransfomer implements StringToNumberTransfomer<Long>, ITransformer<String, Long> {
#Override
public void transform(String source, Long target) {
}
}
#Test
public void test() {
ITransformer<String, Integer> intTransformer = new StringToIntegerTransfomer();
ITransformer<String, Long> longTransformer = new StringToLongTransfomer();
ITransformer<String, String> stringTransformer = new ITransformer<String, String>() {
#Override
public void transform(String source, String target) {
}
};
ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>() {
#Override
public void transform(String source, Double target) {
}
};
System.out.println(String.format("intTransformer: %s", intTransformer.getTransformerName()));
System.out.println(String.format("longTransformer: %s", longTransformer.getTransformerName()));
System.out.println(String.format("stringTransformer: %s", stringTransformer.getTransformerName()));
System.out.println(String.format("doubleTransformer: %s", doubleTransformer.getTransformerName()));
}
Output for this snippet:
intTransformer: java.lang.Stringjava.lang.Integer
longTransformer: java.lang.Stringjava.lang.Long
stringTransformer: java.lang.Stringjava.lang.String
java.lang.IllegalStateException: !
This code has one restriction, you should say implements ITransformer<S, T> for all implementations of ITransformer. That why I have got IllegalStateException for this line ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>(). But you can improve this code.
Better option is to use some base implementation of interface and pass source and target classes into constructor:
public interface ITransformer<S, T> {
void transform(S source, T target);
String getTransformerName();
}
public abstract class BaseITransformer<S, T> implements ITransformer<S, T> {
private final Class<S> sourceClass;
private final Class<T> targetClass;
public BaseITransformer(Class<S> sourceClass, Class<T> targetClass) {
this.sourceClass = sourceClass;
this.targetClass = targetClass;
}
public String getTransformerName() {
return sourceClass.getName() + targetClass.getName();
}
}

In Java it is impossible to get a Class<S>, unless you already know which class S is, or something else that knows which class S is gives you one.

Related

Generic class that extends collection generic class

I'm using Guava's LineProcessor interface when reading lines from files. I've created my class called Line Loader which will store lines read. I want it to be generic on choice of collection lines should be stored in so I wrote something like this:
public abstract class LineLoader<T> implements LineProcessor<Collection<T>> {
private final Collection<T> result;
public LineLoader() {
this.result = init();
}
protected boolean add(final T line) {
return result.add(line);
}
#Override
public boolean processLine(final String line) throws Exception {
final T data = parser.parseLine(line);
if (data == null) {
return false;
}
return add(data);
}
#Override
public Collection<T> getResult() {
return result;
}
protected abstract Collection<T> init();
}
where with init() method I force subclasses to chose type of collection, for example:
public abstract class LinkedLineLoader<T> extends LineLoader<T> {
#Override
protected Collection<T> init() {
return new LinkedList<T>();
}
}
I planned on doing this:
public class LineLoader<T> implements LineProcessor<C<T> extends Collection<T>> {
private final C<T> result;
public LineLoader() {
result = new C<T>();
}
protected boolean add(final T line) {
return result.add(line);
}
#Override
public boolean processLine(final String line) throws Exception {
final T data = parser.parseLine(line);
if (data == null) {
return false;
}
return add(data);
}
#Override
public C<T> getResult() {
return result;
}
}
so that latter subclases (if needed) could do:
public class LinkedLineLoader<T> extends LineLoader<LinkedList<T>> {
}
but it's not possible. Is there a clean solution to this problem?
In Java it is not possible to create instances from generic type arguments, because generics are erased at run-time. Also, generic type arguments can not themselves declare additional type arguments like C<T>. Therefore the code you posted is entirely illegal and will not compile:
private final C<T> result; // illegal
result = new C<T>(); // illegal
Aside from that, your declaration of the type arguments itself has some flaws. The following code is no legal Java code:
public class LineLoader<T> implements LineProcessor<C<T> extends Collection<T>>
It should actually look e.g. like this:
public class LineLoader<T, C extends Collection<T>> implements LineProcessor<C>
As a solution to your problem, you could declare your LineLoader as shown above, and add a protected constructor, that takes the generic collection as an argument:
public abstract class LineLoader<T, C extends Collection<T>> implements LineProcessor<C> {
private final C result;
protected LineLoader(C collection) {
result = collection;
}
protected boolean add(final T line) {
return result.add(line);
}
#Override
public boolean processLine(final String line) throws IOException {
final T data = parser.parseLine(line);
if (data == null) {
return false;
}
return add(data);
}
#Override
public C getResult() {
return result;
}
}
Then you can implement your LinkedLineLoader like so:
class LinkedLineLoader<T> extends LineLoader<T, LinkedList<T>> {
public LinkedLineLoader() {
super(new LinkedList<>());
}
}

Generify class because of unchecked casting warning

I have the following class with methods marked as unchecked that give me a warning. They compile/work fine but I am interested if there is a way to generify the class as IntelliJ IDEA is offering me (but unable to do) to remove the warnings.
public abstract class Attribute {
private final AttributedNode containerNode;
private boolean computationComplete;
public Attribute(AttributedNode node) {
this.containerNode = node;
this.computationComplete = false;
}
public AttributedNode getContainerNode() {
return containerNode;
}
public Attribute getAttributeFromChildNode(int childIndex, AttributeNameEnum attributeName) {
AttributedNode node = getContainerNode().getChild(childIndex);
return node.getAttribute(attributeName);
}
public String getChildNodeText(int index) {
return getContainerNode().getChild(index).getText();
}
#SuppressWarnings("unchecked")
public <T, E extends Attribute> List<T> getListOfChildAttributeValues(AttributeNameEnum name) {
List<T> result = new LinkedList<>();
for (AttributedNode node : this.getContainerNode().getChildren()) {
E attribute = (E) node.getAttribute(name);
result.add((T) attribute.getValue());
}
return result;
}
public <T extends Attribute> Object getAttributeValueFromContainer(AttributeNameEnum name) {
return this.<T>getAttributeValueFromNode(name, this.getContainerNode());
}
public <T extends Attribute> Object getAttributeValueFromParent(AttributeNameEnum name) {
return this.<T>getAttributeValueFromNode(name, this.getContainerNode().getParent());
}
#SuppressWarnings("unchecked")
public <T extends Attribute> Object getAttributeValueFromNode(AttributeNameEnum name, AttributedNode node) {
T attribute = (T) node.getAttribute(name);
return attribute.getValue();
}
// other methods eluded
P.S. I apologize ahead of time of maybe my lack of understanding Generics.

How can I simulate Haskell's "Either a b" in Java

How can I write a typesafe Java method that returns either something of class a or something of class b? For example:
public ... either(boolean b) {
if (b) {
return new Integer(1);
} else {
return new String("hi");
}
}
What is the cleanest way?
( The only thing that comes to my mind is using exceptions which is obviously bad, as it is abusing a error-handling mechanism for a general language feature ...
public String either(boolean b) throws IntException {
if (b) {
return new String("test");
} else {
throw new IntException(new Integer(1));
}
}
)
My general formula for simulating algebraic data types is:
The type is an abstract base class, and the constructors are subclasses of that
The data for each constructor are defined in each subclass. (This allows constructors with different numbers of data to work correctly. It also removes the need to maintain invariants like only one variable is non-null or stuff like that).
The constructors of the subclasses serve to construct the value for each constructor.
To deconstruct it, one uses instanceof to check the constructor, and downcast to the appropriate type to get the data.
So for Either a b, it would be something like this:
abstract class Either<A, B> { }
class Left<A, B> extends Either<A, B> {
public A left_value;
public Left(A a) { left_value = a; }
}
class Right<A, B> extends Either<A, B> {
public B right_value;
public Right(B b) { right_value = b; }
}
// to construct it
Either<A, B> foo = new Left<A, B>(some_A_value);
Either<A, B> bar = new Right<A, B>(some_B_value);
// to deconstruct it
if (foo instanceof Left) {
Left<A, B> foo_left = (Left<A, B>)foo;
// do stuff with foo_left.a
} else if (foo instanceof Right) {
Right<A, B> foo_right = (Right<A, B>)foo;
// do stuff with foo_right.b
}
Here is a statically checked type-safe solution; this means you cannot create runtime errors. Please read the previous sentence in the way it is meant. Yes, you can provoke exceptions in some way or the other...
It's pretty verbose, but hey, it's Java!
public class Either<A,B> {
interface Function<T> {
public void apply(T x);
}
private A left = null;
private B right = null;
private Either(A a,B b) {
left = a;
right = b;
}
public static <A,B> Either<A,B> left(A a) {
return new Either<A,B>(a,null);
}
public static <A,B> Either<A,B> right(B b) {
return new Either<A,B>(null,b);
}
/* Here's the important part: */
public void fold(Function<A> ifLeft, Function<B> ifRight) {
if(right == null)
ifLeft.apply(left);
else
ifRight.apply(right);
}
public static void main(String[] args) {
Either<String,Integer> e1 = Either.left("foo");
e1.fold(
new Function<String>() {
public void apply(String x) {
System.out.println(x);
}
},
new Function<Integer>() {
public void apply(Integer x) {
System.out.println("Integer: " + x);
}
});
}
}
You might want to look at Functional Java and Tony Morris' blog.
Here is the link to the implementation of Either in Functional Java. The fold in my example is called either there. They have a more sophisticated version of fold, that is able to return a value (which seems appropriate for functional programming style).
You can have a close correspondence with Haskell by writing a generic class Either, parametric on two types L and R with two constructors (one taking in an L, and one taking in an R) and two methods L getLeft() and R getRight() such that they either return the value passed when constructing, or throw an exception.
The suggestions already provided, although feasible, are not complete as they rely on some null references and effectively make "Either" masquerade as a tuple of values. A disjoint sum is obviously one type or the other.
I'd suggest having a look at the implementation of FunctionalJava's Either as an example.
The big thing is not to try to write in one language whilst writing in another. Generally in Java you want to put the behaviour in the object, rather than having a "script" running outside with encapsulation destroyed by get methods. There is no context for making that kind of suggestion here.
One safe way of dealing with this particular little fragment is to write it as a callback. Similar to a very simple visitor.
public interface Either {
void string(String value);
void integer(int value);
}
public void either(Either handler, boolean b) throws IntException {
if (b) {
handler.string("test");
} else {
handler.integer(new Integer(1));
}
}
You may well want to implement with pure functions and return a value to the calling context.
public interface Either<R> {
R string(String value);
R integer(int value);
}
public <R> R either(Either<? extends R> handler, boolean b) throws IntException {
return b ?
handler.string("test") :
handler.integer(new Integer(1));
}
(Use Void (capital 'V') if you want to get back to being uninterested in the return value.)
I've implemented it in a Scala-like fashion in the following way. It's a little verbose (it is Java, after all :)) but it's type safe.
public interface Choice {
public enum Type {
LEFT, RIGHT
}
public Type getType();
interface Get<T> {
T value();
}
}
public abstract class Either<A, B> implements Choice {
private static class Base<A, B> extends Either<A, B> {
#Override
public Left leftValue() {
throw new UnsupportedOperationException();
}
#Override
public Right rightValue() {
throw new UnsupportedOperationException();
}
#Override
public Type getType() {
throw new UnsupportedOperationException();
}
}
public abstract Left leftValue();
public abstract Right rightValue();
public static <A, B> Either<A, B> left(A value) {
return new Base<A, B>().new Left(value);
}
public static <A, B> Either<A, B> right(B value) {
return new Base<A, B>().new Right(value);
}
public class Left extends Either<A, B> implements Get<A> {
private A value;
public Left(A value) {
this.value = value;
}
#Override
public Type getType() {
return Type.LEFT;
}
#Override
public Left leftValue() {
return Left.this;
}
#Override
public Right rightValue() {
return null;
}
#Override
public A value() {
return value;
}
}
public class Right extends Either<A, B> implements Get<B> {
private B value;
public Right(B value) {
this.value = value;
}
#Override
public Left leftValue() {
return null;
}
#Override
public Right rightValue() {
return this;
}
#Override
public Type getType() {
return Type.RIGHT;
}
#Override
public B value() {
return value;
}
}
}
Then you can pass Either<A,B> instances around on your code. The Type enum is mainly used on switch statements.
Creating Either values is simple as:
Either<A, B> underTest;
A value = new A();
underTest = Either.left(value);
assertEquals(Choice.Type.LEFT, underTest.getType());
assertSame(underTest, underTest.leftValue());
assertNull(underTest.rightValue());
assertSame(value, underTest.leftValue().value());
Or, in the typical situation where it is used instead of exceptions,
public <Error, Result> Either<Error,Result> doSomething() {
// pseudo code
if (ok) {
Result value = ...
return Either.right(value);
} else {
Error errorMsg = ...
return Either.left(errorMsg);
}
}
// somewhere in the code...
Either<Err, Res> result = doSomething();
switch(result.getType()) {
case Choice.Type.LEFT:
// Handle error
Err errorValue = result.leftValue().value();
break;
case Choice.Type.RIGHT:
// Process result
Res resultValue = result.rightValue().value();
break;
}
Hope it helps.
From http://blog.tmorris.net/posts/maybe-in-java/ I learned that you can make the outer class's constructor private so only nested classes can subclass it. This trick is just as type safe as the best above, but much less verbose, works for any ADT you want like Scala's case class.
public abstract class Either<A, B> {
private Either() { } // makes this a safe ADT
public abstract boolean isRight();
public final static class Left<L, R> extends Either<L, R> {
public final L left_value;
public Left(L l) { left_value = l; }
public boolean isRight() { return false; }
}
public final static class Right<L, R> extends Either<L, R> {
public final R right_value;
public Right(R r) { right_value = r; }
public boolean isRight() { return true; }
}
}
(started from top answer's code and style)
Note that:
The finals on the subclass are optional. Without them you can subtype Left and Right, but still not Either directly. Thus without the finals Either has limited width but unbounded depth.
With ADTs like this, I see no reason to jump on the whole anti-instanceof bandwagon. A boolean works for Maybe or Either, but in general instanceof is your best and only option.
Thanks to Derive4J algebraic data types are now very easy in Java. All you have to do is create the following class:
import java.util.function.Function;
#Data
public abstract class Either<A, B> {
Either(){}
/**
* The catamorphism for either. Folds over this either breaking into left or right.
*
* #param left The function to call if this is left.
* #param right The function to call if this is right.
* #return The reduced value.
*/
public abstract <X> X either(Function<A, X> left, Function<B, X> right);
}
And Derive4J will take care of creating constructors for the left and rights cases, as well as a pattern matching syntax alla Haskell, mapper methods for each sides, and more.
There is a stand-alone implementation of Either for Java 8 in a small library, "ambivalence": http://github.com/poetix/ambivalence
It is closest to the Scala standard implementation - for example, it provides left and right projections for map and hashMap operations.
There is no direct access to the left or right values; rather, you join the two types by providing lambdas to map them into a single result type:
Either<String, Integer> either1 = Either.ofLeft("foo");
Either<String, Integer> either2 = Either.ofRight(23);
String result1 = either1.join(String::toUpperCase, Object::toString);
String result2 = either2.join(String::toUpperCase, Object::toString);
You can get it from Maven central:
<dependency>
<groupId>com.codepoetics</groupId>
<artifactId>ambivalence</artifactId>
<version>0.2</version>
</dependency>
You don't need to settle with the instanceof checks or redundant fields. Surprisingly enough, Java's type system provides enough features to simulate the sum types cleanly.
Background
First of all, do you know that any data type can be encoded with just functions? It's called Church encoding. E.g., using the Haskell signature, the Either type could be defined as follows:
type Either left right =
forall output. (left -> output) -> (right -> output) -> output
You can interpret it as "given a function on the left value and a function on the right value, produce the result of either of them".
Definition
Expanding on this idea, in Java we can define an interface called Matcher, which includes both functions and then define the Sum type in terms of how to pattern-match on it. Here's the complete code:
/**
* A sum class which is defined by how to pattern-match on it.
*/
public interface Sum2<case1, case2> {
<output> output match(Matcher<case1, case2, output> matcher);
/**
* A pattern-matcher for 2 cases.
*/
interface Matcher<case1, case2, output> {
output match1(case1 value);
output match2(case2 value);
}
final class Case1<case1, case2> implements Sum2<case1, case2> {
public final case1 value;
public Case1(case1 value) {
this.value = value;
}
public <output> output match(Matcher<case1, case2, output> matcher) {
return matcher.match1(value);
}
}
final class Case2<case1, case2> implements Sum2<case1, case2> {
public final case2 value;
public Case2(case2 value) {
this.value = value;
}
public <output> output match(Matcher<case1, case2, output> matcher) {
return matcher.match2(value);
}
}
}
Usage
And then you can use it like this:
import junit.framework.TestCase;
public class Test extends TestCase {
public void testSum2() {
assertEquals("Case1(3)", longOrDoubleToString(new Sum2.Case1<>(3L)));
assertEquals("Case2(7.1)", longOrDoubleToString(new Sum2.Case2<>(7.1D)));
}
private String longOrDoubleToString(Sum2<Long, Double> longOrDouble) {
return longOrDouble.match(new Sum2.Matcher<Long, Double, String>() {
public String match1(Long value) {
return "Case1(" + value.toString() + ")";
}
public String match2(Double value) {
return "Case2(" + value.toString() + ")";
}
});
}
}
With this approach you can even find a direct resemblance of pattern-matching in such languages as Haskell and Scala.
Library
This code is distributed as part of my library of composite types (Sums and Products, aka Unions and Tuples) of multiple arities. It's on GitHub:
https://github.com/nikita-volkov/composites.java
Since you've tagged Scala, I'll give a Scala answer. Just use the existing Either class. Here's an example usage:
def whatIsIt(flag: Boolean): Either[Int,String] =
if(flag) Left(123) else Right("hello")
//and then later on...
val x = whatIsIt(true)
x match {
case Left(i) => println("It was an int: " + i)
case Right(s) => println("It was a string: " + s)
}
This is completely type-safe; you won't have problems with erasure or anything like that...
And if you simply can't use Scala, at least use this as an example of how you can implement your own Either class.
The closest I can think of is a wrapper around both values that lets you check which value is set and retrieve it:
class Either<TLeft, TRight> {
boolean isLeft;
TLeft left;
TRight right;
Either(boolean isLeft, TLeft left1, TRight right) {
isLeft = isLeft;
left = left;
this.right = right;
}
public boolean isLeft() {
return isLeft;
}
public TLeft getLeft() {
if (isLeft()) {
return left;
} else {
throw new RuntimeException();
}
}
public TRight getRight() {
if (!isLeft()) {
return right;
} else {
throw new RuntimeException();
}
}
public static <L, R> Either<L, R> newLeft(L left, Class<R> rightType) {
return new Either<L, R>(true, left, null);
}
public static <L, R> Either<L, R> newRight(Class<L> leftType, R right) {
return new Either<L, R>(false, null, right);
}
}
class Main {
public static void main(String[] args) {
Either<String,Integer> foo;
foo = getString();
foo = getInteger();
}
private static Either<String, Integer> getInteger() {
return Either.newRight(String.class, 123);
}
private static Either<String, Integer> getString() {
return Either.newLeft("abc", Integer.class);
}
}
Based on the answer by Riccardo, following code snippet worked for me:
public class Either<L, R> {
private L left_value;
private R right_value;
private boolean right;
public L getLeft() {
if(!right) {
return left_value;
} else {
throw new IllegalArgumentException("Left is not initialized");
}
}
public R getRight() {
if(right) {
return right_value;
} else {
throw new IllegalArgumentException("Right is not initialized");
}
}
public boolean isRight() {
return right;
}
public Either(L left_v, Void right_v) {
this.left_value = left_v;
this.right = false;
}
public Either(Void left_v, R right_v) {
this.right_value = right_v;
right = true;
}
}
Usage:
Either<String, Integer> onlyString = new Either<String, Integer>("string", null);
Either<String, Integer> onlyInt = new Either<String, Integer>(null, new Integer(1));
if(!onlyString.isRight()) {
String s = onlyString.getLeft();
}
Change your design so that you don't need this rather absurd feature. Anything you'd do with the return value would require some sort of if/else construct. It would just be very, very ugly.
From a quick Googling, it seems to me that the only thing Haskell's Either is commonly used for is error reporting anyway, so it looks like exceptions are actually to correct replacement.

What is wrong with this java generic method syntax

I've the following classes
KeyValue.java
package test;
public class KeyValue<T> {
private String key;
private T value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Reader.java
package test;
public interface Reader<T> {
<S extends T> S read(Class<S> clazz);
}
Test.java
package test;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<KeyValue<Object>> list = find(KeyValue.class, new Reader<KeyValue<Object>>() {
#Override
public <S extends KeyValue<Object>> S read(Class<S> clazz) {
return null;
}
});
}
public static <T> List<T> find(Class<T> targetClass, Reader<T> reader) {
return null;
}
}
Here the method call find(......) is failing at compile time with error message
The method find(Class, Reader) in the type Test is not applicable for the arguments (Class, new Reader>(){}).
This method has to return object of type List<KeyValue<Object>>.
What is wrong with this design and how to fix this.
Thank you.
finddefines T and T (in first and second arg) to be of same type - your call to find uses the type Object in the first arg and the Type KeyValue<Object>in the second arg.
Either use two different type identifiers (e.g. T and X, i.e. public static <T, X extends T> List<T> find(Class<T> targetClass, List<X> reader) ) in your find declaration or repair your call to find.
you want to get a list of your class KeyValue from your method find
but u defined it as List note that it is a list of T not KeyValue
change ur method declaration to be as follows
private static <T> List<KeyValue<T> > find(Class<KeyValue> aClass, Reader<KeyValue<T> > reader) {
throw new UnsupportedOperationException("Not yet implemented");
}
i think this is what u want
Try to declare Test as
public class Test<T> {.

Can generics allow the Java compiler to check the type of keys and values in a map?

I am in a situation where I want to have a map where the keys are an interface class, and the corresponding value is a class which implements that interface. In other words the key and value type is related.
My current implementation of the method which adds to the map, and gets an instance of the implementation class looks like:
// should be something like Class<T>, Class<? extends T>
static Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>> ();
public static <T> void add(Class<T> interfaceT,
Class<? extends T> implementationT) {
map.put(interfaceT, implementationT);
}
public static <T> T get(Class<T> interfaceT) {
// cast caused by definition not complete.
Class<T> implementationT = (Class<T>) map.get(interfaceT);
// try catch stuff omitted
T t = implementationT.newInstance();
return t;
}
My question is:
Can I define the "map" variable so the cast in the get(...) method is unneeded? I could not make the " new HashMap<Class<T>, Class<? extends T>>()' work, so either it is impossible or I missed something fundamental :)
Please advise :)
Edit: It turned out that the asSubclass() method on Class did what I wanted :D
Class<?> rawClassFromMap = map.get(interfaceT);
Class<? extends T> implementationT = rawClassFromMap.asSubclass(interfaceT);
It is fine that implementationT is of type "? extends T" as I just need a T object returned.
I like generics. Reminds me of Haskell...
It looks like the goal is something like the "Typesafe Heterogenous Container" described by Josh Bloch in Chapter 5 of Effective Java (item 29). In his case, he's mapping a type (Class<T>) to an (already-instantiated) instance (T).
You can do something similar, using asSubclass instead of cast:
final class Factory
{
private Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();
<T> void map(Class<T> type, Class<? extends T> impl)
{
map.put(type, impl.asSubclass(type));
}
private <T> Class<? extends T> get(Class<T> type)
{
Class<?> impl = map.get(type);
if (impl == null)
throw new IllegalArgumentException("Unknown type: " + type);
return impl.asSubclass(type);
}
<T> T create(Class<T> type)
throws Exception
{
Class<? extends T> impl = get(type);
Constructor<? extends T> ctor = impl.getConstructor();
return ctor.newInstance();
}
}
I would suggest a Proxy. Here's the Java example.
public interface Bike {
public String getWheels();
public int getSize();
}
public class MountainBike implements Bike {
#Override
public int getSize() {
return 24;
}
#Override
public String getWheels() {
return "Treaded";
}
#Override
public String toString() {
String newLine = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
sb.append("Type: MOUNTAIN").append(newLine);
sb.append("Wheels: ").append(getWheels()).append(newLine);
sb.append("Size: ").append(getSize()).append(newLine);
return sb.toString();
}
}
public class CruiserBike implements Bike {
#Override
public int getSize() {
return 26;
}
#Override
public String getWheels() {
return "Smooth";
}
#Override
public String toString() {
String newLine = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
sb.append("Type: CRUISER").append(newLine);
sb.append("Wheels: ").append(getWheels()).append(newLine);
sb.append("Size: ").append(getSize()).append(newLine);
return sb.toString();
}
}
public class BikeProxy implements InvocationHandler {
private Object obj;
public static Object newInstance(Object obj)
{
return java.lang.reflect.Proxy.newProxyInstance(obj.getClass()
.getClassLoader(), obj.getClass().getInterfaces(),
new BikeProxy(obj));
}
public static <T> T newInstance(String className)
{
try
{
return (T) newInstance(Class.forName(className));
}
catch (ClassNotFoundException e)
{
throw new RuntimeException(e);
}
}
public static <T> T newInstance(Class<T> bikeClass)
{
try
{
return (T) java.lang.reflect.Proxy.newProxyInstance(Bike.class.getClassLoader(), new Class[]{Bike.class},
new BikeProxy(bikeClass.newInstance()));
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
private BikeProxy(Object obj)
{
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable
{
Object result;
try
{
result = m.invoke(obj, args);
}
catch (InvocationTargetException e)
{
throw e.getTargetException();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
return result;
}
}
public class ProxyTester
{
public static void main(String[] args)
{
Bike mountainBike = BikeProxy.newInstance(MountainBike.class);
System.out.println(mountainBike);
Bike mountainBike2 = BikeProxy.newInstance(MountainBike.class.getName());
System.out.println(mountainBike2);
Bike cruiserBike = BikeProxy.newInstance(CruiserBike.class);
System.out.println(cruiserBike);
Bike cruiserBike2 = BikeProxy.newInstance(CruiserBike.class.getName());
System.out.println(cruiserBike2);
}
}

Categories