Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
admxiii opened this issue Feb 1, 2017 · 3 comments
Closed
Assignees
Labels
Milestone

Comments

@admxiii
Copy link

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 Groovy POGO with boolean field A boolean property should be able to have two getters: isX() and getX() Feb 2, 2017
@harawata
Copy link
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
Copy link
Author

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
Copy link
Member

harawata commented Feb 2, 2017

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

pulllock pushed a commit to pulllock/mybatis-3 that referenced this issue Oct 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants