I am currently writing unit tests related to GET requests, here below is a parameterized test that take a generic type E.
abstract class AbstractEntityTest< E extends Entity > {
#ParameterizedTest( name = "[{index}]: {2}" )
#MethodSource( "RoleDataProvider#provideIntArgsToTest" )
void testIntRequestsThatReturnSingle( String fileName, Integer requestParam, String testName, int index )
// do something
}
}
What I want to do is to dynamically change the method source in function of the actual type of E at runtime.
Example:
public class AnimalTest extends AbstractEntityTest< Animal > {
... }
Here E is type Animal so I would like to change the #MethodSource to
#MethodSource( "AnimalDataProvider#provideIntArgsToTest" )
Is there any way to do it ? I've been searching for hours to no avail...
That isn't going to be possible in Java I'm afraid. Java is a strongly, statically typed language, which means that objects can't change their type and type checking occurs during compilation.
Java implements generics with erasure, which means that the compiler will replace your bound type parameter E with bounding class Entity, (described here).
What are you trying to achieve? If you want to avoid duplication, you could group shared logic into a single method and call it #BeforeEach for example.
EDIT: Gotcha, I think I know what you mean, cheers for the response. Have you tried specifying that in the children test classes?
I tried messing around with the same concept but with Number, Integer, and Double. Here's what I got:
AbstractTest.java
public abstract class AbstractTest<E extends Number> {
void testIntRequestsThatReturnSingle(Number i){
System.out.println(i);
//doing the same stuff here but with the different data sources
}
public static IntStream intProvider() {
return IntStream.range(0, 10);
}
public static DoubleStream doubleProvider() {
return DoubleStream.of(0.0,1.1,2.2);
}
}
One child IntTest.java class:
public class IntTest extends AbstractTest<Integer>{
#ParameterizedTest
#MethodSource( "intProvider" )
public void intTest(Number i){
this.testIntRequestsThatReturnSingle(i);
}
}
Another child DoubleTest.java class:
public class DoubleTest extends AbstractTest<Integer>{
#ParameterizedTest
#MethodSource( "doubleProvider" )
public void doubleTest(Number i){
this.testIntRequestsThatReturnSingle(i);
}
}
This way you can minimise duplication and ensure that the right methods are called for the right classes (without any scary casting). Is this something along the lines of what you were looking for?
Related
I've an interface Message with two implementations MessageA and MessageB.
Now I have the following generic class that takes a type variable T that extends Message. I want a method test to act in one way if the argument is T (or a subtype) and in an other way if the argument is an other implementation of Message :
I tried this, but it does not work because of erasure :
public class MyClass<T extends Message>
{
public Integer test(T m)
{
System.out.println( "This is the good one." );
return m.f(7);
}
public <S extends Message> Integer test(S m)
{
System.out.println("I'm not the good one");
return m.f(7);
}
}
I could do explicit type checking, but I guess that there exists a cleaner way to reach my goal.
EDIT
I prefer to use overriding or overloading because in my project, I will have a class MyClassA implements MyClass<MessageA> that will implement the method test(MessageA m). But I want to implement the "wrong" case in the base generic class.
The following makes the work :
public class MyClassA extends MyClass<MessageA>
{
public Integer test(Message m)
{
if (m instanceof MessageA)
{
return m.f(7);
}
else
{
System.out.println("Bad type.");
return 0;
}
}
}
But it forces me to implement a if-then block with print("bad type") in every instantiation of my generic MyClass<T extends Message> (for the sake of code duplication).
EDIT
Based on the accepted solution, I posted a fully-functional minimal example here.
You can test using the instanceof keyword :
public Integer test(T m)
{
if(m instanceof MessageA || m instanceof MessageB) {
System.out.println( "A subclass of Message instance." );
//your custom process
}else{
System.out.println( "A Message instance." );
//your custom process
}
}
EDIT
Due to the way generics is implemented in Java, you can't find out what type of Object a generic class is using at runtime (the generic type T is not kept at runtime). Still, you can use a private data member and overload your test method in every Message branch and use it in the generic Class :
public class MyClass<T extends Message>
{
private Class<T> type;
public MyClass(Class<T> type) { this.type = type; }
public Integer test(T m)
{
return type.test(m);
}
}
Overloading is static. It uses the compile-time object type instead of the actual run-time type. Either use Message#test() to use overriding or add explicit type checking (i.e. instanceof) to your code.
My answer may sound harsh, but your design seems a little broken.
The easiest solution is to derive MessageA and MessageB from a common class (which may have nothing to do with your interface), and to add a protected function to this class which you can call.
Or you create a second interface, and follow one of the questions below.
See one of the SO questions below:
Generic extending class AND implements interface
Java generics - Make Generic to extends 2 interfaces
I'm trying to simulate something analogous to a function template in Java, in the sense that I have something like the following:
public interface MyFunctionTemplate<T> {
void doSomething(T thing);
}
public class MyIntegerFunctionTemplate extends MyFunctionTemplate<Integer> { ... }
public class MyStringFunctionTemplate extends MyFunctionTemplate<String> { ... }
It appears that I will need a central registry of some sort. Something like the following:
public class MyFunctionTemplateRegistry {
private static Map<Class<?>, MyFunctionTemplate<?>> registry;
public static <T> void register(Class<T> templateClass, MyFunctionTemplate<T> templateFunction);
public static void doSomething(Object thing);
}
What is the best way to design such a thing?
Well, it depends on what you want to achieve and whether the implementing class needs to know the type or not. To me, your suggestion seems overdesigned (too complex), but it is really hard to say without having more concrete information.
The reason I'm saying this, is that I don't like the fact that you want to implement two separate classes for your interface (one for each type). The strength of using generics is often in finding a way to implement it with one class using the generic type T.
Then again, I might have misunderstood your intentions here...
Anyway, as a simple example, if your function(s) are purely mathematical, something like getMax() and getMin(), then you surely don't need to know anything more about T than the fact that T is comparable with T.
Then you could end up with something like this:
public class FindExtremes<T extends Comparable<T>> {
T getMax(T a, T b) {
return a.compareTo(b) >= 0 ? a : b;
}
T getMin(T a, T b) {
return a.compareTo(b) <= 0 ? a : b;
}
}
This could the be used directly for any class that implements Comparable, e.g.
new FindExtremes<Integer>().getMax(4, 5);
new FindExtremes<Double>().getMax(4.444D, 5.555D);
new FindExtremes<String>().getMax("abc", "zyx");
I'm trying to understand this notation of whats going on here Example also below. I'm looking to see if anyone can supply additional code to help me make sense of this. How do I extend junk with T? what does that imply?
public class Junk<T extends Junk>
{
public Junk()
{
}
public T returnType()
{
return null; //? what would I even return
}
//what would I do to make sense of this class
}
T is a generic type parameter. You know it is a Junk, or a subclass of it. To return anything useful from your method, you'd need some other methods using the same type. For example:
public class Junk<T extends Junk> {
T var;
public void setT(T var) {
this.var = var;
}
public T returnType(){
return var;
}
}
It can be used by creating instances where the type parameter is specified:
Junk junk = new Junk<Junk>();
junk.setT(new Junk<Junk>());
junk.returnType();
This is more useful than simply using "Junk" instead of "T", because subtypes can be used without losing type-safety. If you have a subclass SubclassJunk, then you can do:
Junk junk = new Junk<SubclassJunk>();
junk.setT(new SubclassJunk<Junk>());
SubclassJunk subclass = junk.returnType();
pardon me for making an educated guess, but,
It looks like T is an undefined type,
the statement <T extends junk> looks like a constraint to ensure that T derives from Junk
so if you have a class like
public class SmallJunk extends Junk
{
}
then T can be aSmallJunk, but not other types.
class Junk<T extends Junk> is the syntax for generic programming in Java. It means that wherever the type T is used in the class, it must stand for some (as yet unknown) subclass of Junk.
Given
public class junk<T extends junk<T>>
{
public T returnType()
{
return (T)this;
}
}
you would extend it as
public class Subclass extends junk<Subclass> {
}
and the inherited returnType method would then return Subclass. The most prominent example of this pattern in the standard Java libraries is enum types, where an enum Foo becomes a class that extends Enum<Foo>
How can I iterate over a wildcard generic? Basically I would like to inline the following method:
private <T extends Fact> void iterateFacts(FactManager<T> factManager) {
for (T fact : factManager) {
factManager.doSomething(fact);
}
}
If this code is in a separate method as shown, it works because the generic method context allows to define a wildcard type (here T) over which one can iterate. If one tries to inline this method, the method context is gone and one cannot iterate over a wildcard type anymore. Even doing this automatically in Eclipse fails with the following (uncompilable) code:
...
for (FactManager<?> factManager : factManagers) {
...
for ( fact : factManager) {
factManager.doSomething(fact);
}
...
}
...
My question is simply: Is there a way to put some wildcard type one can iterate over, or is this a limitation of generics (meaning it is impossible to do so)?
No. In situation like this, the workaround is to create a helper method.
The JLS has this example http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.10
public static void reverse(List<?> list) { rev(list);}
private static <T> void rev(List<T> list) { ... }
The issue is, we have a List<?> object. We know it must be a List<X> of some X, and we'd like to write code using X. Internally compiler does convert the wildcard to a type variable X, but Java language does not offer programmers a direct way to access it. But if there's a method accepting List<T>, we can pass the object to the method. Compiler infers that T=X and the call is good.
If there's no type erasure, X can be known at runtime, then Java would definitely give us a way to access X. However as of today since X isn't available at runtime, there's not much point. A purely synthetic way could be provided, which is unlikely to be simpler than the helper method workaround.
Type parameters can only defined on
types (i.e. classes/interfaces),
methods, and
constructors.
You would need a type parameter for a local block, which is not possible.
Yeah, I missed something like this sometimes, too.
But there is not really a problem with having the method non-inlined here - if it presents a performance bottleneck where inlining would help, Hotspot will inline it again (not caring about the type).
Additionally, having a separate method allows giving it a descriptive name.
Just an idea, if you need this often:
interface DoWithFM {
void <T> run(FactManager<T> t);
}
...
for (FactManager<?> factManager : factManagers) {
...
new DoWithFM() { public <T> run(FactManager<T> factManager) {
for (T fact : factManager) {
factManager.doSomething(fact);
}
}.run(factManager);
...
}
...
You can always fall back to Object
for (FactManager<?> factManager : factManagers) {
...
for ( Object fact : factManager) {
factManager.doSomething(fact);
}
...
}
This, of course, is subject to what is the actual declaration of doSomething.
If doSomething is declared as this void doSomething( T fact ), then your recourse here would be to use a raw type and swallow unchecked warnings. If you can guarantee that FactManager can only have homogeneous Facts inserted, then that may be an OK solution.
for (FactManager factManager : factManagers) { // unchecked warning on this line
...
for ( Object fact : factManager) {
factManager.doSomething(fact);
}
...
}
Well, I can think of a way to do it using inner classes, because the inner class shares the type parameter with its enclosing type. Also, even using wildcards you could still process your collections thanks to wildcard capture conversion.
Let me create an example. This code compiles and runs fine. But I cannot be certain if the use of inner classes would be an issue for you.
//as you can see type parameter belongs to the enclosing class
public class FactManager<T> implements Iterable<FactManager<T>.Fact> {
private Collection<Fact> items = new ArrayList<Fact>();
public void doSomething(Fact fact) {
System.out.println(fact.getValue());
}
public void addFact(T value) {
this.items.add(new Fact(value));
}
#Override
public Iterator<Fact> iterator() {
return items.iterator();
}
public class Fact {
//inner class share its enclosing class type parameter
private T value;
public Fact(T value) {
this.value = value;
}
public T getValue() {
return this.value;
}
public void setValue(T value) {
this.value = value;
}
}
public static void main(String[] args) {
List<FactManager<String>> factManagers = new ArrayList<FactManager<String>>();
factManagers.add(new FactManager<String>());
factManagers.get(0).addFact("Obi-wan");
factManagers.get(0).addFact("Skywalker");
for(FactManager<? extends CharSequence> factManager : factManagers){
//process thanks to wildcard capture conversion
procesFactManager(factManager);
}
}
//Wildcard capture conversion can be used to process wildcard-based collections
public static <T> void procesFactManager(FactManager<T> factManager){
for(FactManager<T>.Fact fact : factManager){
factManager.doSomething(fact);
}
}
}
This is more precisely matched to the method you defined (that is, if you can call iterateFacts() with the FactManagers in factManagers, you know that the FactManager contain items that are some subclass of Fact).
for (FactManager<? extends Fact> factManager : factManagers) {
for (Fact fact : factManager) {
factManager.doSomething(fact);
}
}
I would tend to think, however, that you would declare FactManager to be generic for subtypes of Fact (just given the name of the class), e.g.
class FactManager<T extends Fact> implements Iterable<T> {
...
}
The Eclipse refactoring fails because it cannot infer the type of an object contained by FactManager<?>.
I have the following class :
public abstract class Step {
public abstract <S,T> S makeAStep(S currentResult, T element);
}
and I'm trying to Implement it so it will take two int's and return the sum of them , something like this :
public class sumOfInts extends Step {
public <Integer,Integer> Integer makeAStep(Integer currentResult, Integer element){
return currentResult + element;
}
}
but I get the following error :
The type sumOfInts must implement the inherited abstract method Step.makeAStep(S, T)
please help me (I need it for my programming languages course homework)
I asking very kindly to write me a code that does what I want to accomplish which wont
have any errors or warnings
thanks in front
public abstract class Step<S,T> {
public abstract S makeAStep(S currentResult, T element);
}
public class SumOfInts extends Step<Integer,Integer> {
// etc.
I agree with Jonathan's answer.
There is also another possibility, given below, that keeps the type parameters on the method itself.
It's only theory in this case, because the class and method names suggest that this has no meaning for this example.
So I change the names for my example:
public abstract class Step {
public abstract <S,T> String makeAStep(S first, T second);
}
public class ConcatTwo extends Step {
public <S, T> String makeAStep(S first, T second){
return String.valueOf(first) + String.valueOf(second);
}
}
Note : This works because the operation uses String.valueOf(Object), that works for any type (all subclass Object). For another operation, we would have to restrict S and T, using something like
S extend Integer for example.