17

I'm using BeanUtils to manipulate Java objects created via JAXB, and I've run into an interesting issue. Sometimes, JAXB will create a Java object like this:

public class Bean {
    protected Boolean happy;

    public Boolean isHappy() {
        return happy;
    }

    public void setHappy(Boolean happy) {
        this.happy = happy;
    }
}

The following code works just fine:

Bean bean = new Bean();
BeanUtils.setProperty(bean, "happy", true);

However, attempting to get the happy property like so:

Bean bean = new Bean();
BeanUtils.getProperty(bean, "happy");

Results in this exception:

Exception in thread "main" java.lang.NoSuchMethodException: Property 'happy' has no getter method in class 'class Bean'

Changing everything to a primitive boolean allows both the set and get call to work. I don't have this option, however, since these are generated classes. I assume this happens because the Java Bean libraries only consider an is<name> method to represent a property if the return type is a primitive boolean, and not the wrapper type Boolean. Does anyone have a suggestion as to how to access properties like these through BeanUtils? Is there some kind of workaround I can use?

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 5
    Where does the `BeanUtils` class come from? I checked with `org.apache.commons.beanutils.BeanUtils` (1.8.3) and it works fine. Please note that typically `is` prefix is used for `boolean`, while for `Boolean`: `get`. – Tomasz Nurkiewicz Mar 10 '11 at 22:40
  • I'm using the same BeanUtils. You were able to do a `getProperty()` with an `is` method that returns the `Boolean` wrapper class? – Charles Hellstrom Mar 11 '11 at 13:57
  • 2
    Your assumption about is is correct. isXXX only applys to type boolean return type. For Boolean return type, getXXX is the correct method name. – DwB Mar 11 '11 at 14:20
  • 1
    you're right, `getProperty()` does not work with `Boolean is`. In fact, IntelliJ generates getters with `get` for `Boolean` and `is` for `boolean` - I guess Eclipse does the same. – Tomasz Nurkiewicz Mar 11 '11 at 16:46

3 Answers3

10

Finally I've found legal confirmation:

8.3.2 Boolean properties

In addition, for boolean properties, we allow a getter method to match the pattern:

public boolean is<PropertyName>();

From JavaBeans specification. Are you sure you haven't came across JAXB-131 bug?

Community
  • 1
  • 1
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 2
    Yep, looks like I was running into that bug. I upgraded my JAXB version to 2.1.13 and added the "-enableIntrospection" flag. That changed all the `Boolean` wrapper `is` methods to `get`s. Thanks! – Charles Hellstrom Mar 15 '11 at 15:07
8

Workaround to handle Boolean isFooBar() case with BeanUtils

  1. Create new BeanIntrospector

private static class BooleanIntrospector implements BeanIntrospector{
    @Override
    public void introspect(IntrospectionContext icontext) throws IntrospectionException {
        for (Method m : icontext.getTargetClass().getMethods()) {
            if (m.getName().startsWith("is") && Boolean.class.equals(m.getReturnType())) {
                String propertyName = getPropertyName(m);
                PropertyDescriptor pd = icontext.getPropertyDescriptor(propertyName);

                if (pd == null)
                    icontext.addPropertyDescriptor(new PropertyDescriptor(propertyName, m, getWriteMethod(icontext.getTargetClass(), propertyName)));
                else if (pd.getReadMethod() == null)
                    pd.setReadMethod(m);

            }
        }
    }

    private String getPropertyName(Method m){
        return WordUtils.uncapitalize(m.getName().substring(2, m.getName().length()));
    }

    private Method getWriteMethod(Class<?> clazz, String propertyName){
        try {
            return clazz.getMethod("get" + WordUtils.capitalize(propertyName));
        } catch (NoSuchMethodException e) {
            return null;
        }
    }
}

  1. Register BooleanIntrospector:

    BeanUtilsBean.getInstance().getPropertyUtils().addBeanIntrospector(new BooleanIntrospector());

user3570881
  • 81
  • 1
  • 1
  • Good stuff! I think there are 2 changes needed though: in getWriteMethod, it should be "set" - and also, I was getting MethodNotFoundExceptions until I changed to the overloaded method that receives a parameter type: `return clazz.getMethod("set" + WordUtils.capitalize(propertyName), Boolean.class);` – Jmoney38 May 02 '19 at 21:25
0

you can just create second getter with SET - sufix as workaround :)

Irakli
  • 973
  • 3
  • 19
  • 45