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] [Comment Edited] (GROOVY-8186) Builder ExternalStrategy constructors have trouble with private fields
Date Mon, 15 May 2017 01:22:04 GMT

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

Paul King edited comment on GROOVY-8186 at 5/15/17 1:21 AM:
------------------------------------------------------------

For case (1), which is when the builder class and buildee class are in the same compilation
unit, you are correct that JavaBean properties aren't considered, just standard Groovy properties.
We probably should change this. I suspect what we do for {{@ToString}}, where the underlying
transform calls {{BeanUtils.getAllProperties}} to get the complete set of properties, is the
way to go.

For case (2), it isn't really Groovy vs Java but whether the class is pre-compiled or not.
When pre-compiled, {{@Builder}} uses standard JavaBean introspection to find the properties.
If the parameter type of the setter doesn't match with the return type of the getter, the
property is deemed read-only from a JavaBean perspective (and there just happens to be a setter-like
named method also existing with a different parameter type):
{code}
def personClass = new GroovyShell().evaluate '''
class GroovyPerson {
    private Set<String> pets
    //Collection<String> getPets() { pets }
    Set<String> getPets() { pets }
    //void setPets(Set<String> pets) {
    void setPets(Collection<String> pets) {
        this.pets = pets == null ? Collections.emptySet() : new LinkedHashSet<String>(pets)
    }
}
GroovyPerson
'''
java.beans.Introspector.getBeanInfo(personClass).propertyDescriptors.each { pd ->
    if (!['class', 'metaClass'].contains(pd.name))
        println "$pd.name $pd.propertyType.name $pd.writeMethod"
}
{code}
The null {{writeMethod}} indicates a read-only property. Uncomment either of the commented
out lines (and remove the appropriate existing line) to see the property reappear.
I suspect we don't want to change that but I haven't checked what case (1) does in that situation
yet - if we were to fix it as per above.


was (Author: paulk):
For case (1), which is when the builder class and buildee class are in the same compilation
unit, you are correct that JavaBean properties aren't considered, just standard Groovy properties.
We probably should change this. I suspect what we do for {{@ToString}}, where the underlying
transform calls {{BeanUtils.getAllProperties}} to get the complete set of properties, is the
way to go.

For case (2), it isn't really Groovy vs Java but whether the class is pre-compiled or not.
When pre-compiled, {{@Builder}} uses standard JavaBean introspection to find the properties.
If the parameter type of the setter doesn't match with the return type of the getter, the
property is deemed read-only from a JavaBean perspective (and there just happens to be a setter-like
named method also existing with a different parameter type):
{code}
def personClass = new GroovyShell().evaluate '''
class GroovyPerson {
    private Set<String> pets
    //Collection<String> getPets() { pets }
    Set<String> getPets() { pets }
    //void setPets(Set<String> pets) {
    void setPets(Collection<String> pets) {
        this.pets = pets == null ? Collections.emptySet() : new LinkedHashSet<String>(pets)
    }
}
GroovyPerson
'''
java.beans.Introspector.getBeanInfo(personClass).propertyDescriptors.each { pd ->
    if (!['class', 'metaClass'].contains(pd.name))
        println "$pd.name $pd.propertyType.name $pd.writeMethod"
}
{code}
The null {{writeMethod}} indicates a read-only property. Uncomment either of the commented
out lines to see the property reappear.
I suspect we don't want to change that but I haven't checked what case (1) does in that situation
yet.

> Builder ExternalStrategy constructors have trouble with private fields
> ----------------------------------------------------------------------
>
>                 Key: GROOVY-8186
>                 URL: https://issues.apache.org/jira/browse/GROOVY-8186
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 2.4.x, 2.5.x
>            Reporter: Jason Terhune-Wold
>            Priority: Minor
>
> An undocumented feature of @Builder is that the builder's constructor can set default
values for the fields. See http://stackoverflow.com/questions/35066664/default-values-in-groovy-builder-ast
> I tried creating an ExternalStrategy @Builder annotation for [BaseClientDetails|http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/provider/client/BaseClientDetails.html]
with a constructor that set a default scope. I received a MissingMethodException exception,
which I thought was odd.
> I added some tests to BuilderTransformTest that demonstrate apparent problems using the
external builder in two situations:
> 1) A groovy class with private fields and manually defined setters.
> 2) A java class with a private Set field and a setter that takes a Collection
> The tests are here: https://github.com/jterhune/groovy/commit/5b2eb74cc8184235b5235b7fd4c80b241799bbc5
> I noticed this in 2.4.x. My tests fail in the 2.5.x branch also.



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

Mime
View raw message