mebigfatguy / fb-contrib

a FindBugs/SpotBugs plugin for doing static code analysis for java code bases
http://fb-contrib.sf.net
GNU Lesser General Public License v2.1
153 stars 45 forks source link

False positive on URV_CHANGE_RETURN_TYPE with constrained code #368

Open ThrawnCA opened 5 years ago

ThrawnCA commented 5 years ago

URV_CHANGE_RETURN_TYPE sometimes doesn't take account of all the constraints that may exist on code. For example, when creating a custom Hibernate UserType, we have code like the following:

@Override
public <X> X unwrap(Money value, Class<X> type, WrapperOptions options) {
    if (value == null) {
        return null;
    }
    if (BigInteger.class.isAssignableFrom(type)) {
        return (X) value.getAmountInCents();
    }
    if (Long.class.isAssignableFrom(type)) {
        return (X) Long.valueOf(value.getAmountInCents().longValue());
    }

    throw unknownUnwrap(type);
}

The detector notes that all the possible return types are Numbers and flags it. However, the superclass method signature obligates us to return type X, which theoretically doesn't have to be a Number when the method is called.

mebigfatguy commented 5 years ago

can you add this class, and the super classes descriptor to this?

ThrawnCA commented 5 years ago

The superclass is from a third party (Hibernate), but I can provide javap output for ours:

Classfile /osidt/common/target/classes/au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.class
  Last modified 16/08/2019; size 3687 bytes
  MD5 checksum 82d479344260a00d53a8b7129d5df83a
  Compiled from "MoneyUserType.java"
