Monday, April 20, 2015

Abstract method in Enums

Did you know that you can do that?


  private static enum DynamicProperty {

        cacheManagerName {
            @Override
            void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {
                config.cacheManagerName = (String) evt.getNewValue();
            }
        },
        defaultCacheConfiguration {
            @Override
            void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {
                LOG.debug("Default Cache Configuration has changed, previously created caches remain untouched");
            }
        };

        abstract void applyChange(PropertyChangeEvent evt, RuntimeCfg config);
}

I think it's nice because it allows you to customize Enum's behavior or perform other actions on use. 

Piece of code taken from EhCache Configuration (line 118 and further).

Thursday, April 16, 2015

EhCache config with BeanUtils

BeanUtils allows you to set Bean properties.
If you have configuration stored in a Map it's tempting to use BeanUtils to automagically setup EhCache configuration.
Sadly this class has mixed types in setters and getter and thus BeanUtils that use Introspector behind won't get getter and setter pairs properly. It will get only getters and thus inform you that these properties are read only: "Skipping read-only property".

My fast solution is to use BeanUtils and have a fallback to Reflection.

public static void setProperty(Object obj, String propertyName, Object propertyValue, boolean silently) {
        try {
            PropertyDescriptor desc = PropertyUtils.getPropertyDescriptor(obj, propertyName);
            Method writeMethod = desc.getWriteMethod(); 
                 
            if (writeMethod == null) {
                writeMethod = getAlternativeWriteMethod(obj, propertyName, propertyValue.getClass());
            }
            
            if (writeMethod == null) {
                if (silently) {
                    return;
                }
                throw new IllegalArgumentException("Can't find writerMethod for " + propertyName);
            }

            if (LOG.isTraceEnabled()) {
                LOG.trace(String.format("Setting %s property of %s", propertyName, obj.getClass().getSimpleName()));
            }
            
            writeMethod.invoke(obj, propertyValue);
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            throw new IllegalArgumentException("Error when setting object property.", e);
        }
    }

    private static Method getAlternativeWriteMethod(Object obj, String propertyName, Class paramClass) throws NoSuchMethodException {
        String setterMethod = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        Method m; 
        if ((m = getMethod(obj, paramClass, setterMethod)) != null) {
            return m;
        }
        Class altClass = paramClass.isPrimitive() ? ClassUtils.primitiveToWrapper(paramClass) : ClassUtils.wrapperToPrimitive(paramClass);
        if ((m = getMethod(obj, altClass, setterMethod)) != null) {
            return m;
        }
        
        return null;
    }

    private static Method getMethod(Object obj, Class paramClass, String setterMethod) {

        try {
            return obj.getClass().getMethod(setterMethod, paramClass);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }




I will think about PR to Configuration class but it's complicated as EhCache 2.x is not present on GitHub.