Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.datatorrent.lib.util; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.codehaus.commons.compiler.CompileException; import org.codehaus.commons.compiler.CompilerFactoryFactory; import org.codehaus.commons.compiler.IScriptEvaluator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.StringUtils; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import com.datatorrent.lib.expression.Expression; import com.datatorrent.lib.expression.JavaExpressionParser; /** * @since 2.1.0 */ public class PojoUtils { private static final Logger logger = LoggerFactory.getLogger(PojoUtils.class); public static final String DEFAULT_EXP_OBJECT_PLACEHOLDER = "{$}"; public static final String DEFAULT_EXP_VAL_PLACEHOLDER = "{#}"; public static final String DEFAULT_EXPRESSION_OBJ_PLACEHOLDER = "$"; private static final String OBJECT = "object"; private static final String VAL = "val"; private static final String GET = "get"; private static final String IS = "is"; private static final String SET = "set"; private static final Map<Class<?>, Class<?>> primitiveClassToGetterInterface = Maps.newHashMap(); private static final Map<Class<?>, Class<?>> primitiveClassToSetterInterface = Maps.newHashMap(); static { primitiveClassToGetterInterface.put(boolean.class, GetterBoolean.class); primitiveClassToGetterInterface.put(byte.class, GetterByte.class); primitiveClassToGetterInterface.put(char.class, GetterChar.class); primitiveClassToGetterInterface.put(short.class, GetterShort.class); primitiveClassToGetterInterface.put(int.class, GetterInt.class); primitiveClassToGetterInterface.put(long.class, GetterLong.class); primitiveClassToGetterInterface.put(float.class, GetterFloat.class); primitiveClassToGetterInterface.put(double.class, GetterDouble.class); primitiveClassToSetterInterface.put(boolean.class, SetterBoolean.class); primitiveClassToSetterInterface.put(byte.class, SetterByte.class); primitiveClassToSetterInterface.put(char.class, SetterChar.class); primitiveClassToSetterInterface.put(short.class, SetterShort.class); primitiveClassToSetterInterface.put(int.class, SetterInt.class); primitiveClassToSetterInterface.put(long.class, SetterLong.class); primitiveClassToSetterInterface.put(float.class, SetterFloat.class); primitiveClassToSetterInterface.put(double.class, SetterDouble.class); } private PojoUtils() { } public interface GetterBoolean<T> { boolean get(T obj); } public interface GetterByte<T> { byte get(T obj); } public interface GetterChar<T> { char get(T obj); } public interface GetterShort<T> { short get(T obj); } public interface GetterInt<T> { int get(T obj); } public interface GetterLong<T> { long get(T obj); } public interface GetterFloat<T> { float get(T obj); } public interface GetterDouble<T> { double get(T obj); } public interface Getter<T, V> { V get(T obj); } public static <T> GetterBoolean<T> createGetterBoolean(Class<? extends T> pojoClass, String getterExpr) { return createGetterBoolean(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> GetterBoolean<T> createGetterBoolean(Class<? extends T> pojoClass, String getterExpr, String exprObjectPlaceholder) { return (GetterBoolean<T>) createGetter(pojoClass, getterExpr, exprObjectPlaceholder, boolean.class, GetterBoolean.class); } public static <T> GetterByte<T> createGetterByte(Class<? extends T> pojoClass, String getterExpr) { return createGetterByte(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> GetterByte<T> createGetterByte(Class<? extends T> pojoClass, String getterExpr, String exprObjectPlaceholder) { return (GetterByte<T>) createGetter(pojoClass, getterExpr, exprObjectPlaceholder, byte.class, GetterByte.class); } public static <T> GetterChar<T> createGetterChar(Class<? extends T> pojoClass, String getterExpr) { return createGetterChar(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER); } @SuppressWarnings({ "unchecked" }) public static <T> GetterChar<T> createGetterChar(Class<? extends T> pojoClass, String getterExpr, String exprObjectPlaceholder) { return (GetterChar<T>) createGetter(pojoClass, getterExpr, exprObjectPlaceholder, char.class, GetterChar.class); } public static <T> GetterShort<T> createGetterShort(Class<? extends T> pojoClass, String getterExpr) { return createGetterShort(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> GetterShort<T> createGetterShort(Class<? extends T> pojoClass, String getterExpr, String exprObjectPlaceholder) { return (GetterShort<T>) createGetter(pojoClass, getterExpr, exprObjectPlaceholder, short.class, GetterShort.class); } public static <T> GetterInt<T> createGetterInt(Class<? extends T> pojoClass, String getterExpr) { return createGetterInt(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> GetterInt<T> createGetterInt(Class<? extends T> pojoClass, String getterExpr, String exprObjectPlaceholder) { return (GetterInt<T>) createGetter(pojoClass, getterExpr, exprObjectPlaceholder, int.class, GetterInt.class); } public static <T> GetterLong<T> createGetterLong(Class<? extends T> pojoClass, String getterExpr) { return createGetterLong(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> GetterLong<T> createGetterLong(Class<? extends T> pojoClass, String getterExpr, String exprObjectPlaceholder) { return (GetterLong<T>) createGetter(pojoClass, getterExpr, exprObjectPlaceholder, long.class, GetterLong.class); } public static <T> GetterFloat<T> createGetterFloat(Class<? extends T> pojoClass, String getterExpr) { return createGetterFloat(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> GetterFloat<T> createGetterFloat(Class<? extends T> pojoClass, String getterExpr, String exprObjectPlaceholder) { return (GetterFloat<T>) createGetter(pojoClass, getterExpr, exprObjectPlaceholder, float.class, GetterFloat.class); } public static <T> GetterDouble<T> createGetterDouble(Class<? extends T> pojoClass, String getterExpr) { return createGetterDouble(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> GetterDouble<T> createGetterDouble(Class<? extends T> pojoClass, String getterExpr, String exprObjectPlaceholder) { return (GetterDouble<T>) createGetter(pojoClass, getterExpr, exprObjectPlaceholder, double.class, GetterDouble.class); } public static <T, V> Getter<T, V> createGetter(Class<? extends T> pojoClass, String getterExpr, Class<? extends V> exprClass) { return createGetter(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, exprClass); } @SuppressWarnings("unchecked") public static <T, V> Getter<T, V> createGetter(Class<? extends T> pojoClass, String getterExpr, String exprObjectPlaceholder, Class<? extends V> exprClass) { if (primitiveClassToGetterInterface.get(exprClass) != null) { throw new IllegalArgumentException("createGetter does not allow primitive class \"" + exprClass.getName() + "\" for exprClass argument. Use createGetter" + upperCaseWord(exprClass.getName()) + " or constructGetter()."); } return (Getter<T, V>) createGetter(pojoClass, getterExpr, exprObjectPlaceholder, exprClass, Getter.class); } public static Object constructGetter(Class<?> pojoClass, String getterExpr, Class<?> exprClass) { return constructGetter(pojoClass, getterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, exprClass); } public static Object constructGetter(Class<?> pojoClass, String getterExpr, String exprObjectPlaceholder, Class<?> exprClass) { Class<?> interfaceToImplement = primitiveClassToGetterInterface.get(exprClass); if (interfaceToImplement == null) { interfaceToImplement = Getter.class; } return createGetter(pojoClass, getterExpr, exprObjectPlaceholder, exprClass, interfaceToImplement); } /** * Setter interface for <tt>boolean</tt> primitives * @param <T> class of objects that the setter applies to */ public interface SetterBoolean<T> { void set(T obj, boolean booleanVal); } /** * Setter interface for <tt>byte</tt> primitives * @param <T> class of objects that the setter applies to */ public interface SetterByte<T> { void set(T obj, byte byteVal); } /** * Setter interface for <tt>char</tt> primitives * @param <T> class of objects that the setter applies to */ public interface SetterChar<T> { void set(T obj, char charVal); } /** * Setter interface for <tt>short</tt> primitives * @param <T> class of objects that the setter applies to */ public interface SetterShort<T> { void set(T obj, short shortVal); } /** * Setter interface for <tt>int</tt> primitives * @param <T> class of objects that the setter applies to */ public interface SetterInt<T> { void set(T obj, int intVal); } /** * Setter interface for <tt>long</tt> primitives * @param <T> class of objects that the setter applies to */ public interface SetterLong<T> { void set(T obj, long longVal); } /** * Setter interface for <tt>float</tt> primitives * @param <T> class of objects that the setter applies to */ public interface SetterFloat<T> { void set(T obj, float floatVal); } /** * Setter interface for <tt>double</tt> primitives * @param <T> class of objects that the setter applies to */ public interface SetterDouble<T> { void set(T obj, double doubleVal); } /** * Setter interface for arbitrary object * @param <T> class of objects that the setter applies to * @param <V> class of the rhs expression */ public interface Setter<T, V> { void set(T obj, V value); } public static <T> SetterBoolean<T> createSetterBoolean(Class<? extends T> pojoClass, String setterExpr) { return createSetterBoolean(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> SetterBoolean<T> createSetterBoolean(Class<? extends T> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValuePlaceholder) { return (SetterBoolean<T>) createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValuePlaceholder, boolean.class, SetterBoolean.class); } public static <T> SetterByte<T> createSetterByte(Class<? extends T> pojoClass, String setterExpr) { return createSetterByte(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> SetterByte<T> createSetterByte(Class<? extends T> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValuePlaceholder) { return (SetterByte<T>) createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValuePlaceholder, byte.class, SetterByte.class); } public static <T> SetterChar<T> createSetterChar(Class<? extends T> pojoClass, String setterExpr) { return createSetterChar(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> SetterChar<T> createSetterChar(Class<? extends T> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValuePlaceholder) { return (SetterChar<T>) createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValuePlaceholder, char.class, SetterChar.class); } public static <T> SetterShort<T> createSetterShort(Class<? extends T> pojoClass, String setterExpr) { return createSetterShort(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> SetterShort<T> createSetterShort(Class<? extends T> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValuePlaceholder) { return (SetterShort<T>) createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValuePlaceholder, short.class, SetterShort.class); } public static <T> SetterInt<T> createSetterInt(Class<? extends T> pojoClass, String setterExpr) { return createSetterInt(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> SetterInt<T> createSetterInt(Class<? extends T> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValuePlaceholder) { return (SetterInt<T>) createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValuePlaceholder, int.class, SetterInt.class); } public static <T> SetterLong<T> createSetterLong(Class<? extends T> pojoClass, String setterExpr) { return createSetterLong(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> SetterLong<T> createSetterLong(Class<? extends T> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValuePlaceholder) { return (SetterLong<T>) createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValuePlaceholder, long.class, SetterLong.class); } public static <T> SetterFloat<T> createSetterFloat(Class<? extends T> pojoClass, String setterExpr) { return createSetterFloat(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> SetterFloat<T> createSetterFloat(Class<? extends T> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValuePlaceholder) { return (SetterFloat<T>) createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValuePlaceholder, float.class, SetterFloat.class); } public static <T> SetterDouble<T> createSetterDouble(Class<? extends T> pojoClass, String setterExpr) { return createSetterDouble(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER); } @SuppressWarnings("unchecked") public static <T> SetterDouble<T> createSetterDouble(Class<? extends T> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValuePlaceholder) { return (SetterDouble<T>) createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValuePlaceholder, double.class, SetterDouble.class); } public static <T, V> Setter<T, V> createSetter(Class<? extends T> pojoClass, String setterExpr, Class<? extends V> exprClass) { return createSetter(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER, exprClass); } @SuppressWarnings("unchecked") public static <T, V> Setter<T, V> createSetter(Class<? extends T> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValuePlaceholder, Class<? extends V> exprClass) { if (primitiveClassToSetterInterface.get(exprClass) != null) { throw new IllegalArgumentException("createSetter does not allow primitive class \"" + exprClass.getName() + "\" for exprClass argument. Use createSetter" + upperCaseWord(exprClass.getName()) + " or constructSetter()."); } return (Setter<T, V>) createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValuePlaceholder, exprClass, Setter.class); } public static Object constructSetter(Class<?> pojoClass, String setterExpr, Class<?> exprClass) { return constructSetter(pojoClass, setterExpr, DEFAULT_EXP_OBJECT_PLACEHOLDER, DEFAULT_EXP_VAL_PLACEHOLDER, exprClass); } /** * * @param pojoClass Class object that the setter applies to * @param setterExpr expression to use for setter * @param exprClass Class that setter will accept as parameter * @return instance of a class that implements requested Setter interface */ public static Object constructSetter(Class<?> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValPlaceholder, Class<?> exprClass) { Class<?> interfaceToImplement = primitiveClassToSetterInterface.get(exprClass); if (interfaceToImplement == null) { interfaceToImplement = Setter.class; } return createSetter(pojoClass, setterExpr, exprObjectPlaceholder, exprValPlaceholder, exprClass, interfaceToImplement); } private static class JavaStatement { private final StringBuilder javaStatement; private final int capacity; private JavaStatement() { javaStatement = new StringBuilder(); capacity = javaStatement.capacity(); } private JavaStatement(int length) { javaStatement = new StringBuilder(length); capacity = javaStatement.capacity(); } @Override public String toString() { return javaStatement.toString(); } protected JavaStatement append(String string) { javaStatement.append(string); return this; } private JavaStatement appendCastToTypeExpr(Class<?> type, String expr) { return append("((").append(type.getName()).append(")(").append(expr).append("))"); } protected String getStatement() { if (capacity < javaStatement.length() + 1) { logger.debug( "Java statement capacity {} was not sufficient for the statement length {}. Actual statement {}", capacity, javaStatement.length(), javaStatement); } return javaStatement.append(";").toString(); } } private static class JavaReturnStatement extends JavaStatement { private JavaReturnStatement(Class<?> returnType) { super(); append("return (").append(returnType.getName()).append(")"); } private JavaReturnStatement(int length, Class<?> returnType) { super(length); append("return ((").append(returnType.getName()).append(")"); } @Override protected String getStatement() { append(")"); return super.getStatement(); } } private static String upperCaseWord(String field) { Preconditions.checkArgument(!field.isEmpty(), field); return field.substring(0, 1).toUpperCase() + field.substring(1); } /** * Return the getter expression for the given field. * <p> * If the field is a public member, the field name is used else the getter function. If no matching field or getter * method is found, the expression is returned unmodified. * * @param pojoClass class to check for the field * @param fieldExpression field name expression * @param exprClass expected field type * @return java code fragment */ private static String getSingleFieldGetterExpression(final Class<?> pojoClass, final String fieldExpression, final Class<?> exprClass) { JavaStatement code = new JavaReturnStatement( pojoClass.getName().length() + fieldExpression.length() + exprClass.getName().length() + 32, exprClass); code.appendCastToTypeExpr(pojoClass, OBJECT).append("."); try { final Field field = pojoClass.getField(fieldExpression); if (ClassUtils.isAssignable(field.getType(), exprClass)) { return code.append(field.getName()).getStatement(); } logger.debug("Field {} can not be assigned to {}. Proceeding to locate a getter method.", field, exprClass); } catch (NoSuchFieldException ex) { logger.debug("{} does not have field {}. Proceeding to locate a getter method.", pojoClass, fieldExpression); } catch (SecurityException ex) { logger.debug("{} does not have field {}. Proceeding to locate a getter method.", pojoClass, fieldExpression); } String methodName = GET + upperCaseWord(fieldExpression); try { Method method = pojoClass.getMethod(methodName); if (ClassUtils.isAssignable(method.getReturnType(), exprClass)) { return code.append(methodName).append("()").getStatement(); } logger.debug( "method {} of the {} returns {} that can not be assigned to {}. Proceeding to locate another getter method.", pojoClass, methodName, method.getReturnType(), exprClass); } catch (NoSuchMethodException | SecurityException ex) { logger.debug("{} does not have method {}. Proceeding to locate another getter method.", pojoClass, methodName); } methodName = IS + upperCaseWord(fieldExpression); try { Method method = pojoClass.getMethod(methodName); if (ClassUtils.isAssignable(method.getReturnType(), exprClass)) { return code.append(methodName).append("()").getStatement(); } logger.debug( "method {} of the {} returns {} that can not be assigned to {}. Proceeding with the original expression {}.", pojoClass, methodName, method.getReturnType(), exprClass, fieldExpression); } catch (NoSuchMethodException | SecurityException ex) { logger.debug("{} does not have method {}. Proceeding with the original expression {}.", pojoClass, methodName, fieldExpression); } return code.append(fieldExpression).getStatement(); } @SuppressWarnings("StringEquality") private static Object createGetter(Class<?> pojoClass, String getterExpr, String exprObjectPlaceholder, Class<?> exprClass, Class<?> getterClass) { logger.debug("{} {} {} {}", pojoClass, getterExpr, exprClass, getterClass); JavaExpressionParser javaExpressionParser = new JavaExpressionParser(); javaExpressionParser.setInputObjectPlaceholder(PojoUtils.DEFAULT_EXPRESSION_OBJ_PLACEHOLDER, PojoUtils.OBJECT); String code = javaExpressionParser.convertToCompilableExpression(getterExpr, pojoClass, exprClass); return compileExpression(code, getterClass, new String[] { PojoUtils.OBJECT }); } private static String getSingleFieldSetterExpression(final Class<?> pojoClass, final String fieldExpression, final Class<?> exprClass) { JavaStatement code = new JavaStatement( pojoClass.getName().length() + fieldExpression.length() + exprClass.getName().length() + 32); /* Construct ((<pojo class name>)pojo). */ code.appendCastToTypeExpr(pojoClass, OBJECT).append("."); try { final Field field = pojoClass.getField(fieldExpression); if (ClassUtils.isAssignable(exprClass, field.getType())) { /* there is public field on the class, use direct assignment. */ /* append <field name> = (<field type>)val; */ return code.append(field.getName()).append(" = ").appendCastToTypeExpr(exprClass, VAL) .getStatement(); } logger.debug("{} can not be assigned to {}. Proceeding to locate a setter method.", exprClass, field); } catch (NoSuchFieldException ex) { logger.debug("{} does not have field {}. Proceeding to locate a setter method.", pojoClass, fieldExpression); } catch (SecurityException ex) { logger.debug("{} does not have field {}. Proceeding to locate a setter method.", pojoClass, fieldExpression); } final String setMethodName = SET + upperCaseWord(fieldExpression); Method bestMatchMethod = null; List<Method> candidates = new ArrayList<Method>(); for (Method method : pojoClass.getMethods()) { if (setMethodName.equals(method.getName())) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { if (exprClass == parameterTypes[0]) { bestMatchMethod = method; break; } else if (ClassUtils.isAssignable(exprClass, parameterTypes[0])) { candidates.add(method); } } } } if (bestMatchMethod == null) { // We did not find the exact match, use candidates to find the match if (candidates.size() == 0) { logger.debug("{} does not have suitable setter method {}. Returning original expression {}.", pojoClass, setMethodName, fieldExpression); /* We did not find any match at all, use original expression */ /* append = (<expr type>)val;*/ return code.append(fieldExpression).append(" = ").appendCastToTypeExpr(exprClass, VAL) .getStatement(); } else { // TODO: see if we can find a better match bestMatchMethod = candidates.get(0); } } /* We found a method that we may use for setter */ /* append <method name>((<expr class)val); */ return code.append(bestMatchMethod.getName()).append("(").appendCastToTypeExpr(exprClass, VAL).append(")") .getStatement(); } @SuppressWarnings("StringEquality") private static Object createSetter(Class<?> pojoClass, String setterExpr, String exprObjectPlaceholder, String exprValPlaceholder, Class<?> exprClass, Class<?> setterClass) { if (setterExpr.startsWith(".")) { setterExpr = setterExpr.substring(1); } if (setterExpr.isEmpty()) { throw new IllegalArgumentException("The setter expression: \"" + setterExpr + "\" is invalid."); } logger.debug("{} {} {} {}", pojoClass, setterExpr, exprClass, setterClass); String code = StringUtils.replaceEach(setterExpr, new String[] { exprObjectPlaceholder, exprValPlaceholder }, new String[] { new JavaStatement().appendCastToTypeExpr(pojoClass, OBJECT).toString(), new JavaStatement().appendCastToTypeExpr(exprClass, VAL).toString() }); if (code != setterExpr) { code = new JavaStatement(code.length() + 1).append(code).getStatement(); logger.debug("Original expression {} is a complex expression. Replacing it with {}.", setterExpr, code); } else { code = getSingleFieldSetterExpression(pojoClass, setterExpr, exprClass); } return compileExpression(code, setterClass, new String[] { PojoUtils.OBJECT, PojoUtils.VAL }); } /** * This method takes in expression, compiles the expression to provide a executable form of expression. * This method uses {@link com.datatorrent.lib.expression.JavaExpressionParser} as expression parser. * * @param inputType Type of input object * @param expr expression to be compiled. * @param returnType Return type of the expression. * @return Object of type {@link Expression} which can be directly executed. */ public static Expression createExpression(Class<?> inputType, String expr, Class<?> returnType) { return createExpression(inputType, expr, returnType, null); } /** * This method takes in expression, compiles the expression to provide a executable form of expression. * This methods also takes in list of classes and method which can be imported statically in expression. * <p/> * This method uses {@link JavaExpressionParser} as expression parser. * * @param inputType Type of input object * @param expr expression to be compiled. * @param returnType Return type of the expression. * @param defaultImports List of classes/method which will be statically imported to expression compilation. * @return Object of type {@link Expression} which can be directly executed. */ public static Expression createExpression(Class<?> inputType, String expr, Class<?> returnType, String[] defaultImports) { JavaExpressionParser javaExpressionParser = new JavaExpressionParser(); javaExpressionParser.setInputObjectPlaceholder("$", PojoUtils.OBJECT); return createExpression(inputType, expr, returnType, defaultImports, javaExpressionParser); } /** * This method takes in expression, compiles the expression to provide a executable form of expression. * This methods also takes in list of classes and method which can be imported statically in expression. * <p/> * Using this method one can override expression parser implementation. * * @param inputType Type of input object * @param expr expression to be compiled. * @param returnType Return type of the expression. * @param defaultImports List of classes/method which will be statically imported to expression compilation. * @param parser Expression parser that should be used to parse expression. * @return Object of type {@link Expression} which can be directly executed. * @see {@link JavaExpressionParser} as a example. */ public static Expression createExpression(Class<?> inputType, String expr, Class<?> returnType, String[] defaultImports, Expression.ExpressionParser parser) { String code = parser.convertToCompilableExpression(expr, inputType, returnType); return (Expression) compileExpression(code, Expression.class, new String[] { PojoUtils.OBJECT }, defaultImports); } private static Object compileExpression(String code, Class<?> implClass, String[] params) { return compileExpression(code, implClass, params, null); } private static Object compileExpression(String code, Class<?> implClass, String[] params, String[] defaultImports) { List<String> imports = new LinkedList<>(); if (defaultImports != null && defaultImports.length != 0) { for (String defaultImport : defaultImports) { if (defaultImport != null) { if (!defaultImport.startsWith("static")) { imports.add("static " + defaultImport); } else { imports.add(defaultImport); } } } } IScriptEvaluator se; try { se = CompilerFactoryFactory.getDefaultCompilerFactory().newScriptEvaluator(); se.setDefaultImports(imports.toArray(new String[imports.size()])); } catch (Exception ex) { throw new RuntimeException(ex); } try { logger.debug("code: {}", code); return se.createFastEvaluator(code, implClass, params); } catch (CompileException ex) { throw new RuntimeException(ex); } } }