/*
* Copyright (c) 2008-2012, Hazel Bilisim Ltd. All Rights Reserved.
*
* Licensed 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.hazelcast.query;
import com.hazelcast.core.MapEntry;
import com.hazelcast.impl.Util;
import com.hazelcast.nio.DataSerializable;
import com.hazelcast.nio.SerializationHelper;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class Predicates {
private static final String timestampFormat = "yyyy-MM-dd hh:mm:ss.SSS";
private static final String dateFormat = "EEE MMM dd HH:mm:ss zzz yyyy";
private static final String sqlDateFormat = "yyyy-mm-dd";
public static class GreaterLessPredicate extends EqualPredicate {
boolean equal = false;
boolean less = false;
public GreaterLessPredicate() {
}
public GreaterLessPredicate(Expression first, Expression second, boolean equal, boolean less) {
super(first, second);
this.equal = equal;
this.less = less;
}
public GreaterLessPredicate(Expression first, Object second, boolean equal, boolean less) {
super(first, second);
this.equal = equal;
this.less = less;
}
protected boolean doApply(Object first, Object second) {
int expectedResult = (less) ? -1 : 1;
int result = ((Comparable) first).compareTo(second);
return equal && result == 0 || (expectedResult == result);
}
public Set<MapEntry> filter(QueryContext queryContext) {
Index index = queryContext.getMapIndexes().get(first);
return index.getSubRecords(equal, less, index.getLongValue(second));
}
@Override
public void readData(DataInput in) throws IOException {
super.readData(in);
equal = in.readBoolean();
less = in.readBoolean();
}
@Override
public void writeData(DataOutput out) throws IOException {
super.writeData(out);
out.writeBoolean(equal);
out.writeBoolean(less);
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append(first);
sb.append(less ? "<" : ">");
if (equal) sb.append("=");
sb.append(second);
return sb.toString();
}
}
public static class BetweenPredicate extends EqualPredicate {
Object to;
Comparable fromConvertedValue = null;
Comparable toConvertedValue = null;
public BetweenPredicate() {
}
public BetweenPredicate(Expression first, Expression from, Object to) {
super(first, from);
this.to = to;
}
public BetweenPredicate(Expression first, Object from, Object to) {
super(first, from);
this.to = to;
}
public boolean apply(MapEntry entry) {
Expression<Comparable> cFirst = (Expression<Comparable>) first;
Comparable firstValue = cFirst.getValue(entry);
if (firstValue == null) {
return false;
}
if (fromConvertedValue == null) {
fromConvertedValue = (Comparable) getConvertedRealValue(firstValue, second);
toConvertedValue = (Comparable) getConvertedRealValue(firstValue, to);
}
if (firstValue == null || fromConvertedValue == null || toConvertedValue == null) return false;
return firstValue.compareTo(fromConvertedValue) >= 0 && firstValue.compareTo(toConvertedValue) <= 0;
}
public Set<MapEntry> filter(QueryContext queryContext) {
Index index = queryContext.getMapIndexes().get(first);
return index.getSubRecordsBetween(index.getLongValue(second), index.getLongValue(to));
}
public void writeData(DataOutput out) throws IOException {
super.writeData(out);
writeObject(out, to);
}
public void readData(DataInput in) throws IOException {
super.readData(in);
to = readObject(in);
}
@Override
public String toString() {
return first + " BETWEEN " + second + " AND " + to;
}
}
public static class NotEqualPredicate extends EqualPredicate implements IndexAwarePredicate {
public NotEqualPredicate() {
}
public NotEqualPredicate(Expression first, Expression second) {
super(first, second);
}
public NotEqualPredicate(Expression first, Object second) {
super(first, second);
}
public boolean apply(MapEntry entry) {
return !super.apply(entry);
}
public Set<MapEntry> filter(QueryContext queryContext) {
Index index = queryContext.getMapIndexes().get(first);
if (index != null) {
return index.getSubRecords(false, false, index.getLongValue(second));
} else {
return null;
}
}
@Override
public String toString() {
return first + " != " + second;
}
}
public static class NotPredicate extends AbstractPredicate {
Predicate predicate;
public NotPredicate(Predicate predicate) {
this.predicate = predicate;
}
public NotPredicate() {
}
public boolean apply(MapEntry mapEntry) {
return !predicate.apply(mapEntry);
}
public void writeData(DataOutput out) throws IOException {
writeObject(out, predicate);
}
public void readData(DataInput in) throws IOException {
predicate = (Predicate) readObject(in);
}
@Override
public String toString() {
return "NOT(" + predicate + ")";
}
}
public static class InPredicate extends AbstractPredicate implements IndexAwarePredicate {
Expression first;
Object[] inValueArray = null;
Set inValues = null;
Set convertedInValues = null;
Object firstValueObject = null;
public InPredicate() {
}
public InPredicate(Expression first, Object... second) {
this.first = first;
this.inValueArray = second;
}
private void checkInValues() {
if (inValues == null) {
this.inValues = new HashSet(inValueArray.length);
for (Object o : inValueArray) {
inValues.add(o);
}
}
}
public boolean apply(MapEntry entry) {
checkInValues();
if (firstValueObject == null) {
firstValueObject = inValues.iterator().next();
}
Object entryValue = first.getValue(entry);
if (entryValue == null) return false;
if (convertedInValues != null) {
return in(entryValue, convertedInValues);
} else {
if (entryValue.getClass() == firstValueObject.getClass()) {
return in(entryValue, inValues);
} else if (firstValueObject instanceof String) {
convertedInValues = new HashSet(inValues.size());
for (Object objValue : inValues) {
convertedInValues.add(getRealObject(entryValue, objValue));
}
return in(entryValue, convertedInValues);
}
}
return in(entryValue, inValues);
}
private static boolean in(Object firstVal, Set values) {
return values.contains(firstVal);
}
public boolean collectIndexAwarePredicates(List<IndexAwarePredicate> lsIndexPredicates, Map<Expression, Index> mapIndexes) {
if (first instanceof GetExpression) {
Index index = mapIndexes.get(first);
if (index != null) {
lsIndexPredicates.add(this);
return true;
}
}
return false;
}
public void collectAppliedIndexes(Set<Index> setAppliedIndexes, Map<Expression, Index> mapIndexes) {
Index index = mapIndexes.get(first);
if (index != null) {
setAppliedIndexes.add(index);
}
}
public boolean isIndexed(QueryContext queryContext) {
return queryContext.getMapIndexes().get(first) != null;
}
public Set<MapEntry> filter(QueryContext queryContext) {
checkInValues();
Index index = queryContext.getMapIndexes().get(first);
if (index != null) {
Set<Long> setLongValues = new HashSet<Long>(inValues.size());
for (Object valueObj : inValues) {
final Long value = index.getLongValue(valueObj);
setLongValues.add(value);
}
return index.getRecords(setLongValues);
} else {
return null;
}
}
public Object getValue() {
return inValues;
}
public void writeData(DataOutput out) throws IOException {
writeObject(out, first);
out.writeInt(inValueArray.length);
for (Object value : inValueArray) {
writeObject(out, value);
}
}
public void readData(DataInput in) throws IOException {
try {
first = (Expression) readObject(in);
int len = in.readInt();
inValueArray = new Object[len];
for (int i = 0; i < len; i++) {
inValueArray[i] = readObject(in);
}
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append(first);
sb.append(" IN (");
for (int i = 0; i < inValueArray.length; i++) {
if (i > 0) sb.append(",");
sb.append(inValueArray[i]);
}
sb.append(")");
return sb.toString();
}
}
public static class RegexPredicate extends AbstractPredicate {
Expression<String> first;
String regex;
Pattern pattern = null;
public RegexPredicate() {
}
public RegexPredicate(Expression<String> first, String regex) {
this.first = first;
this.regex = regex;
}
public boolean apply(MapEntry entry) {
String firstVal = first.getValue(entry);
if (firstVal == null) {
return (regex == null);
} else if (regex == null) {
return false;
} else {
if (pattern == null) {
pattern = Pattern.compile(regex);
}
Matcher m = pattern.matcher(firstVal);
return m.matches();
}
}
public void writeData(DataOutput out) throws IOException {
writeObject(out, first);
out.writeUTF(regex);
}
public void readData(DataInput in) throws IOException {
try {
first = (Expression) readObject(in);
regex = in.readUTF();
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
@Override
public String toString() {
return first + " REGEX '" + regex + "'";
}
}
public static class LikePredicate extends AbstractPredicate {
Expression<String> first;
String second;
Pattern pattern = null;
public LikePredicate() {
}
public LikePredicate(Expression<String> first, String second) {
this.first = first;
this.second = second;
}
public boolean apply(MapEntry entry) {
String firstVal = first.getValue(entry);
if (firstVal == null) {
return (second == null);
} else if (second == null) {
return false;
} else {
if (pattern == null) {
pattern = Pattern.compile(second.replaceAll("%", ".*").replaceAll("_", "."));
}
Matcher m = pattern.matcher(firstVal);
return m.matches();
}
}
public void writeData(DataOutput out) throws IOException {
writeObject(out, first);
out.writeUTF(second);
}
public void readData(DataInput in) throws IOException {
try {
first = (Expression) readObject(in);
second = in.readUTF();
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
@Override
public String toString() {
return first + " LIKE '" + second + "'";
}
}
public static class EqualPredicate extends AbstractPredicate implements IndexAwarePredicate {
Expression first;
Object second;
Object convertedSecondValue = null;
protected boolean secondIsExpression = false;
public EqualPredicate() {
}
public EqualPredicate(Expression first, Expression second) {
this.first = first;
this.second = second;
this.secondIsExpression = true;
}
public EqualPredicate(Expression first, Object second) {
this.first = first;
this.second = second;
}
public boolean apply(MapEntry entry) {
if (secondIsExpression) {
return doApply(first.getValue(entry), ((Expression) second).getValue(entry));
} else {
Object firstVal = first.getValue(entry);
if (firstVal == null) {
return (second == null);
} else if (second == null) {
return false;
} else {
if (convertedSecondValue == null) {
convertedSecondValue = getConvertedRealValue(firstVal, second);
}
return doApply(firstVal, convertedSecondValue);
}
}
}
protected static Object getConvertedRealValue(Object firstValue, Object value) {
if (firstValue == null) return value;
if (firstValue.getClass() == value.getClass()) {
return value;
} else {
return getRealObject(firstValue, value);
}
}
protected boolean doApply(Object first, Object second) {
return first.equals(second);
}
public boolean collectIndexAwarePredicates(List<IndexAwarePredicate> lsIndexPredicates, Map<Expression, Index> mapIndexes) {
if (!secondIsExpression && first instanceof GetExpression) {
Index index = mapIndexes.get(first);
if (index != null) {
lsIndexPredicates.add(this);
return true;
}
}
return false;
}
public void collectAppliedIndexes(Set<Index> setAppliedIndexes, Map<Expression, Index> mapIndexes) {
Index index = mapIndexes.get(first);
if (index != null) {
setAppliedIndexes.add(index);
}
}
public boolean isIndexed(QueryContext queryContext) {
return queryContext.getMapIndexes().get(first) != null;
}
public Set<MapEntry> filter(QueryContext queryContext) {
Index index = queryContext.getMapIndexes().get(first);
if (index != null) {
return index.getRecords(index.getLongValue(second));
} else {
return null;
}
}
public Object getValue() {
return second;
}
public void writeData(DataOutput out) throws IOException {
writeObject(out, first);
out.writeBoolean(secondIsExpression);
writeObject(out, second);
}
public void readData(DataInput in) throws IOException {
try {
first = (Expression) readObject(in);
secondIsExpression = in.readBoolean();
second = readObject(in);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
@Override
public String toString() {
return first + "=" + second;
}
}
public static abstract class AbstractPredicate extends SerializationHelper implements Predicate, DataSerializable {
public static Object getRealObject(Object type, Object value) {
String valueString = String.valueOf(value);
Object result = null;
if (type instanceof Boolean) {
result = "true".equalsIgnoreCase(valueString) ? true : false;
} else if (type instanceof Integer) {
if (value instanceof Number) {
result = ((Number) value).intValue();
} else {
result = Integer.valueOf(valueString);
}
} else if (type instanceof Long) {
if (value instanceof Number) {
result = ((Number) value).longValue();
} else {
result = Long.valueOf(valueString);
}
} else if (type instanceof Double) {
if (value instanceof Number) {
result = ((Number) value).doubleValue();
} else {
result = Double.valueOf(valueString);
}
} else if (type instanceof Float) {
if (value instanceof Number) {
result = ((Number) value).floatValue();
} else {
result = Float.valueOf(valueString);
}
} else if (type instanceof Byte) {
if (value instanceof Number) {
result = ((Number) value).byteValue();
} else {
result = Byte.valueOf(valueString);
}
} else if (type instanceof Timestamp) {
if (value instanceof Date) { // one of java.util.Date or java.sql.Date
result = value;
} else {
try {
result = new Timestamp(getTimestampFormat().parse(valueString).getTime());
} catch (ParseException e) {
Util.throwUncheckedException(e);
}
}
} else if (type instanceof java.sql.Date) {
if (value instanceof Date) { // one of java.util.Date or java.sql.Timestamp
result = value;
} else {
try {
result = getSqlDateFormat().parse(valueString);
} catch (ParseException e) {
Util.throwUncheckedException(e);
}
}
} else if (type instanceof Date) {
if (value instanceof Date) { // one of java.sql.Date or java.sql.Timestamp
result = value;
} else {
try {
result = getUtilDateFormat().parse(valueString);
} catch (ParseException e) {
Util.throwUncheckedException(e);
}
}
} else if (type.getClass().isEnum()) {
try {
Enum enumType = (Enum) type;
String lastEnum = valueString;
if (valueString.indexOf(".") != -1) {
// there is a dot in the value specifier, keep part after last dot
lastEnum = valueString.substring(1 + valueString.lastIndexOf("."));
}
result = enumType.valueOf(enumType.getClass(), lastEnum);
} catch (IllegalArgumentException iae) {
// illegal enum value specification
throw new IllegalArgumentException("Illegal enum value specification: " + iae.getMessage());
}
} else {
throw new RuntimeException("Unknown type " + type + " value=" + valueString);
}
return result;
}
}
public static class AndOrPredicate extends AbstractPredicate implements IndexAwarePredicate {
Predicate[] predicates;
boolean and = false;
public AndOrPredicate() {
}
public AndOrPredicate(boolean and, Predicate first, Predicate second) {
this.and = and;
predicates = new Predicate[]{first, second};
}
public AndOrPredicate(boolean and, Predicate... predicates) {
this.and = and;
this.predicates = predicates;
}
public boolean apply(MapEntry mapEntry) {
for (Predicate predicate : predicates) {
boolean result = predicate.apply(mapEntry);
if (and && !result) return false;
else if (!and && result) return true;
}
return and;
}
public boolean collectIndexAwarePredicates(List<IndexAwarePredicate> lsIndexPredicates, Map<Expression, Index> mapIndexes) {
boolean strong = and;
if (!mapIndexes.isEmpty()) {
lsIndexPredicates.add(this);
if (strong) {
final List<IndexAwarePredicate> indexPredicates =
new ArrayList<IndexAwarePredicate>(predicates.length);
for (Predicate predicate : predicates) {
if (predicate instanceof IndexAwarePredicate) {
IndexAwarePredicate p = (IndexAwarePredicate) predicate;
if (!p.collectIndexAwarePredicates(indexPredicates, mapIndexes)) {
strong = false;
}
} else {
strong = false;
}
if (!strong) {
break;
}
}
}
return strong;
}
if (and) {
for (Predicate predicate : predicates) {
if (predicate instanceof IndexAwarePredicate) {
IndexAwarePredicate p = (IndexAwarePredicate) predicate;
if (!p.collectIndexAwarePredicates(lsIndexPredicates, mapIndexes)) {
strong = false;
}
} else {
strong = false;
}
}
}
return strong;
}
public boolean isIndexed(QueryContext queryContext) {
return true;
}
public Set<MapEntry> filter(QueryContext queryContext) {
Set<MapEntry> results = null;
for (Predicate predicate : predicates) {
Set<MapEntry> filter = null;
if (predicate instanceof IndexAwarePredicate && ((IndexAwarePredicate) predicate).isIndexed(queryContext)) {
IndexAwarePredicate p = (IndexAwarePredicate) predicate;
filter = p.filter(queryContext);
} else {
filter = new HashSet<MapEntry>();
if (and && results != null) {
for (MapEntry result : results) {
if (predicate.apply(result)) {
filter.add(result);
}
}
results = filter;
continue;
} else {
for (MapEntry entry : queryContext.getMapIndexService().getOwnedRecords()) {
if (predicate.apply(entry)) {
filter.add(entry);
}
}
}
}
if (and && (filter == null || filter.isEmpty())) return null;
if (results == null) { // first predicate
if (and) {
results = filter;
} else if (filter == null) {
results = new HashSet<MapEntry>();
} else {
results = new HashSet<MapEntry>(filter);
}
} else {
if (and) {
boolean direct = results.size() < filter.size();
final Set<MapEntry> s1 = direct ? results : filter;
final Set<MapEntry> s2 = direct ? filter : results;
results = new HashSet<MapEntry>();
for (MapEntry next : s1) {
if (s2.contains(next)) {
results.add(next);
}
}
if (results.isEmpty()) return null;
} else if (filter != null) { // 'OR' case so add all none-null results
results.addAll(filter);
}
}
}
return results;
}
public void collectAppliedIndexes(Set<Index> setAppliedIndexes, Map<Expression, Index> mapIndexes) {
if (and) {
for (Predicate predicate : predicates) {
if (predicate instanceof IndexAwarePredicate) {
IndexAwarePredicate p = (IndexAwarePredicate) predicate;
p.collectAppliedIndexes(setAppliedIndexes, mapIndexes);
}
}
}
}
public void writeData(DataOutput out) throws IOException {
out.writeBoolean(and);
out.writeInt(predicates.length);
for (Predicate predicate : predicates) {
writeObject(out, predicate);
}
}
public void readData(DataInput in) throws IOException {
and = in.readBoolean();
int len = in.readInt();
predicates = new Predicate[len];
for (int i = 0; i < len; i++) {
predicates[i] = (Predicate) readObject(in);
}
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append("(");
String andOr = (and) ? " AND " : " OR ";
int size = predicates.length;
for (int i = 0; i < size; i++) {
if (i > 0) {
sb.append(andOr);
}
sb.append(predicates[i]);
}
sb.append(")");
return sb.toString();
}
}
public static Predicate instanceOf(final Class klass) {
return new Predicate() {
public boolean apply(MapEntry mapEntry) {
Object value = mapEntry.getValue();
if (value == null) return false;
return klass.isAssignableFrom(value.getClass());
}
@Override
public String toString() {
return " instanceOf (" + klass.getName() + ")";
}
};
}
public static Predicate and(Predicate x, Predicate y) {
return new AndOrPredicate(true, x, y);
}
public static Predicate not(Predicate predicate) {
return new NotPredicate(predicate);
}
public static Predicate or(Predicate x, Predicate y) {
return new AndOrPredicate(false, x, y);
}
public static Predicate notEqual(final Expression x, final Object y) {
return new NotEqualPredicate(x, y);
}
public static Predicate equal(final Expression x, final Object y) {
return new EqualPredicate(x, y);
}
public static Predicate like(final Expression<String> x, String pattern) {
return new LikePredicate(x, pattern);
}
public static <T extends Comparable<T>> Predicate greaterThan(Expression<? extends T> x, T y) {
return new GreaterLessPredicate(x, y, false, false);
}
public static <T extends Comparable<T>> Predicate greaterEqual(Expression<? extends T> x, T y) {
return new GreaterLessPredicate(x, y, true, false);
}
public static <T extends Comparable<T>> Predicate lessThan(Expression<? extends T> x, T y) {
return new GreaterLessPredicate(x, y, false, true);
}
public static <T extends Comparable<T>> Predicate lessEqual(Expression<? extends T> x, T y) {
return new GreaterLessPredicate(x, y, true, true);
}
public static <T extends Comparable<T>> Predicate between(Expression<? extends T> expression, T from, T to) {
return new BetweenPredicate(expression, from, to);
}
public static <T extends Comparable<T>> Predicate in(Expression<? extends T> expression, T... values) {
return new InPredicate(expression, values);
}
public static Predicate isNot(final Expression<Boolean> x) {
return new Predicate() {
public boolean apply(MapEntry entry) {
Boolean value = x.getValue(entry);
return Boolean.FALSE.equals(value);
}
};
}
public static GetExpression get(final String methodName) {
return new GetExpressionImpl(methodName);
}
public static abstract class AbstractExpression extends SerializationHelper implements Expression {
}
interface GetExpression<T> extends Expression {
GetExpression get(String fieldName);
}
public static final class GetExpressionImpl<T> extends AbstractExpression implements GetExpression, DataSerializable {
transient Getter getter = null;
String input;
List<GetExpressionImpl<T>> ls = null;
public GetExpressionImpl() {
}
public GetExpressionImpl(String input) {
this.input = input;
}
public GetExpression get(String methodName) {
if (ls == null) {
ls = new ArrayList();
}
ls.add(new GetExpressionImpl(methodName));
return this;
}
public Object getValue(Object obj) {
if (ls != null) {
Object result = doGetValue(obj);
for (GetExpressionImpl<T> e : ls) {
result = e.doGetValue(result);
}
return result;
} else {
return doGetValue(obj);
}
}
private Object doGetValue(Object obj) {
if (obj instanceof MapEntry) {
obj = ((MapEntry) obj).getValue();
}
if (obj == null) return null;
try {
if (getter == null) {
Getter parent = null;
Class clazz = obj.getClass();
List<String> possibleMethodNames = new ArrayList<String>(3);
for (final String name : input.split("\\.")) {
Getter localGetter = null;
possibleMethodNames.clear();
possibleMethodNames.add(name);
final String camelName = Character.toUpperCase(name.charAt(0)) + name.substring(1);
possibleMethodNames.add("get" + camelName);
possibleMethodNames.add("is" + camelName);
if (name.equals("this")) {
localGetter = new ThisGetter(parent, obj);
} else {
for (String methodName : possibleMethodNames) {
try {
final Method method = clazz.getMethod(methodName, null);
method.setAccessible(true);
localGetter = new MethodGetter(parent, method);
clazz = method.getReturnType();
break;
} catch (NoSuchMethodException ignored) {
}
}
if (localGetter == null) {
try {
final Field field = clazz.getField(name);
localGetter = new FieldGetter(parent, field);
clazz = field.getType();
} catch (NoSuchFieldException ignored) {
}
}
if (localGetter == null) {
Class c = clazz;
while (!Object.class.equals(c)) {
try {
final Field field = c.getDeclaredField(name);
field.setAccessible(true);
localGetter = new FieldGetter(parent, field);
clazz = field.getType();
break;
} catch (NoSuchFieldException ignored) {
c = c.getSuperclass();
}
}
}
}
if (localGetter == null) {
throw new RuntimeException("There is no suitable accessor for '" + name + "'");
}
parent = localGetter;
}
getter = parent;
}
return getter.getValue(obj);
} catch (Throwable e) {
Util.throwUncheckedException(e);
return null;
}
}
abstract class Getter {
protected final Getter parent;
public Getter(final Getter parent) {
this.parent = parent;
}
abstract Object getValue(Object obj) throws Exception;
abstract Class getReturnType();
}
class MethodGetter extends Getter {
final Method method;
MethodGetter(Getter parent, Method method) {
super(parent);
this.method = method;
}
Object getValue(Object obj) throws Exception {
obj = parent != null ? parent.getValue(obj) : obj;
return obj != null ? method.invoke(obj) : null;
}
Class getReturnType() {
return this.method.getReturnType();
}
@Override
public String toString() {
return "MethodGetter [parent=" + parent + ", method=" + method.getName() + "]";
}
}
class FieldGetter extends Getter {
final Field field;
FieldGetter(Getter parent, Field field) {
super(parent);
this.field = field;
}
Object getValue(Object obj) throws Exception {
obj = parent != null ? parent.getValue(obj) : obj;
return obj != null ? field.get(obj) : null;
}
Class getReturnType() {
return this.field.getType();
}
@Override
public String toString() {
return "FieldGetter [parent=" + parent + ", field=" + field + "]";
}
}
class ThisGetter extends Getter {
final Object object;
public ThisGetter(final Getter parent, Object object) {
super(parent);
this.object = object;
}
@Override
Object getValue(Object obj) throws Exception {
return obj;
}
@Override
Class getReturnType() {
return this.object.getClass();
}
}
public void writeData(DataOutput out) throws IOException {
out.writeUTF(input);
}
public void readData(DataInput in) throws IOException {
input = in.readUTF();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof GetExpressionImpl)) return false;
GetExpressionImpl that = (GetExpressionImpl) o;
return input.equals(that.input);
}
@Override
public int hashCode() {
return input.hashCode();
}
@Override
public String toString() {
return input;
}
}
private static DateFormat getTimestampFormat() {
return new SimpleDateFormat(timestampFormat);
}
private static DateFormat getSqlDateFormat() {
return new SimpleDateFormat(sqlDateFormat);
}
private static DateFormat getUtilDateFormat() {
return new SimpleDateFormat(dateFormat);
}
}