[
https://issues.apache.org/jira/browse/GROOVY-11508?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17892860#comment-17892860
]
Jochen Theodorou commented on GROOVY-11508:
-------------------------------------------
[~jdaugherty]
I think that we are talking about a trait is a bit of a false flag in the end.
This code here
{code:java}
interface GormEntity<D> {}
class Child implements GormEntity<Child> {}
class Parent extends Child implements GormEntity<Parent> {}
{code}
Has no traits, no (static) methods nothing, still the Java compiler does not
accept this. The connection to traits comes in play if you do not forget that
there is the trait GormEntity for Groovy, but for the JVM this consists of the
interface of the same name and some helper classes. Which means we get exactly
the above situation, even if you remove all the otherwise generated code.
And for the reasoning behind this I have this here
[https://bugs.openjdk.org/browse/JDK-8030724] as an interesting read.
Then there is the issue with the injected method getAll. In case of
{code:java}
trait GormEntity<Integer> {
static List<Integer> getAll() {null}
}
class Parent implements GormEntity {}
{code}
Here Integer is not the class Integer, it is the generics placeholder like you
normally use T:
{code:java}
trait GormEntity<D> {
static List<D> getAll() {null}
}
class Parent implements GormEntity {}
{code}
Since the base type for D is Object using GormEntity is equal to
GormEntity<Object>
Now coming back to the original problem.... According to
[http://docs.groovy-lang.org/docs/groovy-2.3.0/html/documentation/core-traits.html#_default_conflict_resolution]
we have a conflict resolution specified in case of two traits providing a
method with equal signature. That means in case of X implements
GormEntity<String>, GormEntity<Integer> we would have a getAll returning
List<Integer> and in the reverse case List<String>. Let us assume we have
{code:java}
trait GormEntity<D1> {
List<D1> getAll() {null}
}
trait GormEntity2<D2> {
List<D2> getAll() {null}
}
class Child implements GormEntity<Child>{}
class Parent extends Child implements GormEntity2<Parent> {}
{code}
So without the static modifier. Then we get a List<Child>, that looks like
List<Object> in Child and a List<Parent>, that looks like List<Object> in
Parent, overriding the one in child, because the method signatures are equal
after type erasure. That means Parent will have the method from GormEntity2.
Now assume this in Java:
{code:java}
Parent parent = new Parent()
Child child = parent
List<Child> lc = child.getAll()
List<Parent> ld = parent.getAll()
{code}
How can calling the same method produce one time List<Child> and another time
List<Parent>? It cannot, and the Java compiler would refuse compiling the line
for lc.. Therefore I am not really too keen on allowing the implementation of
multiple parametrized interfaces of same name with different parameter
configurations. In theory it could be allowed unless there is a conflict, but
then there is the recompilation issue... feels like a can of worms to reopen
here.
Which means for me that the case of a static modifier is actually something
where we have to take different aspects into consideration. One of them being
that static methods are not really inherited like in the last variant.
Parent.getAll() can call a different method than Child.getAll(). And
[http://docs.groovy-lang.org/docs/groovy-2.3.0/html/documentation/core-traits.html#_static_methods_properties_and_fields]
states that static methods are experimental.
My suggestion would be to modify the way static aspects work by add an
annotation preventing the trait interface to be added to the class receiving
the trait.
This would solve the problem for the static methods by simply putting them in a
trait and use the annotation for the marker interface to not be used. Looking
at
https://github.com/grails/grails-data-mapping/blob/9.0.x/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormEntity.groovy
I see two more groups of methods though... MOP related methods without
generics, which are no problem... but then also methods like save(). Or as you
mentioned already, refresh().
There would be in theory a solution using extension methods. Of course that
means they are not callable from Java, not normally.
> Multiple traits with related generic types cannot be used
> ---------------------------------------------------------
>
> Key: GROOVY-11508
> URL: https://issues.apache.org/jira/browse/GROOVY-11508
> Project: Groovy
> Issue Type: Bug
> Components: Compiler
> Affects Versions: 4.0.0
> Reporter: James Daugherty
> Assignee: Eric Milles
> Priority: Major
> Attachments: screenshot-1.png, screenshot-2.png, screenshot-3.png
>
>
> When updating Grails from Groovy 3.x to 4.x we discovered that GROOVY-5106
> prevents us from updating to Groovy 4 for the
> [grails-data-mapping|https://github.com/grails/grails-data-mapping] (GORM)
> project. Groovy-5106 does not take into account relationships between
> generic types and groovy does not support inheritance in generic types on
> traits so we have no workable solution for using Groovy 4.
>
> For example, the following is not possible in Groovy 4:
> {code:java}
> class Parent extends GormEntity<Parent> {
> }
> class Child extends GormEntity<Child> {
> }
> class GormEntity<? extends GormEntity> { // ? extends GormEntity is not
> allowed
> }{code}
>
> We have documented the impacts of this issue on the grails-data-mapping
> project here: [https://github.com/grails/grails-data-mapping/issues/1811]
> We have discovered that the original change could be reverted and continue to
> work with the latest Java & Groovy.
>
> For Grails Data Mapping (GORM), there is support for inheritance between a
> Parent & Child domain object. This is often implemented like this:
> {code:java}
> class Parent extends GormEntity<Parent> {
> }
> class Child extends GormEntity<Child> {
> }
> trait GormEntity<D> { // Simplified for this ticket
> static D get(Serializable id)
>
> static List<D> getAll()
> }
> {code}
> This allows someone to do the following in code:
> {code:java}
> Parent.get(1L) // Will find either a Child or Parent
> Child.get(1L) // Will find only child types{code}
>
> Since Groovy-5106 does not take into account inheritance, can this change be
> reverted or changed to a warning until inheritance is taken into account?
--
This message was sent by Atlassian Jira
(v8.20.10#820010)