package com.hubspot.jinjava.el.ext; import java.util.Set; import javax.el.BeanELResolver; import javax.el.ELContext; import javax.el.MethodNotFoundException; import com.google.common.base.CaseFormat; import com.google.common.collect.ImmutableSet; /** * {@link BeanELResolver} supporting snake case property names. */ public class JinjavaBeanELResolver extends BeanELResolver { private static final Set<String> RESTRICTED_PROPERTIES = ImmutableSet.<String> builder() .add("class") .build(); private static final Set<String> RESTRICTED_METHODS = ImmutableSet.<String> builder() .add("clone") .add("hashCode") .add("notify") .add("notifyAll") .add("wait") .build(); /** * Creates a new read/write {@link JinjavaBeanELResolver}. */ public JinjavaBeanELResolver() {} /** * Creates a new {@link JinjavaBeanELResolver} whose read-only status is determined by the given parameter. */ public JinjavaBeanELResolver(boolean readOnly) { super(readOnly); } @Override public Class<?> getType(ELContext context, Object base, Object property) { return super.getType(context, base, validatePropertyName(property)); } @Override public Object getValue(ELContext context, Object base, Object property) { return super.getValue(context, base, validatePropertyName(property)); } @Override public boolean isReadOnly(ELContext context, Object base, Object property) { return super.isReadOnly(context, base, validatePropertyName(property)); } @Override public void setValue(ELContext context, Object base, Object property, Object value) { super.setValue(context, base, validatePropertyName(property), value); } @Override public Object invoke(ELContext context, Object base, Object method, Class<?>[] paramTypes, Object[] params) { if (method == null || RESTRICTED_METHODS.contains(method.toString())) { throw new MethodNotFoundException("Cannot find method '" + method + "' in " + base.getClass()); } return super.invoke(context, base, method, paramTypes, params); } private String validatePropertyName(Object property) { String propertyName = transformPropertyName(property); if (RESTRICTED_PROPERTIES.contains(propertyName)) { return null; } return propertyName; } /** * Transform snake case to property name. */ private String transformPropertyName(Object property) { if (property == null) { return null; } String propertyStr = property.toString(); if (propertyStr.indexOf('_') == -1) { return propertyStr; } return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, propertyStr); } }