2

In commons-collections 3.2.1 the following one-liner worked nicely to retrieve the myProperty values of the objects inside myCollection:

Collection<MyType> myTypes = (Collection<MyType>) CollectionUtils.collect(myCollection, new BeanToPropertyValueTransformer("myProperty"))

Only drawback is that generics are not supported, so type casting needs to be done.

What would be a solution that works in commons-collection4, taking advantage of generics?

unziberla
  • 545
  • 4
  • 22
Markus Pscheidt
  • 6,853
  • 5
  • 55
  • 76

2 Answers2

1

Apparently they removed BeanToPropertyValueTransformer from the release of apache-commons-collection4.

I managed to achieve the same behavior by defininig a custom Transformer. The introduction of generics eliminates the necessity of casting the output collection:

Collection<MyInputType> myCollection = ...
Collection<MyType> myTypes = CollectionUtils.collect(myCollection, new Transformer<MyInputType, MyType>() {
    @Override
    public MyType transform(MyInputType input) {
        return input.getMyProperty();
    }
}

You could also write your own Transformer that uses reflection

class ReflectionTransformer<O>
        implements
        Transformer<Object, O> {

    private String  reflectionString;

    public ReflectionTransformer(String reflectionString) {
        this.reflectionString = reflectionString;
    }

    @SuppressWarnings("unchecked")
    @Override
    public O transform(
            Object input) {
        try {
            return (O) BeanUtils.getProperty(input, reflectionString);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}

and use it same as you used to do with BeanToPropertyValueTransformer

Collection<MyType> myTypes = CollectionUtils.collect(myCollection, new ReflectionTransformer<MyType>("myProperty"));
unziberla
  • 545
  • 4
  • 22
0

Try using the below class (using commons-collection4) instead -

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.InvocationTargetException;

public class BeanToPropertyValueTransformer implements Transformer {

    private final Log log = LogFactory.getLog(this.getClass());

    private String propertyName;
    private boolean ignoreNull;
    
    public BeanToPropertyValueTransformer(final String propertyName) {
        this(propertyName, false);
    }

    public BeanToPropertyValueTransformer(final String propertyName, final boolean ignoreNull) {
        super();

        if ((propertyName != null) && (propertyName.length() > 0)) {
            this.propertyName = propertyName;
            this.ignoreNull = ignoreNull;
        } else {
            throw new IllegalArgumentException(
                "propertyName cannot be null or empty");
        }
    }
    
    public Object transform(final Object object) {

        Object propertyValue = null;

        try {
            propertyValue = PropertyUtils.getProperty(object, propertyName);
        } catch (final IllegalArgumentException e) {
            final String errorMsg = "Problem during transformation. Null value encountered in property path...";

            if (ignoreNull) {
                log.warn("WARNING: " + errorMsg + e);
            } else {
                final IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
                if (!BeanUtils.initCause(iae, e)) {
                    log.error(errorMsg, e);
                }
                throw iae;
            }
        } catch (final IllegalAccessException e) {
            final String errorMsg = "Unable to access the property provided.";
            final IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
            if (!BeanUtils.initCause(iae, e)) {
                log.error(errorMsg, e);
            }
            throw iae;
        } catch (final InvocationTargetException e) {
            final String errorMsg = "Exception occurred in property's getter";
            final IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
            if (!BeanUtils.initCause(iae, e)) {
                log.error(errorMsg, e);
            }
            throw iae;
        } catch (final NoSuchMethodException e) {
            final String errorMsg = "No property found for name [" +
                propertyName + "]";
            final IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
            if (!BeanUtils.initCause(iae, e)) {
                log.error(errorMsg, e);
            }
            throw iae;
        }

        return propertyValue;
    }

    public String getPropertyName() {
        return propertyName;
    }

    public boolean isIgnoreNull() {
        return ignoreNull;
    }
}