Java ambiguous type for method? - java

EDIT: This turned out not be a problem with the code at all, but with a bug in the Groovy Eclipse plugin (http://jira.codehaus.org/browse/GRECLIPSE-373)
Eclipse is giving me a weird error message about ambiguous types in a Java program and I really don't understand why. I have an interface that takes a generic parameter indicating what type of data it returns.
public interface InterfaceA<T> {
T getData();
}
One of the implementations of it looks like this:
public class Impl<T extends AnotherClass> implements InterfaceA<Collection<T>> {
public Collection<T> getData() {
// get the data
}
}
There is also a container for an InterfaceA
public class Container<T extends InterfaceA>
{
private T a;
public Container(T a) {
this.a = a;
}
public T getA() {
return a;
}
}
Doing this causes the "getData is ambiguous" error.
Container<Impl<AnotherClass>> c = new Container(new Impl<AnotherClass>());
Collection<AnotherClass> coll = c.getA().getData();
I'm stumped on this one.

There appears to be a bug causing this from the groovy plugin. http://jira.codehaus.org/browse/GRECLIPSE-373. It is not a java problem at all. Thanks for the help and my apologies.

Collection<T> getData() defined in Impl needs to be made public. If I do this the code compiles cleanly for me.

As other posters have said, I am not seeing this problem on Eclipse 3.5.0 running on JDK 1.6.0.14 (when fixing the reduced visibility of the getData() method).
I suggest doing a clean build (Project/Clean in Eclipse). Also, the Eclipse and Java version you are running might help.
-- Flaviu Cipcigan

Your edited example works fine for me (JDK 1.5) with the exception, that you have to define the generic type on the constructor. Here is my complete working code:
public interface InterfaceA<T> {
T getData();
}
public static class Impl<T extends Date> implements InterfaceA<Collection<T>> {
public Collection<T> getData() {
return null;
}
}
public static class Container<T extends InterfaceA> {
private T a;
public Container(T a) {
this.a = a;
}
public T getA() {
return a;
}
}
public static void main(String[] args) {
Container<Impl<Date>> c = new Container<Impl<Date>>(new Impl<Date>());
Collection<Date> coll = c.getA().getData();
}

[Edit to reflect updated question]
This shouldn't even compile as you are reducing the visibility of the method from public to package scope:
public class Impl<T extends AnotherClass> implements InterfaceA<Collection<T>> {
Collection<T> getData() {
// get the data
}
}
And this still compiles for me (Eclispe 3.4, OS X, 1.5), so don't know what exactly is the issue:
package temp.tests;
import java.util.Collection;
public interface InterfaceA <T> {
T getData();
public static final class AnotherClass {}
public static final class Impl<T extends AnotherClass>
implements InterfaceA<Collection<T>>
{
public Collection<T> getData () {
return null;
}
}
public static class Container<T extends InterfaceA>
{
private T a;
public Container(T a) { this.a = a; }
public T getA() { return a; }
}
public static final class Test {
public static void main (String[] args) {
Container<Impl<AnotherClass>> c = new Container(new Impl<AnotherClass>());
Collection<AnotherClass> coll = c.getA().getData();
}
}
}

What you have here seems legitimate. Perhaps Eclipse is showing an error it otherwise should not.
Go to Windows > Preferences > Java > Compiler > Errors/Warnings. In the "Generic Types" section, ensure that Eclipse isn't reporting an error for any of the operations listed (unless you want it too). I have all mine in that section set to "Warning". I would then try refreshing the project and restarting Eclipse.
Edit:
After the updated post was made, I got a warning (not an error still) on the lines of usage, saying "Container is a raw type. References to generic type Container should be parameterized:". This can be fixed by:
Container<Impl<Date>> c = new Container<Impl<Date>>(new Impl<Date>());
(In my example, I'm using java.util.Date as in place of 'AnotherClass').

Related

Weird compile-time error only when class is generic

The following code compiles fine:
public class Test {
public static interface A<Y> {
public B<Y> foo();
}
public static interface B<Y> extends A<Y> {
public A<Y> bar();
}
private static class Impl
implements A, B
{
public B foo() {
return this;
}
public A bar() {
return null;
}
}
}
But when a generic parameter is introduced to top-level class Test the code no longer compiles:
public class Test<X> {
public static interface A<Y> {
public B<Y> foo();
}
public static interface B<Y> extends A<Y> {
public A<Y> bar();
}
private static class Impl
implements A, B
{
public B foo() {
return this;
}
public A bar() {
return null;
}
}
}
The error I get is:
The interface A cannot be implemented more than once with different arguments: Test.A and Test.A
What causes this weird compilation error? What can be done to fix it?
By the way, I use eclipse and Java 1.8.0_144.
Thanks for your help.
As has been suggested by Andy Turner in the comments this is a compiler bug. When compiling with the command line and javac both versions compile just fine. Only within eclipse (using the build in eclipse compiler) does the error occur.
The eclipse version where the bug occured is indeed quite outdated:
Version: Oxygen Release (4.7.0)
Build id: 20170620-1800
The bug appears to have been fixed in later versions of eclipse.

Proxy a private interface

I'm in a situation where I really need to proxy a private inner java interface of a class with a protected constructor.
I'm stuck with existing compiled java code:
public class Foo {
Foo() {}
private interface Bar {
void someMethod();
}
}
And trying to write this clojure code:
(proxy [Foo$Bar] []
(someMethod []
...))
But compiling this throws java.lang.IllegalAccessError "proxy... cannot access its superinterface Foo$Bar".
Is there some incantation that can get around this? I'd be happy to use whatever dirty tricks are necessary.
The answer is to extend the original class, and copy the interface while marking it as public access:
package demo;
public class Calc {
Calc() {
System.out.println( "Calc() constructor");
}
private interface Adder {
String doSomething();
}
}
with the new child class:
package demo;
public class CalcChild extends Calc {
public CalcChild() {
super();
System.out.println("CalcChild(): super() - return ");
}
public interface Adder {
String doSomething();
}
public void doBoo() {
System.out.println("Boo!");
}
}
And the proxy code:
(let [adder (proxy [demo.CalcChild$Adder] []
(doSomething [] "something"))
calcChild (demo.CalcChild.)]
(.doSomething adder)
(.doBoo calcChild))
with result:
Calc() constructor
CalcChild(): super() - return
(.doSomething adder) => "something"
Boo!
Update:
I Updated the answer, but something is still not right. Even if I comment out the new CalcChild() constructor, I can't reproduce your error.

Generics and casting to the right type

My problem can be summed-up by this snippet:
public interface TheClass<T> {
public void theMethod(T obj);
}
public class A {
private TheClass<?> instance;
public A(TheClass<?> instance) {
this.instance = instance;
}
public void doWork(Object target) {
instance.theMethod(target); // Won't compile!
// However, I know that the target can be passed to the
// method safely because its type matches.
}
}
My class A uses an instance of TheClass with its generics type unknown. It features a method with a target passed as Object since the TheClass instance can be parameterized with any class. However, the compiler won't allow me to pass the target like this, which is normal.
What should I do to circumvent this issue?
A dirty solution is to declare the instance as TheClass<? super Object>, which works fine but is semantically wrong...
Another solution I used before was to declare the instance as raw type, just TheClass, but it's bad practice, so I want to correct my mistake.
Solution
public class A {
private TheClass<Object> instance; // type enforced here
public A(TheClass<?> instance) {
this.instance = (TheClass<Object>) instance; // cast works fine
}
public void doWork(Object target) {
instance.theMethod(target);
}
}
public class A {
private TheClass<Object> instance;
public A(TheClass<Object> instance) {
this.instance = instance;
}
public void do(Object target) {
instance.theMethod(target);
}
}
or
public class A<T> {
private TheClass<T> instance;
public A(TheClass<T> instance) {
this.instance = instance;
}
public void do(T target) {
instance.theMethod(target);
}
}
The solution is to also type A. Using a wildcard ? makes you loose the type information of TheClass and there is no way to recover it later. There are some ugly hacks you could do but your best shot is to also type A:
public interface TheClass<T> {
public void theMethod(T obj);
}
public class A<T> {
private TheClass<T> instance;
public A(TheClass<T> instance) {
this.instance = instance;
}
public void doIt(T target) {
instance.theMethod(target);
}
}
It won't break any API either.
The reason for the compile error is that the ? wildcard indicates the unknown type in Java. You may declare a variable with an unknown generic parameter, but you cannot instantiate one with it. Which means that the in your constructor the passed in generic class could have been created to hold types that are incompatible with what you are trying to later on use. Case in point:
public class A {
public static void main(String[] args) {
TheClass<String> stringHolder = null; // should constrain parameters to strings
A a = new A(stringHolder);
a.donot(Float.valueOf(13)) ; // this is an example of what could happen
}
private TheClass<?> instance;
public A(TheClass<?> instance) {
this.instance = instance;
}
public void do(Object target) {
instance.theMethod(target);
}
}
In this case the compiler is preventing you from writing code that would have been prone to bugs. As others have pointed out, you should add a generic parameter type to your A class, in order to constrain the allowed types - that will remove the compile time error.
Some suggested reading: Oracle Generics Trail

Inherit method with unrelated return types

I have the following code snippet
public class Test {
static interface I1 { I1 m(); }
static interface I2 { I2 m(); }
static interface I12 extends I1,I2 { I12 m(); }
public static void main(String [] args) throws Exception {
}
}
When I try to compile it I got error.
Test.java:12: types Test.I2 and Test.I1 are incompatible; both define m(), but with unrelated return types.
How to avoid this?
As discussed in Java - Method name collision in interface implementation you can't do this.
As a workaround, you can create an adapter class.
There is only one case in which this would work, which is mentioned by xamde, but not thoroughly explained. It's related to covariant return types.
In the JDK 5 the covariant returns where added, and as such the following is a valid case that would compile fine and run without problems.
public interface A {
public CharSequence asText();
}
public interface B {
public String asText();
}
public class C implements A, B {
#Override
public String asText() {
return "C";
}
}
Therefore, the following will run without errors and print "C" to the main output:
A a = new C();
System.out.println(a.asText());
This works because String is a subtype of CharSequence.
This is a bug in Sun's Java 6 compiler.
I had the same problem and it seems to be fine by using the JDK 7 from Oracle.

Error Generic Method in java

package com.openwaf.test.basic;
public class MethodArgumentTest {
static interface Inf{}
static class One<E extends Inf > implements Inf{
public <T extends One> T get(T k){
return k;
}
}
static class Two<E extends Inf> extends One<E>{ }
public static void test(){
One o=new One<Inf>();
Two t=new Two<One>();
o.<Two>get(t);
}
}
Above code is just for testing purpose. IMHO it should compile without any problem ,but java compiler says
MethodArgumentTest.java:15:
get(com.openwaf.test.basic.MethodArgumentTest.One) in
com.openwaf.test.basic.MethodArgumentTest.One cannot be applied to
(com.openwaf.test.basic.MethodArgumentTest.Two)
o.get(t);
1 error
Can someone please help me out here ?
Ok, as you said this is for testing only I will not ask what this code is good for. The following one compiles but still produces a warning. You were not consequent enough defining the generics:
public class MethodArgumentTest {
static interface Inf {
}
static class One<E extends Inf> implements Inf {
public <T extends One<E>> T get(T k) {
return k;
}
}
static class Two<E extends Inf> extends One<E> {
}
public static void test() {
One<Inf> o = new One<Inf>();
Two<One<Inf>> t = new Two<One<Inf>>();
o.<Two> get(t); /* unchecked warning */
}
}
I think what you need to do is
Two tPrime= o.get(t);

Categories