You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Paul King (JIRA)" <ji...@apache.org> on 2015/05/08 06:01:59 UTC

[jira] [Created] (GROOVY-7417) @EqualsAndHashCode inconsistent when using boolean properties for classes with explicit getters

Paul King created GROOVY-7417:
---------------------------------

             Summary: @EqualsAndHashCode inconsistent when using boolean properties for classes with explicit getters
                 Key: GROOVY-7417
                 URL: https://issues.apache.org/jira/browse/GROOVY-7417
             Project: Groovy
          Issue Type: Bug
    Affects Versions: 2.4.3
            Reporter: Christopher Smith
            Priority: Critical


I have the following class representing a location in Amazon S3. Depending on some inner business logic, I often need to split the object key into a prefix and a file name, so I access them all through the {{getKey()}} method; with S3, the only thing that matters is the final concatenated string.

The generated {{equals}} method incorrectly returns true for any two objects with the same bucket, ignoring the key property. (I discovered this when I got some interesting results out of a JSR-330 cache.) I have marked this issue critical because it is likely to cause immediate security vulnerabilities and data loss when unequal objects are found equal.

{code}
@CompileStatic
@EqualsAndHashCode(includes = ['bucket', 'key'])
final class S3ImageLocation implements ImageLocation {
    @NotNull
    final String bucket

    final String prefix

    @NotNull
    final String subKey

    @PersistenceConstructor
    S3ImageLocation(String bucket, String prefix, String subKey) {
        this.bucket = bucket
        this.prefix = prefix
        this.subKey = subKey
    }

    S3ImageLocation(String bucket, String subKey) {
        this(bucket, null, subKey)
    }

    @JsonIgnore
    String getKey() {
        prefix ? "$prefix/$subKey" : subKey
    }

    @Override
    String toString() {
        "s3://$bucket/$key"
    }

    S3Location toBlitlineLocation() {
        new S3Location(bucket, key)
    }
}
{code}

Both of the generated methods appear to be including {{bucket}} twice instead of including {{bucket}} and {{key}}.

see :7 and :29
{code}
  public int hashCode();
    Code:
       0: invokestatic  #93                 // Method org/codehaus/groovy/util/HashCodeHelper.initHash:()I
       3: istore_1
       4: iload_1
       5: pop
       6: aload_0
       7: ldc           #94                 // String bucket
       9: invokestatic  #100                // Method org/codehaus/groovy/runtime/InvokerHelper.getProperty:(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
      12: aload_0
      13: invokestatic  #106                // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z
      16: ifne          23
      19: iconst_1
      20: goto          24
      23: iconst_0
      24: ifeq          42
      27: iload_1
      28: aload_0
      29: ldc           #94                 // String bucket
      31: invokestatic  #100                // Method org/codehaus/groovy/runtime/InvokerHelper.getProperty:(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;
      34: invokestatic  #110                // Method org/codehaus/groovy/util/HashCodeHelper.updateHash:(ILjava/lang/Object;)I
      37: istore_2
      38: iload_2
      39: istore_1
      40: iload_2
      41: pop
      42: iload_1
      43: ireturn
      44: ldc           #113                // int 0
      46: ireturn
{code}

see :152/:171 and :208/:219
{code}
  public boolean equals(java.lang.Object);
    Code:
       0: aload_1
       1: ifnonnull     8
       4: iconst_1
       5: goto          9
       8: iconst_0
       9: ifeq          19
      12: getstatic     #129                // Field java/lang/Boolean.FALSE:Ljava/lang/Boolean;
      15: invokestatic  #58                 // Method org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z
      18: ireturn
      19: aload_0
      20: aload_1
      21: invokestatic  #106                // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z
      24: ifeq          34
      27: getstatic     #132                // Field java/lang/Boolean.TRUE:Ljava/lang/Boolean;
      30: invokestatic  #58                 // Method org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z
      33: ireturn
      34: aload_1
      35: instanceof    #2                  // class com/artsquare/studio/img/s3/S3ImageLocation
      38: ifne          45
      41: iconst_1
      42: goto          46
      45: iconst_0
      46: ifeq          56
      49: getstatic     #129                // Field java/lang/Boolean.FALSE:Ljava/lang/Boolean;
      52: invokestatic  #58                 // Method org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z
      55: ireturn
      56: aload_1
      57: ldc           #2                  // class com/artsquare/studio/img/s3/S3ImageLocation
      59: invokestatic  #138                // Method org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType:(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
      62: checkcast     #2                  // class com/artsquare/studio/img/s3/S3ImageLocation
      65: astore_2
      66: aload_2
      67: pop
      68: aload_2
      69: aload_0
      70: invokevirtual #140                // Method canEqual:(Ljava/lang/Object;)Z
      73: ifne          80
      76: iconst_1
      77: goto          81
      80: iconst_0
      81: ifeq          91
      84: getstatic     #129                // Field java/lang/Boolean.FALSE:Ljava/lang/Boolean;
      87: invokestatic  #58                 // Method org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z
      90: ireturn
      91: aload_0
      92: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
      95: aload_2
      96: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
      99: invokestatic  #106                // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z
     102: ifne          109
     105: iconst_1
     106: goto          110
     109: iconst_0
     110: ifeq          274
     113: aload_0
     114: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
     117: aload_0
     118: invokestatic  #106                // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z
     121: ifeq          147
     124: aload_2
     125: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
     128: aload_2
     129: invokestatic  #106                // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z
     132: ifne          139
     135: iconst_1
     136: goto          140
     139: iconst_0
     140: ifeq          147
     143: iconst_1
     144: goto          148
     147: iconst_0
     148: ifne          189
     151: aload_0
     152: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
     155: aload_0
     156: invokestatic  #106                // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z
     159: ifne          166
     162: iconst_1
     163: goto          167
     166: iconst_0
     167: ifeq          185
     170: aload_2
     171: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
     174: aload_2
     175: invokestatic  #106                // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z
     178: ifeq          185
     181: iconst_1
     182: goto          186
     185: iconst_0
     186: ifeq          193
     189: iconst_1
     190: goto          194
     193: iconst_0
     194: ifeq          207
     197: getstatic     #129                // Field java/lang/Boolean.FALSE:Ljava/lang/Boolean;
     200: invokestatic  #58                 // Method org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z
     203: ireturn
     204: goto          274
     207: aload_0
     208: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
     211: aload_0
     212: invokestatic  #106                // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z
     215: ifeq          233
     218: aload_2
     219: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
     222: aload_2
     223: invokestatic  #106                // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z
     226: ifeq          233
     229: iconst_1
     230: goto          234
     233: iconst_0
     234: ifne          241
     237: iconst_1
     238: goto          242
     241: iconst_0
     242: ifeq          274
     245: aload_0
     246: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
     249: aload_2
     250: invokevirtual #143                // Method getBucket:()Ljava/lang/String;
     253: invokestatic  #146                // Method org/codehaus/groovy/runtime/ScriptBytecodeAdapter.compareEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     256: ifne          263
     259: iconst_1
     260: goto          264
     263: iconst_0
     264: ifeq          274
     267: getstatic     #129                // Field java/lang/Boolean.FALSE:Ljava/lang/Boolean;
     270: invokestatic  #58                 // Method org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z
     273: ireturn
     274: getstatic     #132                // Field java/lang/Boolean.TRUE:Ljava/lang/Boolean;
     277: invokestatic  #58                 // Method org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z
     280: ireturn
     281: ldc           #113                // int 0
     283: invokestatic  #122                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     286: invokestatic  #58                 // Method org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z
     289: ireturn
{code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)