Type erasure problem - implementing interface in groovy which implements two generic Java interfaces

View: New views
3 Messages — Rating Filter:   Alert me  

Type erasure problem - implementing interface in groovy which implements two generic Java interfaces

by HamletDRC :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I get a compile error in Groovy 1.5.6 and I think it is a problem with type erasure. Does anyone know if I'm doing something wrong here? Or can I not do this in Groovy?

(Apologies in advance if the code formatting is bad)

I have a Groovy implementation of a Java interface which fails to compile. The Java interface in turn extends two other Java interfaces, both of which have generic types.

If I define everything in Groovy then it works... I have a Validator and Transformer interface, and a ValidatingTransformer interface which extends them both:

interface Validator <T, U> {
        U isValid(T target);
}

interface Transformer<T, U> {
        U transform(T target);
}

interface ValidatingTransformer<T, U, V> extends Validator<T, U>, Transformer<T, V> {
}

So long as these interfaces are all defined in Groovy, then I can implement the ValidatingTransformer with a Groovy object and the object compiles:

class ValidatingTransformerImpl implements ValidatingTransformer<String, Boolean, Integer> {
        public Boolean isValid(String target) {
                return null    // do some validation
        }

        public Integer transform(String target) {
                return null    // do some transformation
        }
}

However, if I define Validator, Transformer, and ValidatingTransformer as Java objects, then the ValidatingTransformerImpl fails to compile with the following error message: "Can't have an abstract method in a non-abstract class. The class 'ValidatingTransformerImpl' must be declared abstract or the method 'java.lang.Object transorm(java.lang.Object)' must be implemented", and a similar message for the isValid method.

So, the interface methods clearly have their types erased to objects as one would expect. So once the Java is compiled, then the Groovy compiler tries to match the methods in ValidatingTransformerImpl with an Object signature and they aren't found... the ValidatingTransformerImpl does not have those methods because it's types aren't erased yet. Is that correct?

For my project, the interfaces _must_ be declared in Java because of our architectural rules about having a one way compile time dependency between Java and Groovy. One workaround is for the ValidatingTransformerImpl to implement both the parent interfaces separately and abandon the idea of a ValidatingTransformer; however, this is undesirable because it would force calling code to maintain two references to the same object: once as a validator and once as a transformer. A workaround that does work for us is to redefine the transform() and isValid() method in the ValidatingTransformer interface. This will trigger the Groovy code to compile but I don't exactly know why this works.

Is this a defect?
Why isn't this compiling?
Why does redefining the interface methods in ValidatingTransformer work?

Thanks in advance,
Hamlet D'Arcy
--
Hamlet D'Arcy

Re: Type erasure problem - implementing interface in groovy which implements two generic Java interfaces

by Randall Schulz :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Monday 10 November 2008 08:14, HamletDRC wrote:
> I get a compile error in Groovy 1.5.6 and I think it is a problem
> with type erasure. Does anyone know if I'm doing something wrong
> here? Or can I not do this in Groovy?
>
> (Apologies in advance if the code formatting is bad)

Everyone's code formatting is bad except mine, of course...


> I have a Groovy implementation of a Java interface which fails to
> compile. The Java interface in turn extends two other Java
> interfaces, both of which have generic types.
>
> If I define everything in Groovy then it works... I have a Validator
> and Transformer interface, and a ValidatingTransformer interface
> which extends them both:
>
> interface Validator <T, U> {
> U isValid(T target);
> }
>
> interface Transformer<T, U> {
> U transform(T target);
> }
>
> interface ValidatingTransformer<T, U, V> extends Validator<T, U>,
> Transformer<T, V> {
> }
>
> So long as these interfaces are all defined in Groovy, then I can
> implement the ValidatingTransformer with a Groovy object and the
> object compiles:
>
> class ValidatingTransformerImpl implements
> ValidatingTransformer<String, Boolean, Integer> {
> public Boolean isValid(String target) {
> return null    // do some validation
> }
>
> public Integer transform(String target) {
> return null    // do some transformation
> }
> }
>
> However, if I define Validator, Transformer, and
> ValidatingTransformer as Java objects, then the
> ValidatingTransformerImpl fails to compile with the following error
> message: "Can't have an abstract method in a non-abstract class. The
> class 'ValidatingTransformerImpl' must be declared abstract or the
> method 'java.lang.Object transorm(java.lang.Object)' must be
> implemented", and a similar message for the isValid method.

I believe the problem is a mismatch of your template vs. actual types:

T: String
U: Boolean
V: Integer

Both isValid() and transform() must return U (Boolean in your
implementing class), but your actual method definitions have one
returning Boolean and the other returning Integer.


> ...
>
> Thanks in advance,
> Hamlet D'Arcy


Randall Schulz

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Type erasure problem - implementing interface in groovy which implements two generic Java interfaces

by HamletDRC :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I'm afraid that isn't it... don't be confused by the fact that both interfaces define T and U... the child interface defines T, U, and V and the type parameters certainly do line up correctly.

As evidence, the following implementation (in Java) compiles just fine:

public class ValidTranfromImplJava implements ValidatingTransformer<String, Boolean, Integer> {

        public Boolean isValid(String target) {
                try {
                        Integer.valueOf(target);
                        return true;
                } catch (NumberFormatException ignored) {
                        return false;
                }
        }


        public Integer transform(String target) {
                return Integer.valueOf(target);
        }
}



Randall Schulz wrote:
On Monday 10 November 2008 08:14, HamletDRC wrote:
> I get a compile error in Groovy 1.5.6 and I think it is a problem
> with type erasure. Does anyone know if I'm doing something wrong
> here? Or can I not do this in Groovy?
>
> (Apologies in advance if the code formatting is bad)

Everyone's code formatting is bad except mine, of course...


> I have a Groovy implementation of a Java interface which fails to
> compile. The Java interface in turn extends two other Java
> interfaces, both of which have generic types.
>
> If I define everything in Groovy then it works... I have a Validator
> and Transformer interface, and a ValidatingTransformer interface
> which extends them both:
>
> interface Validator <T, U> {
> U isValid(T target);
> }
>
> interface Transformer<T, U> {
> U transform(T target);
> }
>
> interface ValidatingTransformer<T, U, V> extends Validator<T, U>,
> Transformer<T, V> {
> }
>
> So long as these interfaces are all defined in Groovy, then I can
> implement the ValidatingTransformer with a Groovy object and the
> object compiles:
>
> class ValidatingTransformerImpl implements
> ValidatingTransformer<String, Boolean, Integer> {
> public Boolean isValid(String target) {
> return null    // do some validation
> }
>
> public Integer transform(String target) {
> return null    // do some transformation
> }
> }
>
> However, if I define Validator, Transformer, and
> ValidatingTransformer as Java objects, then the
> ValidatingTransformerImpl fails to compile with the following error
> message: "Can't have an abstract method in a non-abstract class. The
> class 'ValidatingTransformerImpl' must be declared abstract or the
> method 'java.lang.Object transorm(java.lang.Object)' must be
> implemented", and a similar message for the isValid method.

I believe the problem is a mismatch of your template vs. actual types:

T: String
U: Boolean
V: Integer

Both isValid() and transform() must return U (Boolean in your
implementing class), but your actual method definitions have one
returning Boolean and the other returning Integer.


> ...
>
> Thanks in advance,
> Hamlet D'Arcy


Randall Schulz

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email

--
Hamlet D'Arcy