groovy-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Paul King (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (GROOVY-8760) can't instantiate a class that inherits from base class marked with @MapConstructor
Date Tue, 21 Aug 2018 22:54:00 GMT

    [ https://issues.apache.org/jira/browse/GROOVY-8760?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16588117#comment-16588117
] 

Paul King commented on GROOVY-8760:
-----------------------------------

The first statement automatically added for any constructor is a call to {{super()}} unless
you have an explicit call to {{super}} yourself. This also applies to the generated MapConstructor
for B. Note that the {{super()}} call has no args so expects to find a no-arg constructor
in A. Adding MapConstructor on A adds a constructor with a Map argument which removes the
automatic no-arg constructor that would be added otherwise.
 Many combinations will work depending on what you are trying to do:
 (1) Don't use any AST transforms. Named argument calling is still supported without it. It
will call the no-arg constructor followed by setters. You can't have final properties except
constants.
{code:java}
import groovy.transform.*

class A {
  final long id = new Random().nextInt()
  String name
  Boolean isDead

  String toString() {
    "A ($name, id:$id)"
  }
}

class B extends A {
  String extra
  String toString() {
     "B ($name, id:$id, extra:$extra, isDead:$isDead)"
  }
}

def myA = new A(name:"will")
println myA

def myB = new B(name:"fred", isDead: true, extra: 'foo')
println myB
{code}
(2) You can use {{@MapConstructor}} on A and {{@InheritConstructors}} on B provided you have
no additional properties in B - this will call {{super}} correctly and allows properties to
be final - so long as they are only set in the constructor.
{code:java}
import groovy.transform.*

@MapConstructor (post = {id = new Random().nextInt() })
class A {
  final long id
  final String name
  Boolean isDead

  String toString() {
    "A ($name, id:$id)"
  }
}

@InheritConstructors
class B extends A {
  String toString() {
     "B ($name, id:$id, isDead:$isDead)"
  }
}

def myA = new A(name:"will")
println myA

def myB = new B(name:"fred", isDead: true)
println myB
{code}
(3) Use MapConstructor (allowing e.g. final properties) and add a corrected call to super
yourself in {{pre}}.
{code:java}
import groovy.transform.*

@MapConstructor (post = {id = new Random().nextInt() })
class A {
  final long id
  final String name
  Boolean isDead

  String toString() {
    "A ($name, id:$id)"
  }
}

@MapConstructor (pre = { super(args) }) // post not needed since called in super
class B extends A {
  final String extra
  String toString() {
     "B ($name, id:$id, extra:$extra)"
  }
}

def myA = new A(name:"will")
println myA

def myB = new B(name:"fred", extra: 'foo')
println myB
{code}
(4) Use {{includeSuperProperties}} in B and {{noArg}} in A.
{code:java}
import groovy.transform.*

@MapConstructor (noArg = true)
class A {
  final long id = new Random().nextInt()
  String name
  Boolean isDead

  String toString() {
    "A ($name, id:$id)"
  }
}

@MapConstructor (includeSuperProperties = true)
class B extends A {
  final String extra
  String toString() {
     "B ($name, id:$id, extra:$extra, isDead:$isDead)"
  }
}

def myA = new A(name:"will")
println myA

def myB = new B(name:"fred", isDead: true, extra: 'foo')
println myB
{code}

> can't instantiate a class that inherits from base class marked with @MapConstructor
> -----------------------------------------------------------------------------------
>
>                 Key: GROOVY-8760
>                 URL: https://issues.apache.org/jira/browse/GROOVY-8760
>             Project: Groovy
>          Issue Type: Bug
>          Components: groovy-runtime
>    Affects Versions: 2.5.1
>         Environment: intellij 2018.1.4, java jdk 8.0_172, groovy 2.5.1
>            Reporter: William Woodman
>            Priority: Major
>              Labels: features
>
> basic inheritance where parent is tagged with @MapConstructor then child class cant be
instantiated
> example as follows 
>  
> {code}
> @MapConstructor
> class A {
>  String name
>  A() {}
>  String toString() {
>  "A ($name)"
>  }
> }
> class B extends A {
>  String toString() {
>  "B ($name)"
>  }
> }
> def myA = new A(name:"will")
> println myA
> def myB = new B(name:"fred")
> println myB
> {code}
> run this and get a RT exception 
> {noformat}
> A (will)
> Caught: java.lang.NoSuchMethodError: com.softwood.scripts.A: method <init>()V not
found
> java.lang.NoSuchMethodError: com.softwood.scripts.A: method <init>()V not found
>  at com.softwood.scripts.B.<init>(TestOfferingAttributeGroup.groovy)
>  at com.softwood.scripts.TestOfferingAttributeGroup.run(TestOfferingAttributeGroup.groovy:28)
> {noformat}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Mime
View raw message