public class CSVParser {
protected <T extends Message> void addMessageToResult(Message message, Descriptor descriptor, ImmutableList.Builder<T> messageListBuilder) {
. . .
}
For DynamicMessage I wanted to have a different handling so I tried
public class CSVParserDynamicMessage extends CSVParser {
protected<DynamicMessage> void addMessageToResult(Message message, Descriptor descriptor, ImmutableList.Builder<DynamicMessage> messageListBuilder) {
messageListBuilder.add(DynamicMessage.parseFrom(descriptor, message.toByteString()));
}
But it gives the compilation error
'addMessageToResult(Message, Descriptor, Builder)' in 'com.google.cloud.verticals.telco.taap.dataflow.dataingestion.common.parsers.CSVParserDynamicMessage' clashes with 'addMessageToResult(Message, Descriptor, Builder)' in 'com.google.cloud.verticals.telco.taap.dataflow.dataingestion.common.parsers.CSVParser'; both methods have same erasure, yet neither overrides the other
I'm having to do the ugly method below (haven't yet attempted to run and see if it actually works):
#Override
protected<T extends Message> void addMessageToResult(Message message, Descriptor descriptor, ImmutableList.Builder<T> messageListBuilder)
throws InvalidProtocolBufferException {
messageListBuilder.add((T) DynamicMessage.parseFrom(descriptor, message.toByteString()));
}
Note that my attempt of subclassing was inspired from Java generics (template) specialization possible (overriding template types with specific types) but the difference seems to be that in my case the template paramter T doesn't exist at class level but only at method level. I'm not able to understand why it doesn't work for my usecase.
Any ideas are much appreciated.
Update
What means T
Generic type parameters like T, U, R - are simply placeholders for types, but not the actual types. By convention type parameters are denoted with a single letter but multi-character type parameter will also compile:
public <Something> void doIt(Something s) {}
Something will not be treated by the compiler as a class or interface name, it's just a placeholder.
protected <DynamicMessage> void addMessageToResult(Message message, Descriptor descriptor, ImmutableList.Builder<DynamicMessage> messageListBuilder) {}
As well as DynamicMessage is a placeholder like T. That means that you've changed the generic type parameter declared by in the super class as T extends Message to an arbitrary T. Which is incorrect.
At the beginning I didn't spotted your intention to override a generic method with a non-generic one, that would not work.
The reason for that is that T extends Message compiles to Object due to generic type erasure. I.e. you might think of it, as there's a non-generic method with an argument of Object type declared in the parent class, and therefore it's not possible to override it by providing DynamicMessage as type instead of Object.
A generic method can be overridden only by another generic method, which generic type parameters are precisely the same.
The problem is fully described in the error message: you can't have two method with the same name and arguments that differ only by a generic type parameter, due to generic type erasure.
For instance, these two methods will clash (i.e. their signatures will be treated as they are the same):
public void doIt(List<Integer> list) {}
public void doIt(List<String> list) {}
Because at runtime, there would be only a List<Object> and safe checkcasts added by the compiler.
The remedy when we need two distinct methods:
the method signatures should differ either by method-name, or by the set of parameters (generic type parameters would not be taken into account).
Related
I have an interface Persistable which looks like this, the <T extends Statement<T>> List<Statement<T>> is to allow it to support both BoundedStatements and SimpleStatements in data stax 4.x driver.
public interface Persistable {
<T extends Statement<T>> List<Statement<T>> statements();
}
This java interface is inherited by Kotlin class A such that
data class UpdateRule(
private val something: S) : Persistable {
override fun statements(): List<Statement<BoundStatement> {
return PutKeyValue(Function(orgId, serviceId), JsonUtil.toJson(rule)).statements() //this returns BoundStatement
}
}
However, this gives the error Conflicting overloads.This code seems to work in Java(although with a warning), but in Kotlin it does not allow at all, how can I resolve this while also making sure parent interface remains generic to both Bound and Simple Statement?
You seem to misunderstand what the generics in Persistable mean. As it is written right now, you are supposed to implement the statements method so that it can handle any kind of T that extends Statement<T>. The generics there doesn't mean "implement this by choosing a kind of statement that you like".
It only produces a warning in Java because Java's generics is broken. Because of type erasure, List<Statement<BoundStatement> and List<Statement<T>> both erase to the same type - List, so the method in UpdateRule does implement the method in the interface if you consider the erasures. OTOH, type erasure isn't a thing in Kotlin (at least not in Kotlin/Core).
To fix this, you can move the generic type parameter to the interface:
public interface Persistable<T extends Statement<T>> {
List<Statement<T>> statements();
}
data class UpdateRule(private val something: S) :
Persistable<BoundStatement> {
override fun statements(): List<BoundStatement> =
PutKeyValue(Function(orgId, serviceId), JsonUtil.toJson(rule)).statements()
}
Notice how when we are implementing the interface, we can now specify the specific T that we are implementing for.
In Java just like in Kotin, the value of the type parameter of a generic method is determined by the caller of the method, and can be different at every call of the method, even on the same instance.
In your specific case, with the Java interface declared like this, statements() is supposed to be implemented in such a way that the caller can choose which type of statement will be returned by a given call to this method. This is not the case in your implementation, and that's why Kotlin doesn't allow it. As pointed out by #Sweeper, Java is broken in this respect and might let you get away with a warning.
This is different when using a generic class or interface. If you define the type parameter at the class/interface level, then the value of that type parameter is determined at construction time of the class, or can be fixed by subclasses. For a given instance, all calls to the method will return a well known type, which is (I believe) what you want here.
You can do this in Java:
public interface Persistable<T extends Statement<T>> {
List<Statement<T>> statements();
}
And then in Kotlin:
data class UpdateRule(
private val something: S
) : Persistable<BoundStatement> {
override fun statements(): List<BoundStatement> {
return PutKeyValue(Function(orgId, serviceId), JsonUtil.toJson(rule)).statements() //this returns BoundStatement
}
}
I've encountered a rather weird thing while working on my Java project.
I have this base method in an interface:
public interface Registry<T extends FlakeType<? extends F>, F extends Flake> {
#Nullable
public <E extends F> T findType(#Nonnull String name);
}
Obviously the type parameter E is completely useless since it is neither used in the return type nor the arguments. My IDE also notifies me about that.
And I have another interface extending Registry:
public interface EntityRegistry extends Registry<EntityType<? extends Entity>, Entity> {
#Nullable
#Override
<E extends Entity> EntityType<E> findType(#Nonnull String name);
}
For context, Entity extends Flake, EntityType<E extends Entity> extends FlakeType<E>.
As you can see I am attemting to specify the return type of this method from EntityType<? extends Entity> (this type is coming from the T type parameter) to EntityType<E>, while E is a method type parameter <E extends Entity>.
Logically, ? extends Entity and E extends Entity mean the same thing in this case since E has no other restrictions or something like that and because of this acts essentially also as a wildcard for types extending Entity.
This works perfectly fine.
However, ive noticed the notification by my IDE (Intellij) that
Type parameter E is never used.
This made me think that I could remove it since it is obviously useless and does not have any relationship to either the return value or any argument.
The overriding method provides its own E type parameter which should in no way have something to do with a useless type parameter with the same name in the base method. Or has it?
Because once I changed my base method to this:
#Nullable
public T findType(#Nonnull String name);
overriding it the same way was no longer possible:
findType(String) in EntityRegistry clashes with
findType(String) in Registry; both methods have same erasure, yet
neither overrides the other.
My questions are now:
Why does Java require a useless type parameter in the base method when
an overriding method wants to specify the return values generic type? Shouldn't the parameter provided by the overriding method be sufficient?
Why does overriding in the second case NOT work? Shouldn't it work because the signature is exactly equal to the first case, except that instead of the explicit wildcard another type parameter is used, but since that does mean the same thing, what is the difference?
I am sure I have made some wrong assumptions about generics and this is why I am confused by this. Could you clear it up for me?
Thanks in advance!
Type parameters are part of the method signature. You can find this in JLS §8.4.2:
Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the the type parameters of M, the same formal parameter types.
The signature of a method m1 is a subsignature of the signature of a method m2 if either:
m2 has the same signature as m1, or
the signature of m1 is the same as the erasure (§4.6) of the signature of m2.
Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.
Without the type parameter in Registry, the method in EntityRegistry does not have a subsignature of the base interface method, so it is not seen as an override.
See answer by Jorn Vernee for full description of why it fails to compile:
Type parameters are part of the method signature.
To make it compile, simply specify method in EntityRegistry as:
#Nullable
#Override
EntityType<? extends Entity> findType(#Nonnull String name);
That is consistent with the original version, since E really is undefined, i.e. ?.
Valid override - the signature of the findType method is the same in both interfaces:
<E>findType(String name)
Invalid override - the signature becomes different because of the removal of a type parameter E:
<E>findType(String name)
findType(String name)
JLS §8.4.8.1 and §8.4.2 describe overriding rules and the role of the method signature in them.
A significant part of the problem with your original code, is it is unnecessarily complicated. Also, there would be no way to implement your original EntityRegistry.findType() without settling for an unchecked cast...
...warning: [unchecked] unchecked cast
return ( EntityType< E > ) new EntityType< >( new Entity( name ) );
^
required: EntityType<E>
found: EntityType<Entity>
where E is a type-variable:
E extends Entity declared in method <E>findType(String)
1 warning
Even worse still, because EntityRegistry.findType() is a generic method, it can't be used as a lambda.
Here is a much simpler, more type-safe solution:
interface Registry< T extends FlakeType<? extends Flake> > {
T findType(String name);
}
interface EntityRegistry< U extends EntityType<? extends Entity> > extends Registry<U> {
#Override
U findType(String name);
}
The successfully compiling, correctly running implementation in the above link works this way...
...
EntityRegistry<EntityType<Entity>> registry = (name) -> { return new EntityType<Entity>(new Entity(name)); };
...
and this way...
...
Registry<EntityType<Entity>> registry = (name) -> { return new EntityType<Entity>(new Entity(name)); };
...
I have one method, say getHystrixClass(Class<A<B>> clazz). It requires input type of Class<A<B>> to pass in. How to do that? I have tried a few methods, but all of them failed at compilation time which are shown below with their corresponding error messages.
First trial
Put in class A
getHystrixClass(A.class)
ERROR MESSAGE : The method getHystrixClass(Class<A<B>>) in the type IHystrixProvider<A<B>> is not applicable for the arguments (Class<A>)
Second trial
Put in class B
getHystrixClass(B.class)
ERROR MESSAGE : The method getHystrixClass(Class<A<B>>) in the type IHystrixProvider<A<B>> is not applicable for the arguments (Class<B>)
Third trial
Put in class A<B>
getHystrixClass(A<B>.class)
ERROR MESSAGE : A cannot be resolved to a variable
Fourth trial
Create a dummy object and get class form it.
A<B> dummy = new A<B>();
getHystrixClass(dummy.getClass())
ERROR MESSAGE : The method getHystrixClass(Class<A<B>>) in the type IHystrixProvider<A<B>> is not applicable for the arguments (Class<capture#1-of ? extends A>)
Any hint? Sorry for my bad English.
Edit:
Hi, #GhostCat
The interface is look something like below
// Define by my team lead
public interface IHystrixProvider<T extends HystrixCommand, Rq> {
T getHystrixClass(Class<T> hystrixCommand);
}
/**
* #param <R> the return type
*/
public abstract class HystrixCommand<R> extends ... {
...
}
Code of HystrixCommand.java is public repository which can get from GitHub
You can pass Class<A<B>> using a (unchecked) cast - this is necessary because there is no Class object that represents the generic type A<B>, only one for the raw type A.
getHystrixClass((Class<A<B>>) (Class) A.class)
This will perform casts in the following order:
Class<A> (type of A.class) -> Class -> Class<A<B>>
Note that you first need the cast to raw Class in order to avoid an incompatible cast warning. Both casts also have zero runtime overhead, because the raw type (Class) stays the same, only the type arguments change.
I'm trying to make a method reference to a method which have a generic parameter specified in a class declaration.
So I have:
public interface IExecutable<P extends IParameter> {
void execute(P parameter);
}
public class Parameter implements IParameter {
public void childSpecific() {
...
}
}
public class TestClass {
...
//somewhere in the code
public void foo(Parameter parameter) {
parameter.childSpecific();
}
public void test() {
IExecutable<?> executable = this::foo; //compilation error
// The type TestClass does not define inner(IParameter) that is applicable here
executable.execute(new Parameter()); //compilation error as well
// The method execute(capture#4-of ?) in the type IExecutable<capture#4-of ?> is not applicable for the arguments (Parameter)
}
...
}
It's specific that I don't know the concrete generic type of the executable here. Using
IExecutable<Parameter> = ...
solves the problem immediately, but it's impossible for the case.
Clearly, I'm doing something wrong. But how to make it work?
Thx.
In this case, foo is not written to handle any IParameter other than Parameter. You could assign a reference to foo to a variable of type IExecutable<? extends IParameter>, however this means that it is an executable that handles some unknown type of IParameter (in this case, Parameter). Since the specific subtype is unknown, it would not be syntactically safe to pass any subtype of IParameter in to its execute method, since you don't know which it can handle within this scope!
What you need is another type variable instead of using a capture (the ?). This way you can specify that the IParameter you're passing in is the same type as the IParameter the executable accepts. You could introduce this with a new method, like I'm doing below:
public class TestClass {
public static void foo(Parameter parameter) {
parameter.childSpecific();
}
public static void main(String args) {
execute(TestClass::foo, new Parameter());
}
public static <P extends IParameter> void execute(
IExecutable<P> executable, P param) {
executable.execute(param);
}
}
The type parameter P in your interface IExecutable is constrained to being a subtype of IParameter. Consider these two subtypes:
class Parameter implements IParameter { ... }
class AnotherParameter implements IParameter { ... }
Now, an IExecutable<?> is not more specific regarding the above mentioned constraint. In fact, the ? states that it is bound to an unknown subtype of IParameter, which could be Parameter or AnotherParameter (in my example).
With such a variable declaration, you face the two problems you mentioned.
Your method foo(Parameter) does not match the more general constraint of an IExecutable<?>. As seen above, such an executable could be bound to AnotherParameter which clearly would violate the method signature of foo.
Even if it matched, it cannot be used like you did. The compiler does not know to which type the ? actually was mapped. The only thing it knows: It must be a subtype of IParameter, but which one is not known. That means, the statement executable.execute(new Parameter()) is not allowed (as also executable.execute(new AnotherParameter())). The only parameter you are allowed to pass to execute is null.
Conclusion: Point 1 could be solved by declaring the variable executable with type IExecutable<? extends Parameter>. This matches the method signature of foo. But point 2 still does not allow the call to execute.
The only thing you can do is to declare the variable as
IExecutable<Parameter> executable = this::foo;
This will compile and allow the call to
executable.execute(new Parameter());
This line exposes failure in java type inference
IExecutable<?> executable = this::foo;
Let's look at it this way
IExecutable<?> executable = p->this.foo(p);
To compile it, java needs to know the meaning of foo(p). Before java8, the type of an expression is built on the types of sub-expressions; here, the type of p needs to be known 1st to resolve foo. But the type of p is not specified, it needs to be inferred from surrounding context. Here the context is IExecutable<? extends IParameter>, and p is inferred to IParameter - and method foo(Iparameter) does not exist.
In general, type inference faces a dilemma, does it infer from top down, or bottom up? Java8 defines an extremely complicated procedure for that, which is humanly impossible to understand:)
Workarounds: specify the type of p
IExecutable<?> executable = (Parameter p)->this.foo(p);
or specify a more specific target type
IExecutable<?> executable = (IExecutable<Parameter>)p->this.foo(p);
IExecutable<?> executable = (IExecutable<Parameter>)this::foo;
If you ask the language designers, they'd consider all of this is quite obvious ... but a programmer's best action is probably just try different things till it works, than to study the actual language spec.
I've created a factory class in my project which would allow me (in theory) to create managers for any (supported) given type. Interacting with the manager allows me to alter certain properties of a given type. The problem I'm facing is when I attempt to create a manager for a generic type, the compiler crushes my hopes and dreams.
The following code is a stripped down version of what I'm working with. The line where I attempt to create my 'test3Manager' will not compile and I'm trying to understand why this is the case. The lines below it shows a 'workaround', which I'm trying to avoid.
import java.util.List;
public class GenTest {
public static void main(String[] args) {
String test1 = "";
IRandomType<String> test2 = null;
IAnotherRandomType<?> test3 = null;
IManager<String> test1Manager = Factory.createManager(test1);
IManager<IRandomType<String>> test2Manager = Factory.createManager(test2);
IManager<IAnotherRandomType<?>> test3Manager = Factory.createManager(test3); // Doesn't compile. Why?
// Work around?
IManager<?> test3ManagerTmp = Factory.createManager(test3);
IManager<IAnotherRandomType<?>> test3Manager2 = (IManager<IAnotherRandomType<?>>) test3ManagerTmp;
}
public interface IRandomType<T> {}
public interface IAnotherRandomType<T> {}
public interface IManager<T> {}
public static class Factory {
public static <T> IManager<T> createManager(T object) {
return null;
}
}
}
The exact compile error message is:
Type mismatch: cannot convert from GenTest.IManager<GenTest.IAnotherRandomType<capture#1-of ?>> to GenTest.IManager<GenTest.IAnotherRandomType<?>>
Similar questions have been asked before (see below); however, I don't know if this question is considered a duplicate of them. I only state this since I'm having trouble inferring answers from these questions to mine. I'm hoping someone could clarify what I'm doing wrong with my use of generics.
Related questions on SO are:
Bounded-wildcard related compiler error
Incompatible wildcard types that should be compatible
Use the following:
IManager<IAnotherRandomType<?>> test3Manager =
Factory.<IAnotherRandomType<?>>createManager(test3);
This is just a case of the compiler's type inference falling on its face, so it's necessary explicitly provide the type argument for T.
More technically:
test3 is declared to have the type IAnotherRandomType<?>, where ? is a wildcard capture - a sort of one-use type parameter representing some specific unknown type. That's what the compiler's referring to when it says capture#1-of ?. When you pass test3 into createManager, T gets inferred as IAnotherRandomType<capture#1-of ?>.
Meanwhile, test3Manager is declared to have the type IManager<IAnotherRandomType<?>>, which has a nested wildcard - it does not behave like a type parameter but rather represents any type.
Since generics aren't covariant, the compiler can't convert from IManager<IAnotherRandomType<capture#1-of ?>> to IManager<IAnotherRandomType<?>>.
More reading on nested wildcards:
Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
Java Generic List<List<? extends Number>>
Which super-subset relationships exist among wildcards?