5
0
mirror of https://github.com/apache/sqoop.git synced 2025-05-04 21:00:57 +08:00

SQOOP-158. Additional methods for generated classes.

Adding setter-methods and a field-based equals-implementation to
the generated classes. These new methods enhance the usage of the
generated classes.

(Michael Häusler via ahmed)

From: Ahmed Radwan <ahmed@cloudera.com>

git-svn-id: https://svn.apache.org/repos/asf/incubator/sqoop/trunk@1150037 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andrew Bayer 2011-07-22 20:04:36 +00:00
parent dfd9021662
commit 0870f9499a
2 changed files with 139 additions and 8 deletions

View File

@ -426,13 +426,14 @@ private String rpcSetterForMaybeNull(String javaType, String outputObj,
} }
/** /**
* Generate a member field and getter method for each column. * Generate a member field, getter, setter and with method for each column.
* @param columnTypes - mapping from column names to sql types * @param columnTypes - mapping from column names to sql types
* @param colNames - ordered list of column names for table. * @param colNames - ordered list of column names for table
* @param className - name of the generated class
* @param sb - StringBuilder to append code to * @param sb - StringBuilder to append code to
*/ */
private void generateFields(Map<String, Integer> columnTypes, private void generateFields(Map<String, Integer> columnTypes,
String [] colNames, StringBuilder sb) { String [] colNames, String className, StringBuilder sb) {
for (String col : colNames) { for (String col : colNames) {
int sqlType = columnTypes.get(col); int sqlType = columnTypes.get(col);
@ -446,9 +447,51 @@ private void generateFields(Map<String, Integer> columnTypes,
sb.append(" public " + javaType + " get_" + col + "() {\n"); sb.append(" public " + javaType + " get_" + col + "() {\n");
sb.append(" return " + col + ";\n"); sb.append(" return " + col + ";\n");
sb.append(" }\n"); sb.append(" }\n");
sb.append(" public void set_" + col + "(" + javaType + " " + col
+ ") {\n");
sb.append(" this." + col + " = " + col + ";\n");
sb.append(" }\n");
sb.append(" public " + className + " with_" + col + "(" + javaType + " "
+ col + ") {\n");
sb.append(" this." + col + " = " + col + ";\n");
sb.append(" return this;\n");
sb.append(" }\n");
} }
} }
/**
* Generate an equals method that compares the fields for each column.
* @param columnTypes - mapping from column names to sql types
* @param colNames - ordered list of column names for table
* @param className - name of the generated class
* @param sb - StringBuilder to append code to
*/
private void generateEquals(Map<String, Integer> columnTypes,
String [] colNames, String className, StringBuilder sb) {
sb.append(" public boolean equals(Object o) {\n");
sb.append(" if (this == o) {\n");
sb.append(" return true;\n");
sb.append(" }\n");
sb.append(" if (!(o instanceof " + className + ")) {\n");
sb.append(" return false;\n");
sb.append(" }\n");
sb.append(" " + className + " that = (" + className + ") o;\n");
sb.append(" boolean equal = true;\n");
for (String col : colNames) {
int sqlType = columnTypes.get(col);
String javaType = connManager.toJavaType(sqlType);
if (null == javaType) {
LOG.error("Cannot resolve SQL type " + sqlType);
continue;
}
sb.append(" equal = equal && (this." + col + " == null ? that." + col
+ " == null : this." + col + ".equals(that." + col + "));\n");
}
sb.append(" return equal;\n");
sb.append(" }\n");
}
/** /**
* Generate the readFields() method used by the database. * Generate the readFields() method used by the database.
* @param columnTypes - mapping from column names to sql types * @param columnTypes - mapping from column names to sql types
@ -1180,7 +1223,8 @@ private StringBuilder generateClassForColumns(
sb.append( sb.append(
" public int getClassFormatVersion() { return PROTOCOL_VERSION; }\n"); " public int getClassFormatVersion() { return PROTOCOL_VERSION; }\n");
sb.append(" protected ResultSet __cur_result_set;\n"); sb.append(" protected ResultSet __cur_result_set;\n");
generateFields(columnTypes, colNames, sb); generateFields(columnTypes, colNames, className, sb);
generateEquals(columnTypes, colNames, className, sb);
generateDbRead(columnTypes, colNames, sb); generateDbRead(columnTypes, colNames, sb);
generateLoadLargeObjects(columnTypes, colNames, sb); generateLoadLargeObjects(columnTypes, colNames, sb);
generateDbWrite(columnTypes, dbWriteColNames, sb); generateDbWrite(columnTypes, dbWriteColNames, sb);

View File

@ -21,6 +21,8 @@
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection; import java.sql.Connection;
import java.sql.Statement; import java.sql.Statement;
import java.sql.SQLException; import java.sql.SQLException;
@ -41,6 +43,7 @@
import com.cloudera.sqoop.testutil.HsqldbTestServer; import com.cloudera.sqoop.testutil.HsqldbTestServer;
import com.cloudera.sqoop.testutil.ImportJobTestCase; import com.cloudera.sqoop.testutil.ImportJobTestCase;
import com.cloudera.sqoop.tool.ImportTool; import com.cloudera.sqoop.tool.ImportTool;
import com.cloudera.sqoop.util.ClassLoaderStack;
/** /**
* Test that the ClassWriter generates Java classes based on the given table, * Test that the ClassWriter generates Java classes based on the given table,
@ -118,8 +121,9 @@ public void tearDown() {
/** /**
* Run a test to verify that we can generate code and it emits the output * Run a test to verify that we can generate code and it emits the output
* files where we expect them. * files where we expect them.
* @return
*/ */
private void runGenerationTest(String [] argv, String classNameToCheck) { private File runGenerationTest(String [] argv, String classNameToCheck) {
File codeGenDirFile = new File(CODE_GEN_DIR); File codeGenDirFile = new File(CODE_GEN_DIR);
File classGenDirFile = new File(JAR_GEN_DIR); File classGenDirFile = new File(JAR_GEN_DIR);
@ -195,6 +199,7 @@ private void runGenerationTest(String [] argv, String classNameToCheck) {
+ ".class in jar file", foundCompiledClass); + ".class in jar file", foundCompiledClass);
LOG.debug("Found class in jar - test success!"); LOG.debug("Found class in jar - test success!");
return jarFile;
} }
/** /**
@ -334,5 +339,87 @@ public void testWeirdColumnNames() throws SQLException {
runGenerationTest(argv, OVERRIDE_PACKAGE_NAME + "." runGenerationTest(argv, OVERRIDE_PACKAGE_NAME + "."
+ HsqldbTestServer.getTableName()); + HsqldbTestServer.getTableName());
} }
}
/**
* Test the generated equals method.
* @throws IOException
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
@Test
public void testEqualsMethod() throws IOException, ClassNotFoundException,
InstantiationException, IllegalAccessException, NoSuchMethodException,
InvocationTargetException {
// Set the option strings in an "argv" to redirect our srcdir and bindir
String [] argv = {
"--bindir",
JAR_GEN_DIR,
"--outdir",
CODE_GEN_DIR,
"--class-name",
OVERRIDE_CLASS_AND_PACKAGE_NAME,
};
File ormJarFile = runGenerationTest(argv, OVERRIDE_CLASS_AND_PACKAGE_NAME);
ClassLoader prevClassLoader = ClassLoaderStack.addJarFile(
ormJarFile.getCanonicalPath(),
OVERRIDE_CLASS_AND_PACKAGE_NAME);
Class tableClass = Class.forName(
OVERRIDE_CLASS_AND_PACKAGE_NAME,
true,
Thread.currentThread().getContextClassLoader());
Method setterIntField1 =
tableClass.getMethod("set_INTFIELD1", Integer.class);
Method setterIntField2 =
tableClass.getMethod("set_INTFIELD2", Integer.class);
Method equalsImplementation = tableClass.getMethod("equals", Object.class);
Object instance1 = tableClass.newInstance();
Object instance2 = tableClass.newInstance();
// test reflexivity
assertTrue((Boolean) equalsImplementation.invoke(instance1, instance1));
// test equality for uninitialized fields
assertTrue((Boolean) equalsImplementation.invoke(instance1, instance2));
// test symmetry
assertTrue((Boolean) equalsImplementation.invoke(instance2, instance1));
// test reflexivity with initialized fields
setterIntField1.invoke(instance1, new Integer(1));
setterIntField2.invoke(instance1, new Integer(2));
assertTrue((Boolean) equalsImplementation.invoke(instance1, instance1));
// test difference in both fields
setterIntField1.invoke(instance2, new Integer(3));
setterIntField2.invoke(instance2, new Integer(4));
assertFalse((Boolean) equalsImplementation.invoke(instance1, instance2));
// test difference in second field
setterIntField1.invoke(instance2, new Integer(1));
setterIntField2.invoke(instance2, new Integer(3));
assertFalse((Boolean) equalsImplementation.invoke(instance1, instance2));
// test difference in first field
setterIntField1.invoke(instance2, new Integer(3));
setterIntField2.invoke(instance2, new Integer(2));
assertFalse((Boolean) equalsImplementation.invoke(instance1, instance2));
// test equality for initialized fields
setterIntField1.invoke(instance2, new Integer(1));
setterIntField2.invoke(instance2, new Integer(2));
assertTrue((Boolean) equalsImplementation.invoke(instance1, instance2));
if (null != prevClassLoader) {
ClassLoaderStack.setCurrentClassLoader(prevClassLoader);
}
}
}