public class au.gov.qld.ssq.common.repository.MoneyUserType$MoneyTypeDescriptor extends org.hibernate.type.descriptor.java.AbstractTypeDescriptor<au.gov.qld.ssq.common.money.Money>
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
    #1 = Class              #69           // au/gov/qld/ssq/common/money/Money
    #2 = Methodref          #27.#70       // org/hibernate/type/descriptor/java/AbstractTypeDescriptor."<init>":(Ljava/lang/Class;)V
    #3 = Methodref          #71.#72       // java/util/Optional.ofNullable:(Ljava/lang/Object;)Ljava/util/Optional;
    #4 = Fieldref           #1.#73        // au/gov/qld/ssq/common/money/Money.ZERO:Lau/gov/qld/ssq/common/money/Money;
    #5 = Methodref          #71.#74       // java/util/Optional.orElse:(Ljava/lang/Object;)Ljava/lang/Object;
    #6 = Methodref          #1.#75        // au/gov/qld/ssq/common/money/Money.getAmountInCents:()Ljava/math/BigInteger;
    #7 = Methodref          #8.#76        // java/math/BigInteger.toString:()Ljava/lang/String;
    #8 = Class              #77           // java/math/BigInteger
    #9 = Methodref          #8.#78        // java/math/BigInteger."<init>":(Ljava/lang/String;)V
   #10 = Methodref          #1.#79        // au/gov/qld/ssq/common/money/Money.inCents:(Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
   #11 = Methodref          #80.#81       // java/lang/Class.isAssignableFrom:(Ljava/lang/Class;)Z
   #12 = Class              #82           // java/lang/Long
   #13 = Methodref          #8.#83        // java/math/BigInteger.longValue:()J
   #14 = Methodref          #12.#84       // java/lang/Long.valueOf:(J)Ljava/lang/Long;
   #15 = Methodref          #26.#85       // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.unknownUnwrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
   #16 = Methodref          #80.#86       // java/lang/Class.isInstance:(Ljava/lang/Object;)Z
   #17 = Class              #87           // java/lang/Number
   #18 = Methodref          #17.#83       // java/lang/Number.longValue:()J
   #19 = Methodref          #1.#88        // au/gov/qld/ssq/common/money/Money.inCents:(J)Lau/gov/qld/ssq/common/money/Money;
   #20 = Methodref          #89.#90       // java/lang/Object.getClass:()Ljava/lang/Class;
   #21 = Methodref          #26.#91       // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.unknownWrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
   #22 = Methodref          #26.#92       // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.wrap:(Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
   #23 = Methodref          #26.#93       // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.unwrap:(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
   #24 = Methodref          #26.#94       // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.fromString:(Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
   #25 = Methodref          #26.#95       // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor.toString:(Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
   #26 = Class              #97           // au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor
   #27 = Class              #98           // org/hibernate/type/descriptor/java/AbstractTypeDescriptor
   #28 = Utf8               <init>
   #29 = Utf8               ()V
   #30 = Utf8               Code
   #31 = Utf8               LineNumberTable
   #32 = Utf8               LocalVariableTable
   #33 = Utf8               this
   #34 = Utf8               MoneyTypeDescriptor
   #35 = Utf8               InnerClasses
   #36 = Utf8               Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
   #37 = Utf8               toString
   #38 = Utf8               (Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
   #39 = Utf8               value
   #40 = Utf8               Lau/gov/qld/ssq/common/money/Money;
   #41 = Utf8               MethodParameters
   #42 = Utf8               fromString
   #43 = Utf8               (Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
   #44 = Utf8               string
   #45 = Utf8               Ljava/lang/String;
   #46 = Utf8               unwrap
   #47 = Utf8               (Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
   #48 = Utf8               type
   #49 = Utf8               Ljava/lang/Class;
   #50 = Utf8               options
   #51 = Utf8               Lorg/hibernate/type/descriptor/WrapperOptions;
   #52 = Utf8               LocalVariableTypeTable
   #53 = Utf8               Ljava/lang/Class<TX;>;
   #54 = Utf8               StackMapTable
   #55 = Utf8               Signature
   #56 = Utf8               <X:Ljava/lang/Object;>(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class<TX;>;Lorg/hibernate/type/descriptor/WrapperOptions;)TX;
   #57 = Utf8               wrap
   #58 = Utf8               (Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
   #59 = Utf8               Ljava/lang/Object;
   #60 = Utf8               TX;
   #61 = Utf8               <X:Ljava/lang/Object;>(TX;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
   #62 = Utf8               (Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
   #63 = Utf8               (Ljava/lang/Object;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
   #64 = Utf8               (Ljava/lang/String;)Ljava/lang/Object;
   #65 = Utf8               (Ljava/lang/Object;)Ljava/lang/String;
   #66 = Utf8               Lorg/hibernate/type/descriptor/java/AbstractTypeDescriptor<Lau/gov/qld/ssq/common/money/Money;>;
   #67 = Utf8               SourceFile
   #68 = Utf8               MoneyUserType.java
   #69 = Utf8               au/gov/qld/ssq/common/money/Money
   #70 = NameAndType        #28:#99       // "<init>":(Ljava/lang/Class;)V
   #71 = Class              #100          // java/util/Optional
   #72 = NameAndType        #101:#102     // ofNullable:(Ljava/lang/Object;)Ljava/util/Optional;
   #73 = NameAndType        #103:#40      // ZERO:Lau/gov/qld/ssq/common/money/Money;
   #74 = NameAndType        #104:#105     // orElse:(Ljava/lang/Object;)Ljava/lang/Object;
   #75 = NameAndType        #106:#107     // getAmountInCents:()Ljava/math/BigInteger;
   #76 = NameAndType        #37:#108      // toString:()Ljava/lang/String;
   #77 = Utf8               java/math/BigInteger
   #78 = NameAndType        #28:#109      // "<init>":(Ljava/lang/String;)V
   #79 = NameAndType        #110:#111     // inCents:(Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
   #80 = Class              #112          // java/lang/Class
   #81 = NameAndType        #113:#114     // isAssignableFrom:(Ljava/lang/Class;)Z
   #82 = Utf8               java/lang/Long
   #83 = NameAndType        #115:#116     // longValue:()J
   #84 = NameAndType        #117:#118     // valueOf:(J)Ljava/lang/Long;
   #85 = NameAndType        #119:#120     // unknownUnwrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
   #86 = NameAndType        #121:#122     // isInstance:(Ljava/lang/Object;)Z
   #87 = Utf8               java/lang/Number
   #88 = NameAndType        #110:#123     // inCents:(J)Lau/gov/qld/ssq/common/money/Money;
   #89 = Class              #124          // java/lang/Object
   #90 = NameAndType        #125:#126     // getClass:()Ljava/lang/Class;
   #91 = NameAndType        #127:#120     // unknownWrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
   #92 = NameAndType        #57:#58       // wrap:(Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
   #93 = NameAndType        #46:#47       // unwrap:(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
   #94 = NameAndType        #42:#43       // fromString:(Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
   #95 = NameAndType        #37:#38       // toString:(Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
   #96 = Class              #128          // au/gov/qld/ssq/common/repository/MoneyUserType
   #97 = Utf8               au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor
   #98 = Utf8               org/hibernate/type/descriptor/java/AbstractTypeDescriptor
   #99 = Utf8               (Ljava/lang/Class;)V
  #100 = Utf8               java/util/Optional
  #101 = Utf8               ofNullable
  #102 = Utf8               (Ljava/lang/Object;)Ljava/util/Optional;
  #103 = Utf8               ZERO
  #104 = Utf8               orElse
  #105 = Utf8               (Ljava/lang/Object;)Ljava/lang/Object;
  #106 = Utf8               getAmountInCents
  #107 = Utf8               ()Ljava/math/BigInteger;
  #108 = Utf8               ()Ljava/lang/String;
  #109 = Utf8               (Ljava/lang/String;)V
  #110 = Utf8               inCents
  #111 = Utf8               (Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
  #112 = Utf8               java/lang/Class
  #113 = Utf8               isAssignableFrom
  #114 = Utf8               (Ljava/lang/Class;)Z
  #115 = Utf8               longValue
  #116 = Utf8               ()J
  #117 = Utf8               valueOf
  #118 = Utf8               (J)Ljava/lang/Long;
  #119 = Utf8               unknownUnwrap
  #120 = Utf8               (Ljava/lang/Class;)Lorg/hibernate/HibernateException;
  #121 = Utf8               isInstance
  #122 = Utf8               (Ljava/lang/Object;)Z
  #123 = Utf8               (J)Lau/gov/qld/ssq/common/money/Money;
  #124 = Utf8               java/lang/Object
  #125 = Utf8               getClass
  #126 = Utf8               ()Ljava/lang/Class;
  #127 = Utf8               unknownWrap
  #128 = Utf8               au/gov/qld/ssq/common/repository/MoneyUserType
{
  public au.gov.qld.ssq.common.repository.MoneyUserType$MoneyTypeDescriptor();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: ldc           #1                  // class au/gov/qld/ssq/common/money/Money
         3: invokespecial #2                  // Method org/hibernate/type/descriptor/java/AbstractTypeDescriptor."<init>":(Ljava/lang/Class;)V
         6: return
      LineNumberTable:
        line 46: 0
        line 47: 6
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       7     0  this   Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;

  public java.lang.String toString(au.gov.qld.ssq.common.money.Money);
    descriptor: (Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_1
         1: invokestatic  #3                  // Method java/util/Optional.ofNullable:(Ljava/lang/Object;)Ljava/util/Optional;
         4: getstatic     #4                  // Field au/gov/qld/ssq/common/money/Money.ZERO:Lau/gov/qld/ssq/common/money/Money;
         7: invokevirtual #5                  // Method java/util/Optional.orElse:(Ljava/lang/Object;)Ljava/lang/Object;
        10: checkcast     #1                  // class au/gov/qld/ssq/common/money/Money
        13: invokevirtual #6                  // Method au/gov/qld/ssq/common/money/Money.getAmountInCents:()Ljava/math/BigInteger;
        16: invokevirtual #7                  // Method java/math/BigInteger.toString:()Ljava/lang/String;
        19: areturn
      LineNumberTable:
        line 51: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      20     0  this   Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
            0      20     1 value   Lau/gov/qld/ssq/common/money/Money;
    MethodParameters:
      Name                           Flags
      value

  public au.gov.qld.ssq.common.money.Money fromString(java.lang.String);
    descriptor: (Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=2
         0: new           #8                  // class java/math/BigInteger
         3: dup
         4: aload_1
         5: invokespecial #9                  // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
         8: invokestatic  #10                 // Method au/gov/qld/ssq/common/money/Money.inCents:(Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
        11: areturn
      LineNumberTable:
        line 56: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      12     0  this   Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
            0      12     1 string   Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      string

  public <X extends java.lang.Object> X unwrap(au.gov.qld.ssq.common.money.Money, java.lang.Class<X>, org.hibernate.type.descriptor.WrapperOptions);
    descriptor: (Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=4
         0: aload_1
         1: ifnonnull     6
         4: aconst_null
         5: areturn
         6: ldc           #8                  // class java/math/BigInteger
         8: aload_2
         9: invokevirtual #11                 // Method java/lang/Class.isAssignableFrom:(Ljava/lang/Class;)Z
        12: ifeq          20
        15: aload_1
        16: invokevirtual #6                  // Method au/gov/qld/ssq/common/money/Money.getAmountInCents:()Ljava/math/BigInteger;
        19: areturn
        20: ldc           #12                 // class java/lang/Long
        22: aload_2
        23: invokevirtual #11                 // Method java/lang/Class.isAssignableFrom:(Ljava/lang/Class;)Z
        26: ifeq          40
        29: aload_1
        30: invokevirtual #6                  // Method au/gov/qld/ssq/common/money/Money.getAmountInCents:()Ljava/math/BigInteger;
        33: invokevirtual #13                 // Method java/math/BigInteger.longValue:()J
        36: invokestatic  #14                 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
        39: areturn
        40: aload_0
        41: aload_2
        42: invokevirtual #15                 // Method unknownUnwrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
        45: athrow
      LineNumberTable:
        line 61: 0
        line 62: 4
        line 64: 6
        line 65: 15
        line 67: 20
        line 68: 29
        line 71: 40
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      46     0  this   Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
            0      46     1 value   Lau/gov/qld/ssq/common/money/Money;
            0      46     2  type   Ljava/lang/Class;
            0      46     3 options   Lorg/hibernate/type/descriptor/WrapperOptions;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0      46     2  type   Ljava/lang/Class<TX;>;
      StackMapTable: number_of_entries = 3
        frame_type = 6 /* same */
        frame_type = 13 /* same */
        frame_type = 19 /* same */
    MethodParameters:
      Name                           Flags
      value
      type
      options
    Signature: #56                          // <X:Ljava/lang/Object;>(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class<TX;>;Lorg/hibernate/type/descriptor/WrapperOptions;)TX;

  public <X extends java.lang.Object> au.gov.qld.ssq.common.money.Money wrap(X, org.hibernate.type.descriptor.WrapperOptions);
    descriptor: (Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: aload_1
         1: ifnonnull     6
         4: aconst_null
         5: areturn
         6: ldc           #8                  // class java/math/BigInteger
         8: aload_1
         9: invokevirtual #16                 // Method java/lang/Class.isInstance:(Ljava/lang/Object;)Z
        12: ifeq          23
        15: aload_1
        16: checkcast     #8                  // class java/math/BigInteger
        19: invokestatic  #10                 // Method au/gov/qld/ssq/common/money/Money.inCents:(Ljava/math/BigInteger;)Lau/gov/qld/ssq/common/money/Money;
        22: areturn
        23: ldc           #17                 // class java/lang/Number
        25: aload_1
        26: invokevirtual #16                 // Method java/lang/Class.isInstance:(Ljava/lang/Object;)Z
        29: ifeq          43
        32: aload_1
        33: checkcast     #17                 // class java/lang/Number
        36: invokevirtual #18                 // Method java/lang/Number.longValue:()J
        39: invokestatic  #19                 // Method au/gov/qld/ssq/common/money/Money.inCents:(J)Lau/gov/qld/ssq/common/money/Money;
        42: areturn
        43: aload_0
        44: aload_1
        45: invokevirtual #20                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
        48: invokevirtual #21                 // Method unknownWrap:(Ljava/lang/Class;)Lorg/hibernate/HibernateException;
        51: athrow
      LineNumberTable:
        line 76: 0
        line 77: 4
        line 80: 6
        line 81: 15
        line 83: 23
        line 84: 32
        line 87: 43
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      52     0  this   Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
            0      52     1 value   Ljava/lang/Object;
            0      52     2 options   Lorg/hibernate/type/descriptor/WrapperOptions;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0      52     1 value   TX;
      StackMapTable: number_of_entries = 3
        frame_type = 6 /* same */
        frame_type = 16 /* same */
        frame_type = 19 /* same */
    MethodParameters:
      Name                           Flags
      value
      options
    Signature: #61                          // <X:Ljava/lang/Object;>(TX;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;

  public java.lang.Object wrap(java.lang.Object, org.hibernate.type.descriptor.WrapperOptions);
    descriptor: (Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
    flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=3, locals=3, args_size=3
         0: aload_0
         1: aload_1
         2: aload_2
         3: invokevirtual #22                 // Method wrap:(Ljava/lang/Object;Lorg/hibernate/type/descriptor/WrapperOptions;)Lau/gov/qld/ssq/common/money/Money;
         6: areturn
      LineNumberTable:
        line 43: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       7     0  this   Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
    MethodParameters:
      Name                           Flags
      value                          synthetic
      options                        synthetic

  public java.lang.Object unwrap(java.lang.Object, java.lang.Class, org.hibernate.type.descriptor.WrapperOptions);
    descriptor: (Ljava/lang/Object;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
    flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=4, locals=4, args_size=4
         0: aload_0
         1: aload_1
         2: checkcast     #1                  // class au/gov/qld/ssq/common/money/Money
         5: aload_2
         6: aload_3
         7: invokevirtual #23                 // Method unwrap:(Lau/gov/qld/ssq/common/money/Money;Ljava/lang/Class;Lorg/hibernate/type/descriptor/WrapperOptions;)Ljava/lang/Object;
        10: areturn
      LineNumberTable:
        line 43: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0  this   Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
    MethodParameters:
      Name                           Flags
      value                          synthetic
      type                           synthetic
      options                        synthetic

  public java.lang.Object fromString(java.lang.String);
    descriptor: (Ljava/lang/String;)Ljava/lang/Object;
    flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: invokevirtual #24                 // Method fromString:(Ljava/lang/String;)Lau/gov/qld/ssq/common/money/Money;
         5: areturn
      LineNumberTable:
        line 43: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
    MethodParameters:
      Name                           Flags
      string                         synthetic

  public java.lang.String toString(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: checkcast     #1                  // class au/gov/qld/ssq/common/money/Money
         5: invokevirtual #25                 // Method toString:(Lau/gov/qld/ssq/common/money/Money;)Ljava/lang/String;
         8: areturn
      LineNumberTable:
        line 43: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Lau/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor;
    MethodParameters:
      Name                           Flags
      value                          synthetic
}
Signature: #66                          // Lorg/hibernate/type/descriptor/java/AbstractTypeDescriptor<Lau/gov/qld/ssq/common/money/Money;>;
SourceFile: "MoneyUserType.java"
InnerClasses:
     public static #34= #26 of #96; //MoneyTypeDescriptor=class au/gov/qld/ssq/common/repository/MoneyUserType$MoneyTypeDescriptor of class au/gov/qld/ssq/common/repository/MoneyUserType