| /** |
| * 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); |
| } |
| } |
| |
| } |
| |