From 052fa28586efe39c833a90d973505949dd504594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20S=C3=B8rensen?= Date: Tue, 25 Aug 2015 10:47:10 +0200 Subject: [PATCH 1/5] Converted OperatorType from an enum to an interface --- .../apache/metamodel/query/FilterItem.java | 32 +------ .../apache/metamodel/query/OperatorType.java | 53 +++-------- .../metamodel/query/OperatorTypeImpl.java | 93 +++++++++++++++++++ .../org/apache/metamodel/query/Query.java | 2 +- .../metamodel/query/OperatorTypeTest.java | 14 +-- .../metamodel/util/FormatHelperTest.java | 1 - 6 files changed, 121 insertions(+), 74 deletions(-) create mode 100644 core/src/main/java/org/apache/metamodel/query/OperatorTypeImpl.java diff --git a/core/src/main/java/org/apache/metamodel/query/FilterItem.java b/core/src/main/java/org/apache/metamodel/query/FilterItem.java index 9984401bf..6fb757815 100644 --- a/core/src/main/java/org/apache/metamodel/query/FilterItem.java +++ b/core/src/main/java/org/apache/metamodel/query/FilterItem.java @@ -291,34 +291,12 @@ public String toSql(boolean includeSchemaInColumnPaths) { } public static Object appendOperator(StringBuilder sb, Object operand, OperatorType operator) { - switch (operator) { - case DIFFERENT_FROM: - sb.append(" <> "); - break; - case EQUALS_TO: - sb.append(" = "); - break; - case LIKE: - sb.append(" LIKE "); - break; - case GREATER_THAN: - sb.append(" > "); - break; - case GREATER_THAN_OR_EQUAL: - sb.append(" >= "); - break; - case LESS_THAN: - sb.append(" < "); - break; - case LESS_THAN_OR_EQUAL: - sb.append(" <= "); - break; - case IN: - sb.append(" IN "); + sb.append(' '); + sb.append(operator.toSql()); + sb.append(' '); + + if (operator == OperatorType.IN) { operand = CollectionUtils.toList(operand); - break; - default: - throw new IllegalStateException("Operator could not be determined"); } return operand; } diff --git a/core/src/main/java/org/apache/metamodel/query/OperatorType.java b/core/src/main/java/org/apache/metamodel/query/OperatorType.java index e668da824..d20f49208 100644 --- a/core/src/main/java/org/apache/metamodel/query/OperatorType.java +++ b/core/src/main/java/org/apache/metamodel/query/OperatorType.java @@ -23,58 +23,35 @@ * * @see FilterItem */ -public enum OperatorType { +public interface OperatorType { - EQUALS_TO("=", false), + public static final OperatorType EQUALS_TO = new OperatorTypeImpl("=", false); - DIFFERENT_FROM("<>", false), + public static final OperatorType DIFFERENT_FROM = new OperatorTypeImpl("<>", false); - LIKE("LIKE", true), + public static final OperatorType LIKE = new OperatorTypeImpl("LIKE", true); - GREATER_THAN(">", false), + public static final OperatorType GREATER_THAN = new OperatorTypeImpl(">", false); - GREATER_THAN_OR_EQUAL(">=", false), + public static final OperatorType GREATER_THAN_OR_EQUAL = new OperatorTypeImpl(">=", false); - LESS_THAN("<", false), + public static final OperatorType LESS_THAN = new OperatorTypeImpl("<", false); - LESS_THAN_OR_EQUAL("<=", false), + public static final OperatorType LESS_THAN_OR_EQUAL = new OperatorTypeImpl("<=", false); - IN("IN", true); + public static final OperatorType IN = new OperatorTypeImpl("IN", true); - private final String _sql; - private final boolean _spaceDelimited; - - private OperatorType(String sql, boolean spaceDelimited) { - _sql = sql; - _spaceDelimited = spaceDelimited; - } + public static final OperatorType[] BUILT_IN_OPERATORS = new OperatorType[] { EQUALS_TO, DIFFERENT_FROM, LIKE, + GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, IN }; /** * Determines if this operator requires a space delimitor. Operators that are written using letters usually require * space delimitation whereas sign-based operators such as "=" and "<" can be applied even without any delimitaton. + * + * @return */ - public boolean isSpaceDelimited() { - return _spaceDelimited; - } + public boolean isSpaceDelimited(); - public String toSql() { - return _sql; - } + public String toSql(); -/** - * Converts from SQL string literals to an OperatorType. Valid SQL values are "=", "<>", "LIKE", ">", ">=", "<" and - * "<=". - * - * @return a OperatorType object representing the specified SQL type - */ - public static OperatorType convertOperatorType(String sqlType) { - if (sqlType != null) { - for (OperatorType operator : values()) { - if (sqlType.equals(operator.toSql())) { - return operator; - } - } - } - return null; - } } diff --git a/core/src/main/java/org/apache/metamodel/query/OperatorTypeImpl.java b/core/src/main/java/org/apache/metamodel/query/OperatorTypeImpl.java new file mode 100644 index 000000000..9350f6b39 --- /dev/null +++ b/core/src/main/java/org/apache/metamodel/query/OperatorTypeImpl.java @@ -0,0 +1,93 @@ +/** + * 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 org.apache.metamodel.query; + +/** + * Simple implementation of {@link OperatorType} + */ +public class OperatorTypeImpl implements OperatorType { + + private final String _sql; + private final boolean _spaceDelimited; + + public OperatorTypeImpl(String sql, boolean spaceDelimited) { + _sql = sql; + _spaceDelimited = spaceDelimited; + } + + @Override + public boolean isSpaceDelimited() { + return _spaceDelimited; + } + + @Override + public String toSql() { + return _sql; + } + +/** + * Converts from SQL string literals to an OperatorType. Valid SQL values are "=", "<>", "LIKE", ">", ">=", "<" and + * "<=". + * + * @param sqlType + * @return a OperatorType object representing the specified SQL type + */ + public static OperatorType convertOperatorType(String sqlType) { + if (sqlType != null) { + sqlType = sqlType.trim().toUpperCase(); + switch (sqlType) { + case "=": + case "==": + case "EQ": + case "EQUALS_TO": + return OperatorType.EQUALS_TO; + case "<>": + case "!=": + case "NE": + case "NOT_EQUAL": + case "NOT_EQUAL_TO": + case "NOT_EQUALS": + case "NOT_EQUALS_TO": + case "DIFFERENT_FROM": + return OperatorType.DIFFERENT_FROM; + case ">": + case "GT": + case "GREATER_THAN": + return OperatorType.GREATER_THAN; + case ">=": + case "=>": + case "GREATER_THAN_OR_EQUAL": + return OperatorType.GREATER_THAN_OR_EQUAL; + case "IN": + return OperatorType.IN; + case "<": + case "LT": + case "LESS_THAN": + return OperatorType.LESS_THAN; + case "<=": + case "=<": + case "LESS_THAN_OR_EQUAL": + return OperatorType.LESS_THAN_OR_EQUAL; + case "LIKE": + return OperatorType.LIKE; + } + } + return null; + } +} diff --git a/core/src/main/java/org/apache/metamodel/query/Query.java b/core/src/main/java/org/apache/metamodel/query/Query.java index a1df7eae2..ae1e530d6 100644 --- a/core/src/main/java/org/apache/metamodel/query/Query.java +++ b/core/src/main/java/org/apache/metamodel/query/Query.java @@ -320,7 +320,7 @@ private FilterItem findFilterItem(String expression) { final String rightSide; { String rightSideCandidate = null; - final OperatorType[] operators = OperatorType.values(); + final OperatorType[] operators = OperatorType.BUILT_IN_OPERATORS; for (OperatorType operatorCandidate : operators) { final String searchStr; if (operatorCandidate.isSpaceDelimited()) { diff --git a/core/src/test/java/org/apache/metamodel/query/OperatorTypeTest.java b/core/src/test/java/org/apache/metamodel/query/OperatorTypeTest.java index 1a3f1f18d..cdfed2c0d 100644 --- a/core/src/test/java/org/apache/metamodel/query/OperatorTypeTest.java +++ b/core/src/test/java/org/apache/metamodel/query/OperatorTypeTest.java @@ -23,12 +23,12 @@ public class OperatorTypeTest extends TestCase { public void testConvertOperatorType() throws Exception { - assertEquals(OperatorType.EQUALS_TO, OperatorType.convertOperatorType("=")); - assertEquals(OperatorType.GREATER_THAN, OperatorType.convertOperatorType(">")); - assertEquals(OperatorType.LESS_THAN, OperatorType.convertOperatorType("<")); - assertEquals(OperatorType.DIFFERENT_FROM, OperatorType.convertOperatorType("<>")); - assertEquals(OperatorType.LIKE, OperatorType.convertOperatorType("LIKE")); - assertEquals(OperatorType.IN, OperatorType.convertOperatorType("IN")); - assertEquals(null, OperatorType.convertOperatorType("foo")); + assertEquals(OperatorType.EQUALS_TO, OperatorTypeImpl.convertOperatorType("=")); + assertEquals(OperatorType.GREATER_THAN, OperatorTypeImpl.convertOperatorType(">")); + assertEquals(OperatorType.LESS_THAN, OperatorTypeImpl.convertOperatorType("<")); + assertEquals(OperatorType.DIFFERENT_FROM, OperatorTypeImpl.convertOperatorType("<>")); + assertEquals(OperatorType.LIKE, OperatorTypeImpl.convertOperatorType("LIKE")); + assertEquals(OperatorType.IN, OperatorTypeImpl.convertOperatorType("IN")); + assertEquals(null, OperatorTypeImpl.convertOperatorType("foo")); } } diff --git a/core/src/test/java/org/apache/metamodel/util/FormatHelperTest.java b/core/src/test/java/org/apache/metamodel/util/FormatHelperTest.java index f2ef4d6f8..fc6164a9c 100644 --- a/core/src/test/java/org/apache/metamodel/util/FormatHelperTest.java +++ b/core/src/test/java/org/apache/metamodel/util/FormatHelperTest.java @@ -34,7 +34,6 @@ public void testNumberFormat() throws Exception { assertEquals("20.1", format.format(20.1)); } - @SuppressWarnings("unchecked") public void testFormatSqlValue() throws Exception { assertEquals("'foo'", FormatHelper.formatSqlValue(null, "foo")); assertEquals("1", FormatHelper.formatSqlValue(null, 1)); From b28d5d1635a8fed06b5cdf9c48b2cc474f94bec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20S=C3=B8rensen?= Date: Wed, 9 Sep 2015 20:56:38 +0200 Subject: [PATCH 2/5] Fixed deserialization of enum into instance. Improved the same also for ColumnType FunctionType --- ...egacyDeserializationObjectInputStream.java | 286 +++++++++--------- 1 file changed, 145 insertions(+), 141 deletions(-) diff --git a/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java b/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java index c1125ea46..75741487b 100644 --- a/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java +++ b/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java @@ -18,39 +18,70 @@ */ package org.apache.metamodel.util; -import static org.apache.metamodel.schema.SuperColumnType.BINARY_TYPE; -import static org.apache.metamodel.schema.SuperColumnType.BOOLEAN_TYPE; -import static org.apache.metamodel.schema.SuperColumnType.LITERAL_TYPE; -import static org.apache.metamodel.schema.SuperColumnType.NUMBER_TYPE; -import static org.apache.metamodel.schema.SuperColumnType.OTHER_TYPE; -import static org.apache.metamodel.schema.SuperColumnType.TIME_TYPE; - import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; -import java.lang.reflect.Field; -import java.math.BigInteger; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Types; +import java.lang.reflect.Method; import java.util.Comparator; -import java.util.Date; -import java.util.List; -import java.util.Map; +import org.apache.metamodel.query.AggregateFunction; +import org.apache.metamodel.query.FunctionType; +import org.apache.metamodel.query.OperatorType; import org.apache.metamodel.schema.ColumnType; -import org.apache.metamodel.schema.JdbcTypes; import org.apache.metamodel.schema.SuperColumnType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A specialized {@link ObjectInputStream} for MetaModel which can be used or * extended if it is needed to deserialize legacy MetaModel objects. This is - * needed since the namespace of MetaModel was changed from - * org.apache.metamodel to org.apache.metamodel. + * needed since the namespace of MetaModel was changed from org.apache.metamodel + * to org.apache.metamodel. */ public class LegacyDeserializationObjectInputStream extends ObjectInputStream { + private static final Logger logger = LoggerFactory.getLogger(LegacyDeserializationObjectInputStream.class); + + /** + * Implementation of the new {@link FunctionType} and + * {@link AggregateFunction} interfaces which still adheres to the + * constant/enum values of the old FunctionType definition. While + * deserializing old FunctionType objects, we will convert them to this + * enum. + */ + protected static enum LegacyFunctionType implements AggregateFunction { + + COUNT(FunctionType.COUNT), AVG(FunctionType.AVG), SUM(FunctionType.SUM), MAX(FunctionType.MAX), MIN( + FunctionType.MIN); + + private final AggregateFunction _delegate; + + private LegacyFunctionType(AggregateFunction delegate) { + _delegate = delegate; + } + + @Override + public ColumnType getExpectedColumnType(ColumnType type) { + return _delegate.getExpectedColumnType(type); + } + + @Override + public String getFunctionName() { + return _delegate.getFunctionName(); + } + + @Override + public AggregateBuilder createAggregateBuilder() { + return _delegate.createAggregateBuilder(); + } + + @Override + public Object evaluate(Object... values) { + return _delegate.evaluate(values); + } + } + /** * Implementation of the new {@link ColumnType} interface which still * adheres to the constant/enum values of the old ColumnType definition. @@ -59,174 +90,113 @@ public class LegacyDeserializationObjectInputStream extends ObjectInputStream { */ protected static enum LegacyColumnType implements ColumnType { - /** - * Literal - */ - CHAR(LITERAL_TYPE), VARCHAR(LITERAL_TYPE), LONGVARCHAR(LITERAL_TYPE), CLOB(LITERAL_TYPE), NCHAR(LITERAL_TYPE), NVARCHAR( - LITERAL_TYPE), LONGNVARCHAR(LITERAL_TYPE), NCLOB(LITERAL_TYPE), - - /** - * Numbers - */ - TINYINT(NUMBER_TYPE), SMALLINT(NUMBER_TYPE), INTEGER(NUMBER_TYPE), BIGINT(NUMBER_TYPE), FLOAT(NUMBER_TYPE), REAL( - NUMBER_TYPE), DOUBLE(NUMBER_TYPE), NUMERIC(NUMBER_TYPE), DECIMAL(NUMBER_TYPE), - - /** - * Time based - */ - DATE(TIME_TYPE), TIME(TIME_TYPE), TIMESTAMP(TIME_TYPE), - - /** - * Booleans - */ - BIT(BOOLEAN_TYPE), BOOLEAN(BOOLEAN_TYPE), - - /** - * Binary types - */ - BINARY(BINARY_TYPE), VARBINARY(BINARY_TYPE), LONGVARBINARY(BINARY_TYPE), BLOB(BINARY_TYPE), - - /** - * Other types (as defined in {@link Types}). - */ - NULL(OTHER_TYPE), OTHER(OTHER_TYPE), JAVA_OBJECT(OTHER_TYPE), DISTINCT(OTHER_TYPE), STRUCT(OTHER_TYPE), ARRAY( - OTHER_TYPE), REF(OTHER_TYPE), DATALINK(OTHER_TYPE), ROWID(OTHER_TYPE), SQLXML(OTHER_TYPE), - - /** - * Additional types (added by MetaModel for non-JDBC datastores) - */ - LIST(OTHER_TYPE), MAP(OTHER_TYPE); - - private final SuperColumnType _superType; - - private LegacyColumnType(SuperColumnType superType) { - if (superType == null) { - throw new IllegalArgumentException("SuperColumnType cannot be null"); - } - _superType = superType; + CHAR(ColumnType.CHAR), VARCHAR(ColumnType.VARCHAR), LONGVARCHAR(ColumnType.LONGVARCHAR), CLOB(ColumnType.CLOB), NCHAR( + ColumnType.NCHAR), NVARCHAR(ColumnType.NVARCHAR), LONGNVARCHAR(ColumnType.LONGNVARCHAR), NCLOB( + ColumnType.NCLOB), TINYINT(ColumnType.TINYINT), SMALLINT(ColumnType.SMALLINT), INTEGER( + ColumnType.INTEGER), BIGINT(ColumnType.BIGINT), FLOAT(ColumnType.FLOAT), REAL(ColumnType.REAL), DOUBLE( + ColumnType.DOUBLE), NUMERIC(ColumnType.NUMERIC), DECIMAL(ColumnType.DECIMAL), DATE(ColumnType.DATE), TIME( + ColumnType.TIME), TIMESTAMP(ColumnType.TIMESTAMP), BIT(ColumnType.BIT), BOOLEAN(ColumnType.BOOLEAN), BINARY( + ColumnType.BINARY), VARBINARY(ColumnType.VARBINARY), LONGVARBINARY(ColumnType.LONGVARBINARY), BLOB( + ColumnType.BLOB), NULL(ColumnType.NULL), OTHER(ColumnType.OTHER), JAVA_OBJECT(ColumnType.JAVA_OBJECT), DISTINCT( + ColumnType.DISTINCT), STRUCT(ColumnType.STRUCT), ARRAY(ColumnType.ARRAY), REF(ColumnType.REF), DATALINK( + ColumnType.DATALINK), ROWID(ColumnType.ROWID), SQLXML(ColumnType.SQLXML), LIST(ColumnType.LIST), MAP( + ColumnType.MAP); + + private final ColumnType _delegate; + + private LegacyColumnType(ColumnType delegate) { + _delegate = delegate; } @Override public String getName() { - return name(); + return _delegate.getName(); } @Override public Comparator getComparator() { - if (isTimeBased()) { - return TimeComparator.getComparator(); - } - if (isNumber()) { - return NumberComparator.getComparator(); - } - if (isLiteral()) { - return ToStringComparator.getComparator(); - } - return ObjectComparator.getComparator(); + return _delegate.getComparator(); } @Override public boolean isBoolean() { - return _superType == BOOLEAN_TYPE; + return _delegate.isBoolean(); } @Override public boolean isBinary() { - return _superType == BINARY_TYPE; + return _delegate.isBinary(); } @Override public boolean isNumber() { - return _superType == NUMBER_TYPE; + return _delegate.isNumber(); } @Override public boolean isTimeBased() { - return _superType == TIME_TYPE; + return _delegate.isTimeBased(); } @Override public boolean isLiteral() { - return _superType == LITERAL_TYPE; + return _delegate.isLiteral(); } @Override public boolean isLargeObject() { - switch (this) { - case BLOB: - case CLOB: - case NCLOB: - return true; - default: - return false; - } + return _delegate.isLargeObject(); } @Override public Class getJavaEquivalentClass() { - switch (this) { - case TINYINT: - case SMALLINT: - return Short.class; - case INTEGER: - return Integer.class; - case BIGINT: - return BigInteger.class; - case DECIMAL: - case NUMERIC: - case FLOAT: - case REAL: - case DOUBLE: - return Double.class; - case DATE: - case TIME: - case TIMESTAMP: - return Date.class; - case BLOB: - return Blob.class; - case CLOB: - case NCLOB: - return Clob.class; - case MAP: - return Map.class; - case LIST: - return List.class; - default: - // All other types have fitting java equivalent classes in the - // super - // type - return _superType.getJavaEquivalentClass(); - } + return _delegate.getJavaEquivalentClass(); } @Override public SuperColumnType getSuperType() { - return _superType; + return _delegate.getSuperType(); } @Override public int getJdbcType() throws IllegalStateException { - final String name = this.toString(); - try { - // We assume that the JdbcTypes class only consists of constant - // integer types, so we make no assertions here - final Field[] fields = JdbcTypes.class.getFields(); - for (int i = 0; i < fields.length; i++) { - Field field = fields[i]; - String fieldName = field.getName(); - if (fieldName.equals(name)) { - int value = (Integer) field.getInt(null); - return value; - } - } - throw new IllegalStateException("No JdbcType found with field name: " + name); - } catch (Exception e) { - throw new IllegalStateException("Could not access fields in JdbcTypes", e); - } + return _delegate.getJdbcType(); } } + /** + * Implementation of the new {@link OperatorType} interface which still + * adheres to the constant/enum values of the old OperatorType definition. + * While deserializing old OperatorType objects, we will convert them to + * this enum. + */ + protected static enum LegacyOperatorType implements OperatorType { + + EQUALS_TO(OperatorType.EQUALS_TO), DIFFERENT_FROM(OperatorType.DIFFERENT_FROM), LIKE(OperatorType.LIKE), GREATER_THAN( + OperatorType.GREATER_THAN), GREATER_THAN_OR_EQUAL(OperatorType.GREATER_THAN_OR_EQUAL), LESS_THAN( + OperatorType.LESS_THAN), LESS_THAN_OR_EQUAL(OperatorType.LESS_THAN_OR_EQUAL), IN(OperatorType.IN); + + private final OperatorType _delegate; + + private LegacyOperatorType(OperatorType delegate) { + _delegate = delegate; + } + + @Override + public boolean isSpaceDelimited() { + return _delegate.isSpaceDelimited(); + } + + @Override + public String toSql() { + return _delegate.toSql(); + } + + } + private static final String OLD_CLASS_NAME_COLUMN_TYPE = "org.eobjects.metamodel.schema.ColumnType"; + private static final String CLASS_NAME_OPERATOR_TYPE = "org.apache.metamodel.query.OperatorType"; + private static final String CLASS_NAME_FUNCTION_TYPE = "org.apache.metamodel.query.FunctionType"; public LegacyDeserializationObjectInputStream(InputStream in) throws IOException, SecurityException { super(in); @@ -252,10 +222,44 @@ protected Class resolveClass(ObjectStreamClass desc) throws IOException, Clas @Override protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { final ObjectStreamClass objectStreamClass = super.readClassDescriptor(); - if (OLD_CLASS_NAME_COLUMN_TYPE.equals(objectStreamClass.getName())) { - final ObjectStreamClass result = ObjectStreamClass.lookup(LegacyColumnType.class); - return result; + final String className = objectStreamClass.getName(); + switch (className) { + case OLD_CLASS_NAME_COLUMN_TYPE: + final ObjectStreamClass legacyColumnTypeResult = ObjectStreamClass.lookup(LegacyColumnType.class); + return legacyColumnTypeResult; + case CLASS_NAME_OPERATOR_TYPE: + if (isEnumExpected(objectStreamClass)) { + final ObjectStreamClass legacyOperatorTypeResult = ObjectStreamClass.lookup(LegacyOperatorType.class); + return legacyOperatorTypeResult; + } + break; + case CLASS_NAME_FUNCTION_TYPE: + if (isEnumExpected(objectStreamClass)) { + final ObjectStreamClass legacyOperatorTypeResult = ObjectStreamClass.lookup(LegacyOperatorType.class); + return legacyOperatorTypeResult; + } + break; } return objectStreamClass; } + + /** + * Method that uses the (non-public) isEnum() method of + * {@link ObjectStreamClass} to determine if an enum is expected. + * + * @param objectStreamClass + * @return + */ + private boolean isEnumExpected(ObjectStreamClass objectStreamClass) { + try { + final Method isEnumMethod = ObjectStreamClass.class.getDeclaredMethod("isEnum"); + isEnumMethod.setAccessible(true); + final Boolean result = (Boolean) isEnumMethod.invoke(objectStreamClass); + return result.booleanValue(); + } catch (Exception e) { + logger.warn("Failed to access and invoke ObjectStreamClass.isEnum to determine if {} is an enum", + objectStreamClass.getName(), e); + } + return false; + } } From 1f014e54008cd95c9473e610220f7079bc0066c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20S=C3=B8rensen?= Date: Wed, 9 Sep 2015 21:19:38 +0200 Subject: [PATCH 3/5] Made OperatorTypeImpl.equals also compare with legacy enum impl --- .../QueryPostprocessDataContext.java | 6 +- .../metamodel/query/OperatorTypeImpl.java | 21 +++++++ ...egacyDeserializationObjectInputStream.java | 2 +- .../ElasticSearchDataContext.java | 17 ++---- .../ElasticSearchDataContextTest.java | 1 - .../metamodel/mongodb/MongoDbDataContext.java | 57 +++++++++---------- 6 files changed, 57 insertions(+), 47 deletions(-) diff --git a/core/src/main/java/org/apache/metamodel/QueryPostprocessDataContext.java b/core/src/main/java/org/apache/metamodel/QueryPostprocessDataContext.java index 1fecf985e..0282a26f2 100644 --- a/core/src/main/java/org/apache/metamodel/QueryPostprocessDataContext.java +++ b/core/src/main/java/org/apache/metamodel/QueryPostprocessDataContext.java @@ -142,7 +142,7 @@ public DataSet executeQuery(final Query query) { final SelectItem selectItem = whereItem.getSelectItem(); if (!whereItem.isCompoundFilter() && selectItem != null && selectItem.getColumn() != null) { final Column column = selectItem.getColumn(); - if (column.isPrimaryKey() && whereItem.getOperator() == OperatorType.EQUALS_TO) { + if (column.isPrimaryKey() && OperatorType.EQUALS_TO.equals(whereItem.getOperator())) { logger.debug("Query is a primary key lookup query. Trying executePrimaryKeyLookupQuery(...)"); if (table != null) { if (isMainSchemaTable(table)) { @@ -430,7 +430,7 @@ protected final String[] getSchemaNamesInternal() throws MetaModelException { schemaNames[1] = getMainSchemaName(); return schemaNames; } - + @Override protected String getDefaultSchemaName() throws MetaModelException { return getMainSchemaName(); @@ -618,7 +618,7 @@ public void addConverter(Column column, TypeConverter converter) { protected DataSet materializeMainSchemaTable(Table table, List selectItems, List whereItems, int firstRow, int maxRows) { final List workingSelectItems = buildWorkingSelectItems(selectItems, whereItems); - DataSet dataSet; + DataSet dataSet; if (whereItems.isEmpty()) { // paging is pushed down to materializeMainSchemaTable dataSet = materializeMainSchemaTable(table, workingSelectItems, firstRow, maxRows); diff --git a/core/src/main/java/org/apache/metamodel/query/OperatorTypeImpl.java b/core/src/main/java/org/apache/metamodel/query/OperatorTypeImpl.java index 9350f6b39..9869c888d 100644 --- a/core/src/main/java/org/apache/metamodel/query/OperatorTypeImpl.java +++ b/core/src/main/java/org/apache/metamodel/query/OperatorTypeImpl.java @@ -18,6 +18,8 @@ */ package org.apache.metamodel.query; +import java.util.Objects; + /** * Simple implementation of {@link OperatorType} */ @@ -41,6 +43,25 @@ public String toSql() { return _sql; } + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (obj instanceof OperatorType) { + // we only require another OperatorType, not necesarily an _Impl_. + // This is to allow other implementations that wrap this. For + // instance the implementation provided by + // LegacyDeserializationObjectInputStream. + final OperatorType other = (OperatorType) obj; + return isSpaceDelimited() == other.isSpaceDelimited() && Objects.equals(toSql(), other.toSql()); + } + return false; + } + /** * Converts from SQL string literals to an OperatorType. Valid SQL values are "=", "<>", "LIKE", ">", ">=", "<" and * "<=". diff --git a/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java b/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java index 75741487b..289f82368 100644 --- a/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java +++ b/core/src/main/java/org/apache/metamodel/util/LegacyDeserializationObjectInputStream.java @@ -181,7 +181,7 @@ protected static enum LegacyOperatorType implements OperatorType { private LegacyOperatorType(OperatorType delegate) { _delegate = delegate; } - + @Override public boolean isSpaceDelimited() { return _delegate.isSpaceDelimited(); diff --git a/elasticsearch/src/main/java/org/apache/metamodel/elasticsearch/ElasticSearchDataContext.java b/elasticsearch/src/main/java/org/apache/metamodel/elasticsearch/ElasticSearchDataContext.java index ba221d1bb..0b15939d2 100644 --- a/elasticsearch/src/main/java/org/apache/metamodel/elasticsearch/ElasticSearchDataContext.java +++ b/elasticsearch/src/main/java/org/apache/metamodel/elasticsearch/ElasticSearchDataContext.java @@ -339,23 +339,14 @@ protected QueryBuilder createQueryBuilderForSimpleWhere(Table table, List operands = CollectionUtils.toList(operand); itemQueryBuilder = QueryBuilders.termsQuery(fieldName, operands); - break; - case LIKE: - case GREATER_THAN_OR_EQUAL: - case GREATER_THAN: - case LESS_THAN: - case LESS_THAN_OR_EQUAL: - default: + } else { // not (yet) support operator types return null; } diff --git a/elasticsearch/src/test/java/org/apache/metamodel/elasticsearch/ElasticSearchDataContextTest.java b/elasticsearch/src/test/java/org/apache/metamodel/elasticsearch/ElasticSearchDataContextTest.java index d421b9965..3698da6a5 100644 --- a/elasticsearch/src/test/java/org/apache/metamodel/elasticsearch/ElasticSearchDataContextTest.java +++ b/elasticsearch/src/test/java/org/apache/metamodel/elasticsearch/ElasticSearchDataContextTest.java @@ -49,7 +49,6 @@ import org.apache.metamodel.schema.Schema; import org.apache.metamodel.schema.Table; import org.apache.metamodel.update.Update; -import org.elasticsearch.Version; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; diff --git a/mongodb/src/main/java/org/apache/metamodel/mongodb/MongoDbDataContext.java b/mongodb/src/main/java/org/apache/metamodel/mongodb/MongoDbDataContext.java index 5e89b6d9b..32a2023c7 100644 --- a/mongodb/src/main/java/org/apache/metamodel/mongodb/MongoDbDataContext.java +++ b/mongodb/src/main/java/org/apache/metamodel/mongodb/MongoDbDataContext.java @@ -394,8 +394,7 @@ private void convertToCursorObject(BasicDBObject query, FilterItem item) { if (operatorName == null) { if (item.getOperator().equals(OperatorType.LIKE)) { query.put(columnName, turnOperandIntoRegExp(operand)); - } - else { + } else { query.put(columnName, operand); } } else { @@ -412,34 +411,34 @@ private void convertToCursorObject(BasicDBObject query, FilterItem item) { } private String getOperatorName(FilterItem item) { - final String operatorName; - switch (item.getOperator()) { - case EQUALS_TO: - case LIKE: - operatorName = null; - break; - case LESS_THAN: - operatorName = "$lt"; - break; - case LESS_THAN_OR_EQUAL: - operatorName = "$lte"; - break; - case GREATER_THAN: - operatorName = "$gt"; - break; - case GREATER_THAN_OR_EQUAL: - operatorName = "$gte"; - break; - case DIFFERENT_FROM: - operatorName = "$ne"; - break; - case IN: - operatorName = "$in"; - break; - default: - throw new IllegalStateException("Unsupported operator type: " + item.getOperator()); + final OperatorType operator = item.getOperator(); + + if (OperatorType.EQUALS_TO.equals(operator)) { + return null; + } + if (OperatorType.LIKE.equals(operator)) { + return null; + } + if (OperatorType.LESS_THAN.equals(operator)) { + return "$lt"; + } + if (OperatorType.LESS_THAN_OR_EQUAL.equals(operator)) { + return "$lte"; } - return operatorName; + if (OperatorType.GREATER_THAN.equals(operator)) { + return "$gt"; + } + if (OperatorType.GREATER_THAN_OR_EQUAL.equals(operator)) { + return "$gte"; + } + if (OperatorType.DIFFERENT_FROM.equals(operator)) { + return "$ne"; + } + if (OperatorType.IN.equals(operator)) { + return "$in"; + } + + throw new IllegalStateException("Unsupported operator type: " + operator); } private Pattern turnOperandIntoRegExp(Object operand) { From 0ad2b3f4b6205fc68751cb3e98c4df1ee4872413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20S=C3=B8rensen?= Date: Wed, 9 Sep 2015 21:25:49 +0200 Subject: [PATCH 4/5] Fixed use of OperatorTypeImpl.equals(...) instead of == --- .../org/apache/metamodel/jdbc/JdbcUtils.java | 2 +- .../jdbc/dialects/AbstractQueryRewriter.java | 2 +- .../jdbc/dialects/DB2QueryRewriter.java | 21 ++++++++++--------- .../jdbc/dialects/DefaultQueryRewriter.java | 2 +- .../metamodel/mongodb/MongoDbDataContext.java | 4 ++-- .../salesforce/SalesforceDataContext.java | 2 +- .../salesforce/SalesforceUpdateCallback.java | 2 +- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcUtils.java b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcUtils.java index a6065ae39..ea067516d 100644 --- a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcUtils.java +++ b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcUtils.java @@ -229,7 +229,7 @@ public static String createWhereClause(List whereItems, IQueryRewrit * @return */ public static boolean isPreparedParameterCandidate(FilterItem whereItem) { - return !whereItem.isCompoundFilter() && whereItem.getOperator() != OperatorType.IN + return !whereItem.isCompoundFilter() && !OperatorType.IN.equals(whereItem.getOperator()) && whereItem.getOperand() != null; } diff --git a/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/AbstractQueryRewriter.java b/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/AbstractQueryRewriter.java index 16ec9853f..05453dfaf 100644 --- a/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/AbstractQueryRewriter.java +++ b/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/AbstractQueryRewriter.java @@ -215,7 +215,7 @@ public String rewriteFilterItem(FilterItem item) { final String primaryFilterSql = item.toSql(isSchemaIncludedInColumnPaths()); final OperatorType operator = item.getOperator(); - if (operator == OperatorType.DIFFERENT_FROM) { + if (OperatorType.DIFFERENT_FROM.equals(operator)) { final Object operand = item.getOperand(); if (operand != null) { // special case in SQL where NULL is not treated as a value - diff --git a/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/DB2QueryRewriter.java b/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/DB2QueryRewriter.java index 0a4c31eec..fa8ebe038 100644 --- a/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/DB2QueryRewriter.java +++ b/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/DB2QueryRewriter.java @@ -111,7 +111,8 @@ public String rewriteQuery(Query query) { return baseQueryString + " WHERE metamodel_row_number > " + (firstRow - 1); } - return baseQueryString + " WHERE metamodel_row_number BETWEEN " + firstRow + " AND " + (firstRow - 1 + maxRows); + return baseQueryString + " WHERE metamodel_row_number BETWEEN " + firstRow + " AND " + + (firstRow - 1 + maxRows); } } @@ -125,26 +126,26 @@ public String rewriteColumnType(ColumnType columnType, Integer columnSize) { @Override public String rewriteFilterItem(FilterItem item) { - SelectItem _selectItem = item.getSelectItem(); - Object _operand = item.getOperand(); - OperatorType _operator = item.getOperator(); - if (null != _selectItem && _operand != null) { - ColumnType columnType = _selectItem.getExpectedColumnType(); + final SelectItem selectItem = item.getSelectItem(); + final Object itemOperand = item.getOperand(); + final OperatorType operator = item.getOperator(); + if (null != selectItem && itemOperand != null) { + ColumnType columnType = selectItem.getExpectedColumnType(); if (columnType != null) { if (columnType.isTimeBased()) { // special logic for DB2 based time operands. StringBuilder sb = new StringBuilder(); - sb.append(_selectItem.getSameQueryAlias(true)); - final Object operand = FilterItem.appendOperator(sb, _operand, _operator); + sb.append(selectItem.getSameQueryAlias(true)); + final Object operand = FilterItem.appendOperator(sb, itemOperand, operator); if (operand instanceof SelectItem) { final String selectItemString = ((SelectItem) operand).getSameQueryAlias(true); sb.append(selectItemString); } else { - Date date = TimeComparator.toDate(_operand); + Date date = TimeComparator.toDate(itemOperand); if (date == null) { - throw new IllegalStateException("Could not convert " + _operand + " to date"); + throw new IllegalStateException("Could not convert " + itemOperand + " to date"); } final String sqlValue = FormatHelper.formatSqlTime(columnType, date, true, "('", "')"); diff --git a/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/DefaultQueryRewriter.java b/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/DefaultQueryRewriter.java index e44df06bf..288bf785b 100644 --- a/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/DefaultQueryRewriter.java +++ b/jdbc/src/main/java/org/apache/metamodel/jdbc/dialects/DefaultQueryRewriter.java @@ -117,7 +117,7 @@ public String rewriteFilterItem(FilterItem item) { // operand is a set of values (typically in combination with an // IN operator). Each individual element must be escaped. - assert item.getOperator() == OperatorType.IN; + assert OperatorType.IN.equals(item.getOperator()); @SuppressWarnings("unchecked") final List elements = (List) CollectionUtils.toList(operand); diff --git a/mongodb/src/main/java/org/apache/metamodel/mongodb/MongoDbDataContext.java b/mongodb/src/main/java/org/apache/metamodel/mongodb/MongoDbDataContext.java index 32a2023c7..73adea4b8 100644 --- a/mongodb/src/main/java/org/apache/metamodel/mongodb/MongoDbDataContext.java +++ b/mongodb/src/main/java/org/apache/metamodel/mongodb/MongoDbDataContext.java @@ -306,7 +306,7 @@ public DataSet executeQuery(Query query) { final SelectItem selectItem = whereItem.getSelectItem(); if (!whereItem.isCompoundFilter() && selectItem != null && selectItem.getColumn() != null) { final Column column = selectItem.getColumn(); - if (column.isPrimaryKey() && whereItem.getOperator() == OperatorType.EQUALS_TO) { + if (column.isPrimaryKey() && OperatorType.EQUALS_TO.equals(whereItem.getOperator())) { logger.debug("Query is a primary key lookup query. Trying executePrimaryKeyLookupQuery(...)"); final Object operand = whereItem.getOperand(); final Row row = executePrimaryKeyLookupQuery(table, selectItems, column, operand); @@ -392,7 +392,7 @@ private void convertToCursorObject(BasicDBObject query, FilterItem item) { final BasicDBObject existingFilterObject = (BasicDBObject) query.get(columnName); if (existingFilterObject == null) { if (operatorName == null) { - if (item.getOperator().equals(OperatorType.LIKE)) { + if (OperatorType.LIKE.equals(item.getOperator())) { query.put(columnName, turnOperandIntoRegExp(operand)); } else { query.put(columnName, operand); diff --git a/salesforce/src/main/java/org/apache/metamodel/salesforce/SalesforceDataContext.java b/salesforce/src/main/java/org/apache/metamodel/salesforce/SalesforceDataContext.java index 730aaaef0..c8add52bb 100644 --- a/salesforce/src/main/java/org/apache/metamodel/salesforce/SalesforceDataContext.java +++ b/salesforce/src/main/java/org/apache/metamodel/salesforce/SalesforceDataContext.java @@ -269,7 +269,7 @@ protected static void rewriteFilterItem(StringBuilder sb, FilterItem filterItem) sb.append(' '); final OperatorType operator = filterItem.getOperator(); - if (operator == OperatorType.IN) { + if (OperatorType.IN.equals(operator)) { throw new UnsupportedOperationException("IN operator not supported: " + filterItem); } sb.append(operator.toSql()); diff --git a/salesforce/src/main/java/org/apache/metamodel/salesforce/SalesforceUpdateCallback.java b/salesforce/src/main/java/org/apache/metamodel/salesforce/SalesforceUpdateCallback.java index 21669d332..757cb9565 100644 --- a/salesforce/src/main/java/org/apache/metamodel/salesforce/SalesforceUpdateCallback.java +++ b/salesforce/src/main/java/org/apache/metamodel/salesforce/SalesforceUpdateCallback.java @@ -233,7 +233,7 @@ protected void buildIdList(List idList, FilterItem whereItem) { final OperatorType operator = whereItem.getOperator(); - if (operator != OperatorType.EQUALS_TO && operator != OperatorType.IN) { + if (!OperatorType.EQUALS_TO.equals(operator) && !OperatorType.IN.equals(operator)) { throw new IllegalStateException( "Salesforce only allows deletion of records by their specific IDs. Violated by operator in where item: " + whereItem); From 9f43cfb2c7f7982b20136c0b4f3cc1d8d7f2c8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20S=C3=B8rensen?= Date: Thu, 10 Sep 2015 20:58:08 +0200 Subject: [PATCH 5/5] Added more tests for resolution of OperatorTypes based on aliases. Updated CHANGES.md --- CHANGES.md | 1 + .../metamodel/query/OperatorTypeTest.java | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 89baa1b22..e42adad80 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ * [METAMODEL-176] - Trimmed the transient dependencies of the JDBC module. * [METAMODEL-170] - Dropped support for Java 6. * [METAMODEL-178] - Added AggregateFunction and ScalarFunction interfaces. Changed FunctionType enum to be super-interface of those. Compatibility is retained but a recompile of code using FunctionType is needed. + * [METAMODEL-188] - Changed OperatorType enum to be an interface. Compatibility is retained but a recompile of code is needed. * [METAMODEL-179] - Ensured that HdfsResource is not closing a shared HDFS file system reference. * [METAMODEL-171] - Made integration tests for Cassandra module function properly in all environments. * [METAMODEL-177] - Fixed a bug pertaining to the serializability of HdfsResource. diff --git a/core/src/test/java/org/apache/metamodel/query/OperatorTypeTest.java b/core/src/test/java/org/apache/metamodel/query/OperatorTypeTest.java index cdfed2c0d..c46073492 100644 --- a/core/src/test/java/org/apache/metamodel/query/OperatorTypeTest.java +++ b/core/src/test/java/org/apache/metamodel/query/OperatorTypeTest.java @@ -22,7 +22,7 @@ public class OperatorTypeTest extends TestCase { - public void testConvertOperatorType() throws Exception { + public void testConvertOperatorTypeNormal() throws Exception { assertEquals(OperatorType.EQUALS_TO, OperatorTypeImpl.convertOperatorType("=")); assertEquals(OperatorType.GREATER_THAN, OperatorTypeImpl.convertOperatorType(">")); assertEquals(OperatorType.LESS_THAN, OperatorTypeImpl.convertOperatorType("<")); @@ -31,4 +31,33 @@ public void testConvertOperatorType() throws Exception { assertEquals(OperatorType.IN, OperatorTypeImpl.convertOperatorType("IN")); assertEquals(null, OperatorTypeImpl.convertOperatorType("foo")); } + + public void testConvertOperatorTypeAliases() throws Exception { + assertEquals(OperatorType.EQUALS_TO, OperatorTypeImpl.convertOperatorType("eq")); + assertEquals(OperatorType.EQUALS_TO, OperatorTypeImpl.convertOperatorType("EQ")); + assertEquals(OperatorType.EQUALS_TO, OperatorTypeImpl.convertOperatorType("EQUALS_TO")); + assertEquals(OperatorType.EQUALS_TO, OperatorTypeImpl.convertOperatorType("==")); + assertEquals(OperatorType.DIFFERENT_FROM, OperatorTypeImpl.convertOperatorType("!=")); + assertEquals(OperatorType.DIFFERENT_FROM, OperatorTypeImpl.convertOperatorType("DIFFERENT_FROM")); + assertEquals(OperatorType.DIFFERENT_FROM, OperatorTypeImpl.convertOperatorType("ne")); + assertEquals(OperatorType.DIFFERENT_FROM, OperatorTypeImpl.convertOperatorType("NOT_EQUALS_TO")); + assertEquals(OperatorType.DIFFERENT_FROM, OperatorTypeImpl.convertOperatorType("NOT_EQUAL_TO")); + assertEquals(OperatorType.IN, OperatorTypeImpl.convertOperatorType("in")); + assertEquals(OperatorType.IN, OperatorTypeImpl.convertOperatorType("IN")); + assertEquals(OperatorType.GREATER_THAN, OperatorTypeImpl.convertOperatorType("GREATER_THAN")); + assertEquals(OperatorType.GREATER_THAN, OperatorTypeImpl.convertOperatorType("GT")); + assertEquals(OperatorType.GREATER_THAN_OR_EQUAL, OperatorTypeImpl.convertOperatorType(">=")); + assertEquals(OperatorType.GREATER_THAN_OR_EQUAL, OperatorTypeImpl.convertOperatorType("=>")); + assertEquals(OperatorType.GREATER_THAN_OR_EQUAL, OperatorTypeImpl.convertOperatorType("GREATER_THAN_OR_EQUAL")); + assertEquals(OperatorType.LESS_THAN, OperatorTypeImpl.convertOperatorType("lt")); + assertEquals(OperatorType.LESS_THAN, OperatorTypeImpl.convertOperatorType("LESS_THAN")); + assertEquals(OperatorType.LESS_THAN_OR_EQUAL, OperatorTypeImpl.convertOperatorType("<=")); + assertEquals(OperatorType.LESS_THAN_OR_EQUAL, OperatorTypeImpl.convertOperatorType("=<")); + assertEquals(OperatorType.LESS_THAN_OR_EQUAL, OperatorTypeImpl.convertOperatorType("LESS_THAN_OR_EQUAL")); + assertEquals(OperatorType.LIKE, OperatorTypeImpl.convertOperatorType("like")); + } + + public void testConvertOperatorTypeTrimmed() throws Exception { + assertEquals(OperatorType.EQUALS_TO, OperatorTypeImpl.convertOperatorType(" = ")); + } }