A boolean property should be able to have two getters: isX() and getX() #906

Closed
admxiii opened this Issue Feb 1, 2017 · 3 comments

Comments

Projects
None yet
2 participants
@admxiii

admxiii commented Feb 1, 2017

Groovy object properties follow the javabean spec for boolean, which allows for both a get* and an is* method to appear on the same object. Mybatis complains this doesn't follow the javabean spec which isn't entirely true. I know you can use Boolean to get around the get/is issue or define your own getter which stops groovy from building the pair, but the strange part is that this field is not even used by mybatis, its just a helper boolean internal to the object, but mybatis still validates the entire object whether the field is used or not in a resultmap.

could this rule be relaxed to allow the official javabean spec to not throw an error?

from oracle:

8.3.2 Boolean properties
In addition, for boolean properties, we allow a getter method to match the pattern:
public boolean is();
This “is” method may be provided instead of a “get” method,
or it may be provided in addition to a “get” method.
In either case, if the “is” method is present for a boolean property then we will
use the “is” method to read the property value.

heres the code in question that throws the error on a valid javabean.

private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
    for (String propName : conflictingGetters.keySet()) {
      List<Method> getters = conflictingGetters.get(propName);
      Iterator<Method> iterator = getters.iterator();
      Method firstMethod = iterator.next();
      if (getters.size() == 1) {
        addGetMethod(propName, firstMethod);
      } else {
        Method getter = firstMethod;
        Class<?> getterType = firstMethod.getReturnType();
        while (iterator.hasNext()) {
          Method method = iterator.next();
          Class<?> methodType = method.getReturnType();
          if (methodType.equals(getterType)) {
            throw new ReflectionException("Illegal overloaded getter method with ambiguous type for property "
                + propName + " in class " + firstMethod.getDeclaringClass()
                + ".  This breaks the JavaBeans " + "specification and can cause unpredictable results.");
          } else if (methodType.isAssignableFrom(getterType)) {
            // OK getter type is descendant
          } else if (getterType.isAssignableFrom(methodType)) {
            getter = method;
            getterType = methodType;
          } else {
            throw new ReflectionException("Illegal overloaded getter method with ambiguous type for property "
                + propName + " in class " + firstMethod.getDeclaringClass()
                + ".  This breaks the JavaBeans " + "specification and can cause unpredictable results.");
          }
        }
        addGetMethod(propName, getter);
      }
    }
  }

@harawata harawata self-assigned this Feb 2, 2017

@harawata harawata added the bug label Feb 2, 2017

@harawata harawata added this to the 3.4.3 milestone Feb 2, 2017

@harawata harawata changed the title from Groovy POGO with boolean field to A boolean property should be able to have two getters: isX() and getX() Feb 2, 2017

@harawata harawata closed this in 27d37ce Feb 2, 2017

@harawata

This comment has been minimized.

Show comment
Hide comment
@harawata

harawata Feb 2, 2017

Member

Thank you for the report, @admxiii !

I have committed the fix.
Could you try the latest 3.4.3-SNAPSHOT with a Groovy class?

For future reference, here is the stack trace:

org.apache.ibatis.reflection.ReflectionException: Illegal overloaded getter method with ambiguous type for property boolProp in class class com.example.SomeBean.  This breaks the JavaBeans specification and can cause unpredictable results.
  at org.apache.ibatis.reflection.Reflector.resolveGetterConflicts(Reflector.java:130)
  at org.apache.ibatis.reflection.Reflector.addGetMethods(Reflector.java:113)
  at org.apache.ibatis.reflection.Reflector.<init>(Reflector.java:65)
  at org.apache.ibatis.reflection.DefaultReflectorFactory.findForClass(DefaultReflectorFactory.java:44)
  at org.apache.ibatis.reflection.ReflectorTest.shouldAllowTwoBooleanGetters(ReflectorTest.java:211)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:498)
  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
  at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
  at org.junit.rules.RunRules.evaluate(RunRules.java:20)
  at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
  at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
  at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
  at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
  at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
  at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Member

harawata commented Feb 2, 2017

Thank you for the report, @admxiii !

I have committed the fix.
Could you try the latest 3.4.3-SNAPSHOT with a Groovy class?

For future reference, here is the stack trace:

org.apache.ibatis.reflection.ReflectionException: Illegal overloaded getter method with ambiguous type for property boolProp in class class com.example.SomeBean.  This breaks the JavaBeans specification and can cause unpredictable results.
  at org.apache.ibatis.reflection.Reflector.resolveGetterConflicts(Reflector.java:130)
  at org.apache.ibatis.reflection.Reflector.addGetMethods(Reflector.java:113)
  at org.apache.ibatis.reflection.Reflector.<init>(Reflector.java:65)
  at org.apache.ibatis.reflection.DefaultReflectorFactory.findForClass(DefaultReflectorFactory.java:44)
  at org.apache.ibatis.reflection.ReflectorTest.shouldAllowTwoBooleanGetters(ReflectorTest.java:211)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:498)
  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
  at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
  at org.junit.rules.RunRules.evaluate(RunRules.java:20)
  at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
  at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
  at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
  at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
  at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
  at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
@admxiii

This comment has been minimized.

Show comment
Hide comment
@admxiii

admxiii Feb 2, 2017

I re-tested with the snapshot and it is working now. Thank you for the quick response! I am now able to remove a ton of useless is* methods on my groovy objects.

admxiii commented Feb 2, 2017

I re-tested with the snapshot and it is working now. Thank you for the quick response! I am now able to remove a ton of useless is* methods on my groovy objects.

@harawata

This comment has been minimized.

Show comment
Hide comment
@harawata

harawata Feb 2, 2017

Member

Thanks for the quick check! Glad to hear it's working =)

Member

harawata commented Feb 2, 2017

Thanks for the quick check! Glad to hear it's working =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment