Weird compile-time error only when class is generic - java

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.

Related

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.

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);

Returning a Subclass in Java when a Superclass is Expected

Edit: This didn't work because I had:
class Animal { ... }
class Horse extends Animal { ... }
class Unicorn extends **Animal** { ... }
Clearly, this is a typo, and Unicorn is supposed to extend Horse, not animal. And here, I thought I found a hole in Java's polymorphism!
Maybe it's just me, but this doesn't make sense. Let's assume I have two classes in Java, Horse and Unicorn (which is a subclass of Horse):
public class Horse {
public String speak() {
return "Wow, a talking horse!";
}
}
public class Unicorn extends Horse {
#Override
public String speak() {
return "Unicorns really exist?!";
}
}
This code doesn't compile:
public Horse getHorse() {
return new Unicorn(); // Doesn't compile
}
I get the compilation error "Cannot convert from Unicorn to Horse" under Eclipse using JRE or JSE 1.6.
Why doesn't it compile? Every unicorn is also a horse, and therefore, I'm returning a valid instance of horse ... aren't I?
My question is really about how polymorphism works in Java. I expect this to work. For what it's worth, this code compiles in .NET 2.0 (maybe that's why I expect it to work in Java, too).
Did you write it exactly like this? because you can't have the parentheses in class definitions... e.g.
public class Horse() {
should be
public class Horse {
also
public class Unicorn extends Horse() {
should be
public class Unicorn extends Horse {
Works as expected:
Probably your error, is you have both classes defined in the same source file.
There should be only one public class per file ( or as in my case, many non public )
But, without the exact error message is only speculation.
This works:
public class Test {
public static class Horse {
public void speak() {
System.out.println("I'm a horse");
}
}
public static class Unicorn extends Horse {
public void speak() {
System.out.println("I'm a unicorn");
}
}
public static void main(String[] args) {
getHorse().speak();
}
public static Horse getHorse() {
return new Unicorn();
}
}
It's not fundamentally different from what you claim to be doing, so your problem must be elsewhere.

Java ambiguous type for method?

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').

Categories