/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.sql.parser;
import org.hamcrest.core.StringEndsWith;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
public class CheckParserUsagesDT {
private static Logger logger = LoggerFactory.getLogger(CheckParserUsagesDT.class);
private static Logger csvLogger = LoggerFactory.getLogger(CheckParserUsagesDT.class.getName() + ".csv");
private static Logger sqlLogger = LoggerFactory.getLogger(CheckParserUsagesDT.class.getName() + ".sql");
private static Logger codeLogger = LoggerFactory.getLogger(CheckParserUsagesDT.class.getName() + ".code");
private static Set<Class<? extends QueryTreeNode>> queryTreeNodes;
private static Collection<String> sqlLayerClassPaths;
private PropertyFinder finder;
@BeforeClass
public static void getParserClasses() {
Reflections reflections = new Reflections("com.foundationdb.sql.parser");
queryTreeNodes = reflections.getSubTypesOf(QueryTreeNode.class);
// Note: queryTreeNode is not counted here.
}
@BeforeClass
public static void getSqlLayerClassNames() throws Exception {
sqlLayerClassPaths = getClassesInPackage("com.foundationdb.sql", "com.foundationdb.sql.Main");
}
private static Collection<String> getClassesInPackage(String packageName, String sampleClass) {
String sampleClassPathSuffix = sampleClass.replaceAll("\\.", "/") + ".class";
String sampleClassPath = CheckParserUsagesDT.class.getClassLoader().getResource(sampleClassPathSuffix).getPath();
assertThat(sampleClassPath, new StringEndsWith(sampleClassPathSuffix));
String packagePath = sampleClassPath.substring(0,sampleClassPath.length()-sampleClassPathSuffix.length()) +
packageName.replaceAll("\\.", "/");
return getAllClassesInDirectory(new File(packagePath));
}
private static Collection<String> getAllClassesInDirectory(File directory) {
Collection<String> result = new HashSet<>();
for (File file : directory.listFiles()) {
if (file.isDirectory())
{
result.addAll(getAllClassesInDirectory(file));
} else if (file.isFile() && file.getName().endsWith(".class")) {
result.add(file.getAbsolutePath());
}
}
return result;
}
@Before
public void initializeFinder() throws Exception {
finder = new PropertyFinder();
for (Class<? extends QueryTreeNode> nodeClass : queryTreeNodes) {
try {
ClassReader reader = new ClassReader(nodeClass.getName());
reader.accept(finder, 0);
} catch (IOException e) {
throw new Exception("Could not open class to scan: " + nodeClass.getName(), e);
}
}
// Remove any base class methods here, before they get propagated down
finder.getNodes().get("com/foundationdb/sql/parser/DDLStatementNode")
.removeMethod("getRelativeName", "()Ljava/lang/String;")
.removeMethod("getFullName", "()Ljava/lang/String;");
finder.finalizeState();
// Remove any concrete class methods here, base class methods have already been propagated down
removeTemporarilyIgnoredUnused(finder);
}
/**
* After running this test for the first time we found a lot that were ignored.
* They look ok enough that we will table this until a later point in time.
* Ignoring them here means that we haven't checked them fully. Once we get
* a chance we should go through them and confirm and then either remove them
* or put them in a different method
* @param finder
*/
private static void removeTemporarilyIgnoredUnused(PropertyFinder finder) {
finder.getNodes().get("com/foundationdb/sql/parser/CopyStatementNode")
.removeMethod("getSubquery","()Lcom/foundationdb/sql/parser/SubqueryNode;");
finder.getNodes().get("com/foundationdb/sql/parser/CallStatementNode")
.removeMethod("getResultSetNode","()Lcom/foundationdb/sql/parser/ResultSetNode;");
finder.getNodes().get("com/foundationdb/sql/parser/ResultColumnList")
.removeMethod("getOrderByColumn","(I)Lcom/foundationdb/sql/parser/ResultColumn;");
finder.getNodes().get("com/foundationdb/sql/parser/ResultColumn")
.removeMethod("getTableNameObject","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getVirtualColumnId","()I")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/AndNode")
.removeMethod("getOperator","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getMethodName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/SubqueryNode")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;");
finder.getNodes().get("com/foundationdb/sql/parser/SimpleCaseNode")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getCaseOperands","()Lcom/foundationdb/sql/parser/ValueNodeList;")
.removeMethod("getResultValues","()Lcom/foundationdb/sql/parser/ValueNodeList;")
.removeMethod("getTableName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/ParameterNode")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/GroupByColumn")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getColumnPosition","()I");
finder.getNodes().get("com/foundationdb/sql/parser/CreateSequenceNode")
.removeMethod("getSequenceName","()Lcom/foundationdb/sql/parser/TableName;");
finder.getNodes().get("com/foundationdb/sql/parser/ConditionalNode")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getThenElseList","()Lcom/foundationdb/sql/parser/ValueNodeList;");
finder.getNodes().get("com/foundationdb/sql/parser/AlterTableRenameNode")
.removeMethod("getName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/CastNode")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;");
finder.getNodes().get("com/foundationdb/sql/parser/CursorNode")
.removeMethod("getScanIsolationLevel","()Lcom/foundationdb/sql/parser/IsolationLevel;")
.removeMethod("getUpdatableColumns","()Ljava/util/List;")
.removeMethod("getName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/UpdateNode")
.removeMethod("getTargetTableName","()Lcom/foundationdb/sql/parser/TableName;");
finder.getNodes().get("com/foundationdb/sql/parser/ColumnDefinitionNode")
.removeMethod("getAutoinc_create_or_modify_Start_Increment","()J")
.removeMethod("getGenerationClauseNode","()Lcom/foundationdb/sql/parser/GenerationClauseNode;")
.removeMethod("getName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/CurrentSequenceNode")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getColumnName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/RowResultSetNode")
.removeMethod("getResultColumns","()Lcom/foundationdb/sql/parser/ResultColumnList;")
.removeMethod("getCorrelationName","()Ljava/lang/String;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getOrigTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getTableName","()Lcom/foundationdb/sql/parser/TableName;");
finder.getNodes().get("com/foundationdb/sql/parser/HalfOuterJoinNode")
.removeMethod("getCorrelationName","()Ljava/lang/String;")
.removeMethod("getTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getUsingClause","()Lcom/foundationdb/sql/parser/ResultColumnList;")
.removeMethod("getResultColumns","()Lcom/foundationdb/sql/parser/ResultColumnList;")
.removeMethod("getLeftmostResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getJoinClause","()Lcom/foundationdb/sql/parser/ValueNode;")
.removeMethod("getLogicalLeftResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getLeftmostResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getLogicalRightResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getOrigTableName","()Lcom/foundationdb/sql/parser/TableName;");
finder.getNodes().get("com/foundationdb/sql/parser/CoalesceFunctionNode")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;");
finder.getNodes().get("com/foundationdb/sql/parser/ColumnReference")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/ModifyColumnNode")
.removeMethod("getName","()Ljava/lang/String;")
.removeMethod("getAutoincrementIncrement","()J")
.removeMethod("getGenerationClauseNode","()Lcom/foundationdb/sql/parser/GenerationClauseNode;")
.removeMethod("getDefaultNode","()Lcom/foundationdb/sql/parser/DefaultNode;");
finder.getNodes().get("com/foundationdb/sql/parser/DropTableNode")
.removeMethod("getDropBehavior","()I");
finder.getNodes().get("com/foundationdb/sql/parser/BooleanConstantNode")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getValue","()Ljava/lang/Object;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/NextSequenceNode")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;");
finder.getNodes().get("com/foundationdb/sql/parser/TableElementNode")
.removeMethod("getName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/RowsResultSetNode")
.removeMethod("getResultColumns","()Lcom/foundationdb/sql/parser/ResultColumnList;")
.removeMethod("getOrigTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getCorrelationName","()Ljava/lang/String;")
.removeMethod("getExposedName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/InListOperatorNode")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;");
finder.getNodes().get("com/foundationdb/sql/parser/CreateIndexNode")
.removeMethod("getIndexName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getProperties","()Ljava/util/Properties;")
.removeMethod("getJoinType","()Lcom/foundationdb/sql/parser/JoinNode$JoinType;");
finder.getNodes().get("com/foundationdb/sql/parser/UntypedNullConstantNode")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getValue","()Ljava/lang/Object;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;");
finder.getNodes().get("com/foundationdb/sql/parser/BetweenOperatorNode")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;");
finder.getNodes().get("com/foundationdb/sql/parser/IsNode")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getMethodName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getOperator","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;");
finder.getNodes().get("com/foundationdb/sql/parser/DropSchemaNode")
.removeMethod("getObjectName","()Lcom/foundationdb/sql/parser/TableName;");
finder.getNodes().get("com/foundationdb/sql/parser/UnionNode")
.removeMethod("getCorrelationName","()Ljava/lang/String;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getLeftmostResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getResultColumns","()Lcom/foundationdb/sql/parser/ResultColumnList;")
.removeMethod("getLeftmostResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getOrigTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getExposedName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/OrderByList")
.removeMethod("get","(I)Lcom/foundationdb/sql/parser/QueryTreeNode;")
.removeMethod("getOrderByColumn","(I)Lcom/foundationdb/sql/parser/OrderByColumn;");
finder.getNodes().get("com/foundationdb/sql/parser/FKConstraintDefinitionNode")
.removeMethod("getVerifyType","()Lcom/foundationdb/sql/parser/ConstraintDefinitionNode$ConstraintType;")
.removeMethod("getProperties","()Ljava/util/Properties;");
finder.getNodes().get("com/foundationdb/sql/parser/AlterDropIndexNode")
.removeMethod("getName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/CreateSchemaNode")
.removeMethod("getDefaultCharacterAttributes","()Lcom/foundationdb/sql/types/CharacterTypeAttributes;")
.removeMethod("getObjectName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getAuthorizationID","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/CurrentDatetimeOperatorNode")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;");
finder.getNodes().get("com/foundationdb/sql/parser/IntersectOrExceptNode")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getCorrelationName","()Ljava/lang/String;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getOrigTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getLeftmostResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getResultColumns","()Lcom/foundationdb/sql/parser/ResultColumnList;")
.removeMethod("getOpType","()Lcom/foundationdb/sql/parser/IntersectOrExceptNode$OpType;")
.removeMethod("getLeftmostResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getExposedName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/IndexDefinitionNode")
.removeMethod("getIndexColumnList","()Lcom/foundationdb/sql/parser/IndexColumnList;")
.removeMethod("getStorageFormat","()Lcom/foundationdb/sql/parser/StorageFormatNode;");
finder.getNodes().get("com/foundationdb/sql/parser/CreateViewNode")
.removeMethod("getOrderByList","()Lcom/foundationdb/sql/parser/OrderByList;")
.removeMethod("getOffset","()Lcom/foundationdb/sql/parser/ValueNode;")
.removeMethod("getResultColumns","()Lcom/foundationdb/sql/parser/ResultColumnList;")
.removeMethod("getCheckOption","()I")
.removeMethod("getFetchFirst","()Lcom/foundationdb/sql/parser/ValueNode;")
.removeMethod("getQueryExpression","()Ljava/lang/String;")
.removeMethod("getParsedQueryExpression","()Lcom/foundationdb/sql/parser/ResultSetNode;");
finder.getNodes().get("com/foundationdb/sql/parser/AllResultColumn")
.removeMethod("getColumnPosition","()I")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getExpression","()Lcom/foundationdb/sql/parser/ValueNode;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getReference","()Lcom/foundationdb/sql/parser/ColumnReference;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getFullTableName","()Ljava/lang/String;")
.removeMethod("getVirtualColumnId","()I")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;");
finder.getNodes().get("com/foundationdb/sql/parser/GroupConcatNode")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getAggregateName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getOperand","()Lcom/foundationdb/sql/parser/ValueNode;")
.removeMethod("getOperator","()Ljava/lang/String;")
.removeMethod("getMethodName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;");
finder.getNodes().get("com/foundationdb/sql/parser/BinaryOperatorNode")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getOperator","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getSchemaName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/FromBaseTable")
.removeMethod("getIndexHints","()Lcom/foundationdb/sql/parser/IndexHintList;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getResultColumns","()Lcom/foundationdb/sql/parser/ResultColumnList;")
.removeMethod("getExposedName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/IsNullNode")
.removeMethod("getOperator","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getTableName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/InsertNode")
.removeMethod("getTargetProperties","()Ljava/util/Properties;");
finder.getNodes().get("com/foundationdb/sql/parser/AlterTableNode")
.removeField("defragment")
.removeField("purge")
.removeField("compressTable")
.removeField("truncateEndOfTable")
.removeField("behavior")
.removeField("sequential")
.removeMethod("getBehavior","()I")
.removeMethod("getChangeType","()I");
finder.getNodes().get("com/foundationdb/sql/parser/DefaultNode")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;");
finder.getNodes().get("com/foundationdb/sql/parser/StaticMethodCallNode")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getJSQLType","()Lcom/foundationdb/sql/types/JSQLType;")
.removeMethod("getJavaClassName","()Ljava/lang/String;")
.removeMethod("getJavaTypeName","()Ljava/lang/String;")
.removeMethod("getPrimitiveTypeName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/SpecialFunctionNode")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/SelectNode")
.removeMethod("getWindows","()Lcom/foundationdb/sql/parser/WindowList;")
.removeMethod("getCacheHint","()Ljava/lang/Boolean;");
finder.getNodes().get("com/foundationdb/sql/parser/TernaryOperatorNode")
.removeMethod("getOperator","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;");
finder.getNodes().get("com/foundationdb/sql/parser/DropSequenceNode")
.removeMethod("getDropBehavior","()I");
finder.getNodes().get("com/foundationdb/sql/parser/AggregateNode")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getMethodName","()Ljava/lang/String;")
.removeMethod("getOperator","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/ConstraintDefinitionNode")
.removeMethod("getProperties","()Ljava/util/Properties;");
finder.getNodes().get("com/foundationdb/sql/parser/OrderByColumn")
.removeMethod("getColumnPosition","()I");
finder.getNodes().get("com/foundationdb/sql/parser/RenameNode")
.removeMethod("getNewObjectName","()Ljava/lang/String;")
.removeMethod("getOldObjectName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/DeleteNode")
.removeMethod("getTargetTableName","()Lcom/foundationdb/sql/parser/TableName;");
finder.getNodes().get("com/foundationdb/sql/parser/RowConstructorNode")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getDepth","()I")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getTableName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/NumericConstantNode")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;");
finder.getNodes().get("com/foundationdb/sql/parser/UnaryOperatorNode")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getOperator","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/SQLToJavaValueNode")
.removeMethod("getJSQLType","()Lcom/foundationdb/sql/types/JSQLType;")
.removeMethod("getJavaTypeName","()Ljava/lang/String;")
.removeMethod("getPrimitiveTypeName","()Ljava/lang/String;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;");
finder.getNodes().get("com/foundationdb/sql/parser/JavaToSQLValueNode")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getSchemaName","()Ljava/lang/String;");
finder.getNodes().get("com/foundationdb/sql/parser/GroupByList")
.removeMethod("get","(I)Lcom/foundationdb/sql/parser/QueryTreeNode;")
.removeMethod("getGroupByColumn","(I)Lcom/foundationdb/sql/parser/GroupByColumn;");
finder.getNodes().get("com/foundationdb/sql/parser/FromSubquery")
.removeMethod("getCorrelationName","()Ljava/lang/String;")
.removeMethod("getTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getOrigTableName","()Lcom/foundationdb/sql/parser/TableName;");
finder.getNodes().get("com/foundationdb/sql/parser/JoinNode")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getLeftmostResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getOrigTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getCorrelationName","()Ljava/lang/String;")
.removeMethod("getExposedName","()Ljava/lang/String;")
.removeMethod("getLeftmostResultSet","()Lcom/foundationdb/sql/parser/ResultSetNode;")
.removeMethod("getTableName","()Lcom/foundationdb/sql/parser/TableName;")
.removeMethod("getResultColumns","()Lcom/foundationdb/sql/parser/ResultColumnList;");
finder.getNodes().get("com/foundationdb/sql/parser/ExplicitCollateNode")
.removeMethod("getType","()Lcom/foundationdb/sql/types/DataTypeDescriptor;")
.removeMethod("getSourceResultColumn","()Lcom/foundationdb/sql/parser/ResultColumn;")
.removeMethod("getColumnName","()Ljava/lang/String;")
.removeMethod("getSchemaName","()Ljava/lang/String;")
.removeMethod("getTableName","()Ljava/lang/String;")
.removeMethod("getTypeId","()Lcom/foundationdb/sql/types/TypeId;");
}
@Test
public void testAllReferencedClassesHaveReferencedGetters() throws Exception {
UsageClassVisitor checker = new UsageClassVisitor(finder.getNodes());
int fullyUsed = 0;
int total = 0;
Iterator<Map.Entry<String, NodeClass>> iterator = finder.getNodes().entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, NodeClass> nodeClass = iterator.next();
if (nodeClass.getValue().fullyUsed()) {
fullyUsed++;
iterator.remove();
}
total++;
}
assertThat(fullyUsed, lessThan(total));
for (String usageClass : sqlLayerClassPaths) {
try {
ClassReader reader = new ClassReader(new FileInputStream(usageClass));
reader.accept(checker, 0);
} catch (IOException e) {
throw new Exception("Failed to check against class", e);
}
}
StringBuilder sql = new StringBuilder("Sql\n");
StringBuilder csv = new StringBuilder("\n");
logHeaderInfo(sql, csv);
Collection<String> unused = new TreeSet<>();
for (NodeClass nodeClass : finder.getNodes().values()) {
if (nodeClass.isReferenced && nodeClass.isConcrete()) {
String name = nodeClass.getJavaName();
codeLogger.debug("finder.getNodes().get(\"{}\")",nodeClass.getName());
for (NodeClass.Field field : nodeClass.fields) {
if (!field.isReferenced) {
codeLogger.debug(".removeField(\"{}\")", field.name);
unused.add(name + "." + field.name);
}
logMember(name, field, sql, csv);
}
for (NodeClass.Method method : nodeClass.methods) {
if (!method.isReferenced) {
codeLogger.debug(".removeMethod(\"{}\",\"{}\")",method.name, method.descriptor);
unused.add(method.getJavaString(name) + " -- " + method.descriptor);
}
logMember(name, method, sql, csv);
}
codeLogger.debug(";");
}
}
if (sqlLogger.isDebugEnabled()) {
sqlLogger.debug(sql.toString());
}
if (csvLogger.isDebugEnabled()) {
csvLogger.debug(csv.toString());
}
assertThat(unused, empty());
}
public void logHeaderInfo(StringBuilder sql, StringBuilder csv) {
if (csvLogger.isDebugEnabled()) {
csv.append("DeclaredType,SubType,PropertyType,IsReferenced,Name,Java Declaration,Code To Remove\n");
}
if (sqlLogger.isDebugEnabled()) {
// helpful sql:
// SELECT declaredtype,name,cnr,cr FROM
// (SELECT declaredtype,name,count(*) as cr FROM methods
// WHERE IsReferenced IS TRUE GROUP BY declaredtype,name) AS ReferencedCounts
// RIGHT OUTER JOIN
// (SELECT declaredtype,name,COUNT(*) as cnr FROM methods
// WHERE IsReferenced IS FALSE GROUP BY declaredtype,name) AS UnReferencedCounts
// USING(declaredtype,name) ORDER BY cnr;
//
// SELECT declaredtype,name,java,removal FROM methods WHERE declaredtype = subtype AND isreferenced IS FALSE;
sql.append("CREATE TABLE fields (DeclaredType VARCHAR(100),SubType VARCHAR(100)," +
"PropertyType VARCHAR(25),IsReferenced BOOLEAN,Name VARCHAR(100));\n");
sql.append("CREATE TABLE methods (DeclaredType VARCHAR(100),SubType VARCHAR(100)," +
"PropertyType VARCHAR(25),IsReferenced BOOLEAN,Name VARCHAR(100)," +
"Java VARCHAR(200),Removal VARCHAR(200));\n");
}
}
public void logMember(String typeName, NodeClass.Member member, StringBuilder sql, StringBuilder csv) {
if (csvLogger.isDebugEnabled()) {
csv.append(member.csvString(typeName));
csv.append("\n");
}
if (sqlLogger.isDebugEnabled()) {
sql.append(member.sqlInsertStatement("methods", typeName));
sql.append("\n");
}
}
/**
* Finds all fields and methods adding them to a list of nodes
*/
public static class PropertyFinder extends ClassVisitor {
private Map<String, NodeClass> nodes;
private NodeClass currentClass;
public PropertyFinder() {
super(Opcodes.ASM5);
nodes = new HashMap<>();
}
public Map<String, NodeClass> getNodes() {
return nodes;
}
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
currentClass = new NodeClass(name, superName,
(access & Opcodes.ACC_ABSTRACT) > 0, (access & Opcodes.ACC_INTERFACE) > 0);
nodes.put(name, currentClass);
}
@Override
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
currentClass.addField(access, name);
return null;
}
@Override
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
currentClass.addMethod(access, name, desc);
return null;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
for (NodeClass node : nodes.values()) {
stringBuilder.append(node.toString());
stringBuilder.append("\n");
}
return stringBuilder.toString();
}
public void finalizeState() {
for (NodeClass nodeClass : nodes.values()) {
nodeClass.incorporateBaseClass(nodes);
}
}
}
/**
* Marks all nodes & there members as referenced, if they are.
*/
public static class UsageClassVisitor extends ClassVisitor{
private Map<String, NodeClass> nodes;
public UsageClassVisitor(Map<String, NodeClass> nodes) {
super(Opcodes.ASM5);
this.nodes = nodes;
}
private void markNodesAsVisited(String descriptor, int maxCount) {
Collection<String> referencedTypes = getParameterAndReturnTypes(descriptor);
assertThat(referencedTypes.size(), lessThanOrEqualTo(maxCount));
for (String referencedType : referencedTypes) {
if (nodes.containsKey(referencedType)) {
nodes.get(referencedType).reference();
}
}
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
if (nodes.containsKey(superName)) {
throw new RuntimeException("Class " + name + " extends " + superName);
}
}
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
markNodesAsVisited(desc, 1);
return null;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
markNodesAsVisited(desc, Integer.MAX_VALUE);
return new UsageMethodVisitor();
}
private Collection<String> getParameterAndReturnTypes(String descriptor) {
Set<String> types = new HashSet<>();
Type type = Type.getType(descriptor);
types.add(NodeClass.typeToString(type.getReturnType()));
if (type.getSort() == Type.METHOD) {
for (Type argumentType : type.getArgumentTypes()) {
types.add(NodeClass.typeToString(argumentType));
}
}
return types;
}
private class UsageMethodVisitor extends MethodVisitor{
public UsageMethodVisitor() {
super(Opcodes.ASM5);
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
throw new RuntimeException("Unexpected Dynamic Instruction " + name);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (nodes.containsKey(owner)) {
nodes.get(owner).usedField(name);
}
}
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
markNodesAsVisited(desc, 1);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (nodes.containsKey(owner)) {
nodes.get(owner).referenceMethod(name, desc);
}
}
@Override
@Deprecated // just like parent method
@SuppressWarnings("deprecated")
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
this.visitMethodInsn(opcode, owner, name, desc, false);
}
@Override
public void visitTypeInsn(int opcode, String type) {
if (nodes.containsKey(type)) {
nodes.get(type).reference();
}
}
}
}
public static class NodeClass {
public String name;
public String baseClassName;
public NodeClass baseClass;
public Set<Field> fields;
private Set<Method> methods;
private boolean isAbstract;
private boolean isInterface;
private boolean isReferenced;
public NodeClass(String name, String baseClassName, boolean isAbstract, boolean isInterface) {
this.name = name;
this.baseClassName = baseClassName;
this.isAbstract = isAbstract;
this.isInterface = isInterface;
fields = new HashSet<>();
methods = new HashSet<>();
}
public String getName() {
return name;
}
public String getJavaName() {
return name.replaceAll("/", ".");
}
public void addField(int access, String fieldName) {
if ((access & Opcodes.ACC_PUBLIC) > 0) {
if ((access & Opcodes.ACC_STATIC) == 0) {
fields.add(new Field(this.name, fieldName));
if (logger.isWarnEnabled()) {
logger.warn(getJavaName() + " has a public field: " + fieldName);
}
}
}
}
public Method addMethod(int access, String name, String descriptor) {
if ((access & Opcodes.ACC_PUBLIC) > 0) {
if ((access & Opcodes.ACC_STATIC) == 0) {
if (name.startsWith("get")) {
Method member = new Method(this.name, name, descriptor);
methods.add(member);
return member;
}
}
}
return null;
}
public void incorporateBaseClass(Map<String, NodeClass> nodeClasses) {
if (baseClass == null) {
if (nodeClasses.containsKey(baseClassName)) {
baseClass = nodeClasses.get(baseClassName);
baseClass.incorporateBaseClass(nodeClasses);
for (Field field : baseClass.fields){
fields.add(new Field(field));
}
for (Method method : baseClass.methods) {
methods.add(new Method(method));
}
}
}
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(getJavaName());
stringBuilder.append(": ");
for (Field field : fields) {
stringBuilder.append(field);
stringBuilder.append(", ");
}
for (Method member : methods) {
stringBuilder.append(member);
stringBuilder.append(", ");
}
return stringBuilder.toString();
}
public void referenceMethod(String name, String desc) {
if (name.startsWith("get")) {
for (Method method : methods) {
if (method.equals(name, desc)) {
method.reference();
}
}
}
}
public void usedField(String name) {
for (Field field : fields) {
if (field.name.equals(name)) {
field.reference();
}
}
}
public boolean fullyUsed() {
return methods.size() == 0 && fields.size() == 0;
}
public void reference() {
isReferenced = true;
}
public NodeClass removeField(String fieldName) {
Iterator<Field> iterator = fields.iterator();
while (iterator.hasNext()) {
if (Objects.equals(iterator.next().name, fieldName)) {
iterator.remove();
break;
}
}
return this;
}
public NodeClass removeMethod(String name, String descriptor) {
Iterator<Method> iterator = methods.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals(name, descriptor)) {
iterator.remove();
break;
}
}
return this;
}
public boolean isConcrete() {
return !isAbstract && !isInterface;
}
public static String typeToString(Type type) {
String className = type.getClassName();
if (type.getSort() == Type.OBJECT) {
className = className.substring(className.lastIndexOf('.')+1);
}
return className;
}
public static class Method extends Member {
private final String descriptor;
public Method(String className, String name, String descriptor) {
super(className, name);
this.descriptor = descriptor;
}
public Method(Method method) {
super(method);
this.descriptor = method.descriptor;
}
@Override
public String toString() {
return name + " " + descriptor;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Method) {
Method method = (Method) obj;
return method.name.equals(this.name) && method.descriptor.equals(this.descriptor);
}
return false;
}
public boolean equals(String name, String descriptor) {
return this.name.equals(name) && this.descriptor.equals(descriptor);
}
public String getJavaString(String className) {
StringBuilder stringBuilder = new StringBuilder();
Type type = Type.getType(descriptor);
stringBuilder.append(typeToString(type.getReturnType()));
stringBuilder.append(" ");
if (className != null) {
stringBuilder.append(className);
stringBuilder.append(".");
}
stringBuilder.append(name);
stringBuilder.append("(");
for (Type argumentType : type.getArgumentTypes()) {
stringBuilder.append(typeToString(argumentType));
stringBuilder.append(", ");
}
if (type.getArgumentTypes().length > 0) {
stringBuilder.delete(stringBuilder.length() - 2, stringBuilder.length() - 1);
}
stringBuilder.append(")");
return stringBuilder.toString();
}
@Override
public String csvString(String forType) {
return super.csvString(forType) + ",\"" + getJavaString(null) + "\",\""
+ ".removeMethod(\"\"" + name + "\"\", \"\"" + descriptor + ")\"";
}
@Override
public String sqlInsertStatement(String table, String forType) {
return "INSERT INTO \"" + table +
"\" (" + sqlColumnNames() + ",Java,Removal) VALUES (" + sqlColumnValues(forType) + ",'" +
getJavaString(null) + "','" + ".removeMethod(\"" + name + "\", \"" + descriptor + "\")');";
}
@Override
protected String getPropertyType() {
return "Method";
}
}
public static class Field extends Member {
public Field(String className, String name) {
super(className, name);
}
@Override
public String sqlInsertStatement(String table, String forType) {
return "INSERT INTO \"" + table +
"\" (" + sqlColumnNames() + ") VALUES (" + sqlColumnValues(forType) + ");";
}
@Override
protected String getPropertyType() {
return "Field";
}
public Field(Field field) {
super(field);
}
@Override
public String toString() {
return name;
}
}
public static abstract class Member {
protected final String className;
protected final String name;
boolean isReferenced;
public Member(String className, String name) {
this.className = className;
this.name = name;
}
public Member(Member member) {
className = member.className;
name = member.name;
isReferenced = member.isReferenced;
}
public void reference() {
isReferenced = true;
}
public String csvString(String forType) {
return getClassName() + "," + forType + "," + getPropertyType() + "," + isReferenced + "," + name;
}
public abstract String sqlInsertStatement(String table, String forType);
protected String sqlColumnNames() {
return "DeclaredType,SubType,PropertyType,IsReferenced,Name";
}
protected String sqlColumnValues(String forType) {
return "'" + getClassName() + "','" + forType + "','" + getPropertyType() + "'," +
isReferenced + ",'" + name + "'";
}
protected abstract String getPropertyType();
public String getClassName() {
return className.replaceAll("/", ".");
}
}
}
}