Make behavior of mapping consistant between methods and fields, and handle conflicts between underscores and no underscores by picking the most exact match

This commit is contained in:
moparisthebest 2014-06-11 13:22:01 -04:00
parent f7b1a52ba1
commit 375f8b8413
17 changed files with 1282 additions and 12 deletions

3
.gitignore vendored
View File

@ -2,4 +2,5 @@
**.iml
**/build
**/target
**~
**~
**derby.log

View File

@ -10,6 +10,22 @@
</parent>
<artifactId>beehive-jdbc-mapper</artifactId>
<name>${project.artifactId}</name>
<properties>
<maven.test.skip>false</maven.test.skip>
<maven.test.failure.ignore>false</maven.test.failure.ignore>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>

View File

@ -19,7 +19,7 @@ public class QueryMapper implements Closeable {
method.invoke(null);
}catch(Throwable e){
// ignore
e.printStackTrace();
//e.printStackTrace();
}
}

View File

@ -341,23 +341,32 @@ public class RowToObjectMapper<T> extends RowMapper {
//System.out.printf("method: '%s', isSetterMethod: '%s'\n", m, isSetterMethod(m));
if (isSetterMethod(m)) {
String fieldName = m.getName().substring(3).toUpperCase();
//System.out.println("METHOD-fieldName: "+fieldName);
AccessibleObject field = mapFields.get(fieldName);
if (field == null) {
//System.out.println("METHOD-fieldName1: "+fieldName);
if (!mapFields.containsKey(fieldName)) {
fieldName = strippedKeys.get(fieldName);
if (fieldName == null)
continue;
field = mapFields.get(fieldName);
//System.out.println("METHOD-fieldName2: "+fieldName);
}
final AccessibleObject field = mapFields.get(fieldName);
// check for overloads
if (field == null) {
mapFields.put(fieldName, m);
} else {
throw new MapperException("Unable to choose between overloaded methods '" + m.getName()
+ "' and '"+((Method)field).getName()+"' for field '"+fieldName+"' on the " + _returnTypeClass.getName() + " class. Mapping is done using "
+ "a case insensitive comparison of SQL ResultSet columns to field "
+ "names and public setter methods on the return class. Columns are also "
+ "stripped of '_' and compared if no match is found with them.");
// fix for 'overloaded' methods when it comes to stripped keys, we want the exact match
final String thisName = m.getName().substring(3).toUpperCase();
final String previousName = ((Method) field).getName().substring(3).toUpperCase();
//System.out.printf("thisName: '%s', previousName: '%s', mapFields.containsKey(thisName): %b, strippedKeys.containsKey(previousName): %b\n", thisName, previousName, mapFields.containsKey(thisName), strippedKeys.containsKey(previousName));
if(mapFields.containsKey(thisName) && strippedKeys.containsKey(previousName)) {
mapFields.put(fieldName, m);
} else if (!mapFields.containsKey(previousName) || !strippedKeys.containsKey(thisName)) {
throw new MapperException("Unable to choose between overloaded methods '" + m.getName()
+ "' and '" + ((Method) field).getName() + "' for field '" + fieldName + "' on the '" + _returnTypeClass.getName() + "' class. Mapping is done using "
+ "a case insensitive comparison of SQL ResultSet columns to field "
+ "names and public setter methods on the return class. Columns are also "
+ "stripped of '_' and compared if no match is found with them.");
}
// then the 'overloaded' method is already correct
}
}
}
@ -377,9 +386,24 @@ public class RowToObjectMapper<T> extends RowMapper {
if (fieldName == null)
continue;
}
Object field = mapFields.get(fieldName);
final AccessibleObject field = mapFields.get(fieldName);
if (field == null) {
mapFields.put(fieldName, f);
} else if(field instanceof Field) {
// fix for 'overloaded' fields when it comes to stripped keys, we want the exact match
final String thisName = f.getName().toUpperCase();
final String previousName = ((Field) field).getName().toUpperCase();
//System.out.printf("thisName: '%s', previousName: '%s', mapFields.containsKey(thisName): %b, strippedKeys.containsKey(previousName): %b\n", thisName, previousName, mapFields.containsKey(thisName), strippedKeys.containsKey(previousName));
if(mapFields.containsKey(thisName) && strippedKeys.containsKey(previousName)) {
mapFields.put(fieldName, f);
} else if (!mapFields.containsKey(previousName) || !strippedKeys.containsKey(thisName)) {
throw new MapperException("Unable to choose between overloaded fields '" + f.getName()
+ "' and '" + ((Field) field).getName() + "' for field '" + fieldName + "' on the '" + _returnTypeClass.getName() + "' class. Mapping is done using "
+ "a case insensitive comparison of SQL ResultSet columns to field "
+ "names and public setter methods on the return class. Columns are also "
+ "stripped of '_' and compared if no match is found with them.");
}
// then the 'overloaded' field is already correct
}
}
}

View File

@ -0,0 +1,196 @@
package com.moparisthebest.jdbc;
import com.moparisthebest.jdbc.dto.*;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Date;
import static com.moparisthebest.jdbc.TryClose.tryClose;
/**
* Created by mopar on 6/10/14.
*/
public class QueryMapperTest {
private static Connection conn;
protected static QueryMapper qm;
protected static final Person fieldPerson1 = new FieldPerson(1, new Date(0), "First", "Person");
protected static final Boss fieldBoss1 = new FieldBoss(2, new Date(0), "Second", "Person", "Finance", "Second");
protected static final Boss fieldBoss2 = new FieldBoss(3, new Date(0), "Third", "Person", "Finance", null);
protected static final Boss fieldBoss3 = new FieldBoss(4, new Date(0), null, "Person", "Finance", "Fourth");
protected static final Person setPerson1 = new SetPerson(fieldPerson1);
protected static final Boss setBoss1 = new SetBoss(fieldBoss1);
protected static final Boss setBoss2 = new SetBoss(fieldBoss2);
protected static final Boss setBoss3 = new SetBoss(fieldBoss3);
protected static final Person reverseFieldPerson1 = new ReverseFieldPerson(fieldPerson1);
protected static final Boss reverseFieldBoss1 = new ReverseFieldBoss(fieldBoss1);
protected static final Boss reverseFieldBoss2 = new ReverseFieldBoss(fieldBoss2);
protected static final Boss reverseFieldBoss3 = new ReverseFieldBoss(fieldBoss3);
protected static final Person reverseSetPerson1 = new ReverseSetPerson(fieldPerson1);
protected static final Boss reverseSetBoss1 = new ReverseSetBoss(fieldBoss1);
protected static final Boss reverseSetBoss2 = new ReverseSetBoss(fieldBoss2);
protected static final Boss reverseSetBoss3 = new ReverseSetBoss(fieldBoss3);
protected static final String personRegular = "SELECT * FROM person WHERE person_no = ?";
protected static final String bossRegularAndUnderscore = "SELECT p.person_no, p.first_name AS firstName, p.last_name, p.birth_date, b.department, p.first_name " +
"FROM person p " +
"JOIN boss b ON p.person_no = b.person_no " +
"WHERE p.person_no = ?";
protected static final String bossRegularAndUnderscoreReverse = "SELECT p.person_no, p.first_name, p.last_name, p.birth_date, b.department, p.first_name AS firstName " +
"FROM person p " +
"JOIN boss b ON p.person_no = b.person_no " +
"WHERE p.person_no = ?";
protected static final String bossRegular = "SELECT p.person_no, p.first_name AS firstName, p.last_name, p.birth_date, b.department " +
"FROM person p " +
"JOIN boss b ON p.person_no = b.person_no " +
"WHERE p.person_no = ?";
protected static final String bossUnderscore = "SELECT p.person_no, p.first_name, p.last_name, p.birth_date, b.department " +
"FROM person p " +
"JOIN boss b ON p.person_no = b.person_no " +
"WHERE p.person_no = ?";
@BeforeClass
public static void setUp() throws Throwable {
Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
conn = DriverManager.getConnection("jdbc:derby:memory:derbyDB;create=true");
qm = new QueryMapper(conn);
qm.executeUpdate("CREATE TABLE person (person_no NUMERIC, first_name VARCHAR(40), last_name VARCHAR(40), birth_date TIMESTAMP)");
qm.executeUpdate("CREATE TABLE boss (person_no NUMERIC, department VARCHAR(40))");
for (final Person person : new Person[]{fieldPerson1})
qm.executeUpdate("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES (?, ?, ?, ?)", person.getPersonNo(), person.getBirthDate(), person.getLastName(), person.getFirstName());
for (final Boss boss : new Boss[]{fieldBoss1, fieldBoss2, fieldBoss3}) {
qm.executeUpdate("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES (?, ?, ?, ?)", boss.getPersonNo(), boss.getBirthDate(), boss.getLastName(), boss.getFirstName() == null ? boss.getFirst_name() : boss.getFirstName());
qm.executeUpdate("INSERT INTO boss (person_no, department) VALUES (?, ?)", boss.getPersonNo(), boss.getDepartment());
}
}
@AfterClass
public static void tearDown() throws Throwable {
tryClose(qm);
tryClose(conn);
}
// fields
@Test
public void testFieldRegularPerson() throws Throwable {
testPerson(fieldPerson1, personRegular);
}
@Test
public void testFieldRegularAndUnderscore() throws Throwable {
testPerson(fieldBoss1, bossRegularAndUnderscore);
}
@Test
public void testFieldRegularAndUnderscoreReverse() throws Throwable {
testPerson(fieldBoss1, bossRegularAndUnderscoreReverse);
}
@Test
public void testFieldRegular() throws Throwable {
testPerson(fieldBoss2, bossRegular);
}
@Test
public void testFieldUnderscore() throws Throwable {
testPerson(fieldBoss3, bossUnderscore);
}
// sets
@Test
public void testSetRegularPerson() throws Throwable {
testPerson(setPerson1, personRegular);
}
@Test
public void testSetRegularAndUnderscore() throws Throwable {
testPerson(setBoss1, bossRegularAndUnderscore);
}
@Test
public void testSetRegularAndUnderscoreReverse() throws Throwable {
testPerson(setBoss1, bossRegularAndUnderscoreReverse);
}
@Test
public void testSetRegular() throws Throwable {
testPerson(setBoss2, bossRegular);
}
@Test
public void testSetUnderscore() throws Throwable {
testPerson(setBoss3, bossUnderscore);
}
// reverse fields
@Test
public void testReverseFieldRegularPerson() throws Throwable {
testPerson(reverseFieldPerson1, personRegular);
}
@Test
public void testReverseFieldRegularAndUnderscore() throws Throwable {
testPerson(reverseFieldBoss1, bossRegularAndUnderscore);
}
@Test
public void testReverseFieldRegularAndUnderscoreReverse() throws Throwable {
testPerson(reverseFieldBoss1, bossRegularAndUnderscoreReverse);
}
@Test
public void testReverseFieldRegular() throws Throwable {
testPerson(reverseFieldBoss3, bossRegular);
}
@Test
public void testReverseFieldUnderscore() throws Throwable {
testPerson(reverseFieldBoss2, bossUnderscore);
}
// reverse sets
@Test
public void testReverseSetRegularPerson() throws Throwable {
testPerson(reverseSetPerson1, personRegular);
}
@Test
public void testReverseSetRegularAndUnderscore() throws Throwable {
testPerson(reverseSetBoss1, bossRegularAndUnderscore);
}
@Test
public void testReverseSetRegularAndUnderscoreReverse() throws Throwable {
testPerson(reverseSetBoss1, bossRegularAndUnderscoreReverse);
}
@Test
public void testReverseSetRegular() throws Throwable {
testPerson(reverseSetBoss3, bossRegular);
}
@Test
public void testReverseSetUnderscore() throws Throwable {
testPerson(reverseSetBoss2, bossUnderscore);
}
private static void testPerson(final Person expected, final String query) throws Throwable {
final Person actual = qm.toObject(query, expected.getClass(), expected.getPersonNo());
//System.out.println("expected: " + expected);
//System.out.println("actual: " + actual);
Assert.assertEquals(expected, actual);
}
}

View File

@ -0,0 +1,488 @@
package com.moparisthebest.jdbc;
/*
Derby - Class SimpleApp
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.
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Properties;
/**
* <p>
* This sample program is a minimal Java application showing JDBC access to a
* Derby database.</p>
* <p>
* Instructions for how to run this program are
* given in <A HREF=example.html>example.html</A>, by default located in the
* same directory as this source file ($DERBY_HOME/demo/programs/simple/).</p>
* <p>
* Derby applications can run against Derby running in an embedded
* or a client/server framework.</p>
* <p>
* When Derby runs in an embedded framework, the JDBC application and Derby
* run in the same Java Virtual Machine (JVM). The application
* starts up the Derby engine.</p>
* <p>
* When Derby runs in a client/server framework, the application runs in a
* different JVM from Derby. The application only needs to load the client
* driver, and the connectivity framework (in this case the Derby Network
* Server) provides network connections.</p>
*/
public class SimpleApp
{
/* the default framework is embedded*/
private String framework = "embedded";
private String driver = "org.apache.derby.jdbc.EmbeddedDriver";
private String protocol = "jdbc:derby:";
/**
* <p>
* Starts the demo by creating a new instance of this class and running
* the <code>go()</code> method.</p>
* <p>
* When you run this application, you may give one of the following
* arguments:
* <ul>
<li><code>embedded</code> - default, if none specified. Will use
* Derby's embedded driver. This driver is included in the derby.jar
* file.</li>
* <li><code>derbyclient</code> - will use the Derby client driver to
* access the Derby Network Server. This driver is included in the
* derbyclient.jar file.</li>
* </ul>
* <p>
* When you are using a client/server framework, the network server must
* already be running when trying to obtain client connections to Derby.
* This demo program will will try to connect to a network server on this
* host (the localhost), see the <code>protocol</code> instance variable.
* </p>
* <p>
* When running this demo, you must include the correct driver in the
* classpath of the JVM. See <a href="example.html">example.html</a> for
* details.
* </p>
* @param args This program accepts one optional argument specifying which
* connection framework (JDBC driver) to use (see above). The default
* is to use the embedded JDBC driver.
*/
public static void main(String[] args)
{
new SimpleApp().go(args);
System.out.println("SimpleApp finished");
}
/**
* <p>
* Starts the actual demo activities. This includes loading the correct
* JDBC driver, creating a database by making a connection to Derby,
* creating a table in the database, and inserting, updating and retrieving
* some data. Some of the retrieved data is then verified (compared) against
* the expected results. Finally, the table is deleted and, if the embedded
* framework is used, the database is shut down.</p>
* <p>
* Generally, when using a client/server framework, other clients may be
* (or want to be) connected to the database, so you should be careful about
* doing shutdown unless you know that no one else needs to access the
* database until it is rebooted. That is why this demo will not shut down
* the database unless it is running Derby embedded.</p>
*
* @param args - Optional argument specifying which framework or JDBC driver
* to use to connect to Derby. Default is the embedded framework,
* see the <code>main()</code> method for details.
* @see #main(String[])
*/
void go(String[] args)
{
/* parse the arguments to determine which framework is desired*/
parseArguments(args);
System.out.println("SimpleApp starting in " + framework + " mode");
/* load the desired JDBC driver */
loadDriver();
/* We will be using Statement and PreparedStatement objects for
* executing SQL. These objects, as well as Connections and ResultSets,
* are resources that should be released explicitly after use, hence
* the try-catch-finally pattern used below.
* We are storing the Statement and Prepared statement object references
* in an array list for convenience.
*/
Connection conn = null;
/* This ArrayList usage may cause a warning when compiling this class
* with a compiler for J2SE 5.0 or newer. We are not using generics
* because we want the source to support J2SE 1.4.2 environments. */
ArrayList statements = new ArrayList(); // list of Statements, PreparedStatements
PreparedStatement psInsert = null;
PreparedStatement psUpdate = null;
Statement s = null;
ResultSet rs = null;
try
{
Properties props = new Properties(); // connection properties
// providing a user name and password is optional in the embedded
// and derbyclient frameworks
props.put("user", "user1");
props.put("password", "user1");
/* By default, the schema APP will be used when no username is
* provided.
* Otherwise, the schema name is the same as the user name (in this
* case "user1" or USER1.)
*
* Note that user authentication is off by default, meaning that any
* user can connect to your database using any password. To enable
* authentication, see the Derby Developer's Guide.
*/
String dbName = "derbyDB"; // the name of the database
/*
* This connection specifies create=true in the connection URL to
* cause the database to be created when connecting for the first
* time. To remove the database, remove the directory derbyDB (the
* same as the database name) and its contents.
*
* The directory derbyDB will be created under the directory that
* the system property derby.system.home points to, or the current
* directory (user.dir) if derby.system.home is not set.
*/
conn = DriverManager.getConnection(protocol + dbName
+ ";create=true", props);
System.out.println("Connected to and created database " + dbName);
// We want to control transactions manually. Autocommit is on by
// default in JDBC.
conn.setAutoCommit(false);
/* Creating a statement object that we can use for running various
* SQL statements commands against the database.*/
s = conn.createStatement();
statements.add(s);
// We create a table...
s.execute("create table location(num int, addr varchar(40))");
System.out.println("Created table location");
// and add a few rows...
/* It is recommended to use PreparedStatements when you are
* repeating execution of an SQL statement. PreparedStatements also
* allows you to parameterize variables. By using PreparedStatements
* you may increase performance (because the Derby engine does not
* have to recompile the SQL statement each time it is executed) and
* improve security (because of Java type checking).
*/
// parameter 1 is num (int), parameter 2 is addr (varchar)
psInsert = conn.prepareStatement(
"insert into location values (?, ?)");
statements.add(psInsert);
psInsert.setInt(1, 1956);
psInsert.setString(2, "Webster St.");
psInsert.executeUpdate();
System.out.println("Inserted 1956 Webster");
psInsert.setInt(1, 1910);
psInsert.setString(2, "Union St.");
psInsert.executeUpdate();
System.out.println("Inserted 1910 Union");
// Let's update some rows as well...
// parameter 1 and 3 are num (int), parameter 2 is addr (varchar)
psUpdate = conn.prepareStatement(
"update location set num=?, addr=? where num=?");
statements.add(psUpdate);
psUpdate.setInt(1, 180);
psUpdate.setString(2, "Grand Ave.");
psUpdate.setInt(3, 1956);
psUpdate.executeUpdate();
System.out.println("Updated 1956 Webster to 180 Grand");
psUpdate.setInt(1, 300);
psUpdate.setString(2, "Lakeshore Ave.");
psUpdate.setInt(3, 180);
psUpdate.executeUpdate();
System.out.println("Updated 180 Grand to 300 Lakeshore");
/*
We select the rows and verify the results.
*/
rs = s.executeQuery(
"SELECT num, addr FROM location ORDER BY num");
/* we expect the first returned column to be an integer (num),
* and second to be a String (addr). Rows are sorted by street
* number (num).
*
* Normally, it is best to use a pattern of
* while(rs.next()) {
* // do something with the result set
* }
* to process all returned rows, but we are only expecting two rows
* this time, and want the verification code to be easy to
* comprehend, so we use a different pattern.
*/
int number; // street number retrieved from the database
boolean failure = false;
if (!rs.next())
{
failure = true;
reportFailure("No rows in ResultSet");
}
if ((number = rs.getInt(1)) != 300)
{
failure = true;
reportFailure(
"Wrong row returned, expected num=300, got " + number);
}
if (!rs.next())
{
failure = true;
reportFailure("Too few rows");
}
if ((number = rs.getInt(1)) != 1910)
{
failure = true;
reportFailure(
"Wrong row returned, expected num=1910, got " + number);
}
if (rs.next())
{
failure = true;
reportFailure("Too many rows");
}
if (!failure) {
System.out.println("Verified the rows");
}
// delete the table
s.execute("drop table location");
System.out.println("Dropped table location");
/*
We commit the transaction. Any changes will be persisted to
the database now.
*/
conn.commit();
System.out.println("Committed the transaction");
/*
* In embedded mode, an application should shut down the database.
* If the application fails to shut down the database,
* Derby will not perform a checkpoint when the JVM shuts down.
* This means that it will take longer to boot (connect to) the
* database the next time, because Derby needs to perform a recovery
* operation.
*
* It is also possible to shut down the Derby system/engine, which
* automatically shuts down all booted databases.
*
* Explicitly shutting down the database or the Derby engine with
* the connection URL is preferred. This style of shutdown will
* always throw an SQLException.
*
* Not shutting down when in a client environment, see method
* Javadoc.
*/
if (framework.equals("embedded"))
{
try
{
// the shutdown=true attribute shuts down Derby
DriverManager.getConnection("jdbc:derby:;shutdown=true");
// To shut down a specific database only, but keep the
// engine running (for example for connecting to other
// databases), specify a database in the connection URL:
//DriverManager.getConnection("jdbc:derby:" + dbName + ";shutdown=true");
}
catch (SQLException se)
{
if (( (se.getErrorCode() == 50000)
&& ("XJ015".equals(se.getSQLState()) ))) {
// we got the expected exception
System.out.println("Derby shut down normally");
// Note that for single database shutdown, the expected
// SQL state is "08006", and the error code is 45000.
} else {
// if the error code or SQLState is different, we have
// an unexpected exception (shutdown failed)
System.err.println("Derby did not shut down normally");
printSQLException(se);
}
}
}
}
catch (SQLException sqle)
{
printSQLException(sqle);
} finally {
// release all open resources to avoid unnecessary memory usage
// ResultSet
try {
if (rs != null) {
rs.close();
rs = null;
}
} catch (SQLException sqle) {
printSQLException(sqle);
}
// Statements and PreparedStatements
int i = 0;
while (!statements.isEmpty()) {
// PreparedStatement extend Statement
Statement st = (Statement)statements.remove(i);
try {
if (st != null) {
st.close();
st = null;
}
} catch (SQLException sqle) {
printSQLException(sqle);
}
}
//Connection
try {
if (conn != null) {
conn.close();
conn = null;
}
} catch (SQLException sqle) {
printSQLException(sqle);
}
}
}
/**
* Loads the appropriate JDBC driver for this environment/framework. For
* example, if we are in an embedded environment, we load Derby's
* embedded Driver, <code>org.apache.derby.jdbc.EmbeddedDriver</code>.
*/
private void loadDriver() {
/*
* The JDBC driver is loaded by loading its class.
* If you are using JDBC 4.0 (Java SE 6) or newer, JDBC drivers may
* be automatically loaded, making this code optional.
*
* In an embedded environment, this will also start up the Derby
* engine (though not any databases), since it is not already
* running. In a client environment, the Derby engine is being run
* by the network server framework.
*
* In an embedded environment, any static Derby system properties
* must be set before loading the driver to take effect.
*/
try {
Class.forName(driver).newInstance();
System.out.println("Loaded the appropriate driver");
} catch (ClassNotFoundException cnfe) {
System.err.println("\nUnable to load the JDBC driver " + driver);
System.err.println("Please check your CLASSPATH.");
cnfe.printStackTrace(System.err);
} catch (InstantiationException ie) {
System.err.println(
"\nUnable to instantiate the JDBC driver " + driver);
ie.printStackTrace(System.err);
} catch (IllegalAccessException iae) {
System.err.println(
"\nNot allowed to access the JDBC driver " + driver);
iae.printStackTrace(System.err);
}
}
/**
* Reports a data verification failure to System.err with the given message.
*
* @param message A message describing what failed.
*/
private void reportFailure(String message) {
System.err.println("\nData verification failed:");
System.err.println('\t' + message);
}
/**
* Prints details of an SQLException chain to <code>System.err</code>.
* Details included are SQL State, Error code, Exception message.
*
* @param e the SQLException from which to print details.
*/
public static void printSQLException(SQLException e)
{
// Unwraps the entire exception chain to unveil the real cause of the
// Exception.
while (e != null)
{
System.err.println("\n----- SQLException -----");
System.err.println(" SQL State: " + e.getSQLState());
System.err.println(" Error Code: " + e.getErrorCode());
System.err.println(" Message: " + e.getMessage());
// for stack traces, refer to derby.log or uncomment this:
//e.printStackTrace(System.err);
e = e.getNextException();
}
}
/**
* Parses the arguments given and sets the values of this class' instance
* variables accordingly - that is which framework to use, the name of the
* JDBC driver class, and which connection protocol protocol to use. The
* protocol should be used as part of the JDBC URL when connecting to Derby.
* <p>
* If the argument is "embedded" or invalid, this method will not change
* anything, meaning that the default values will be used.</p>
* <p>
* @param args JDBC connection framework, either "embedded", "derbyclient".
* Only the first argument will be considered, the rest will be ignored.
*/
private void parseArguments(String[] args)
{
if (args.length > 0) {
if (args[0].equalsIgnoreCase("derbyclient"))
{
framework = "derbyclient";
driver = "org.apache.derby.jdbc.ClientDriver";
protocol = "jdbc:derby://localhost:1527/";
}
}
}
}

View File

@ -0,0 +1,12 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public interface Boss extends Person {
public String getDepartment();
public String getFirst_name();
}

View File

@ -0,0 +1,65 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public class FieldBoss extends FieldPerson implements Boss {
protected String department;
protected String first_name;
protected FieldBoss() {
super();
}
public FieldBoss(long personNo, Date birthDate, String firstName, String lastName, String department, String first_name) {
super(personNo, birthDate, firstName, lastName);
this.department = department;
this.first_name = first_name;
}
public FieldBoss(Boss boss) {
super(boss);
this.department = boss.getDepartment();
this.first_name = boss.getFirst_name();
}
public String getDepartment() {
return department;
}
public String getFirst_name() {
return first_name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FieldBoss)) return false;
if (!super.equals(o)) return false;
FieldBoss boss = (FieldBoss) o;
if (department != null ? !department.equals(boss.department) : boss.department != null) return false;
if (first_name != null ? !first_name.equals(boss.first_name) : boss.first_name != null) return false;
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (department != null ? department.hashCode() : 0);
result = 31 * result + (first_name != null ? first_name.hashCode() : 0);
return result;
}
@Override
public String toString() {
return this.getClass().getSimpleName()+"{" +
"department='" + department + '\'' +
", first_name='" + first_name + '\'' +
"} " + super.toString();
}
}

View File

@ -0,0 +1,81 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public class FieldPerson implements Person {
protected long personNo;
protected Date birthDate;
protected String firstName;
protected String lastName;
protected FieldPerson(){
}
public FieldPerson(long personNo, Date birthDate, String firstName, String lastName) {
this.personNo = personNo;
this.birthDate = birthDate;
this.lastName = lastName;
this.firstName = firstName;
}
public FieldPerson(Person person) {
this.personNo = person.getPersonNo();
this.birthDate = person.getBirthDate();
this.lastName = person.getLastName();
this.firstName = person.getFirstName();
}
public long getPersonNo() {
return personNo;
}
public Date getBirthDate() {
return birthDate;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FieldPerson)) return false;
FieldPerson person = (FieldPerson) o;
if (personNo != person.personNo) return false;
if (birthDate != null ? !birthDate.equals(person.birthDate) : person.birthDate != null) return false;
if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) return false;
if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (personNo ^ (personNo >>> 32));
result = 31 * result + (birthDate != null ? birthDate.hashCode() : 0);
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
return result;
}
@Override
public String toString() {
return this.getClass().getSimpleName()+"{" +
"personNo=" + personNo +
", birthDate=" + birthDate +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}

View File

@ -0,0 +1,17 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public interface Person {
public long getPersonNo();
public Date getBirthDate();
public String getFirstName();
public String getLastName();
}

View File

@ -0,0 +1,65 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public class ReverseFieldBoss extends ReverseFieldPerson implements Boss {
protected String department;
protected String firstName;
protected ReverseFieldBoss() {
super();
}
public ReverseFieldBoss(long personNo, Date birthDate, String firstName, String lastName, String department, String first_name) {
super(personNo, birthDate, firstName, lastName);
this.department = department;
this.firstName = first_name;
}
public ReverseFieldBoss(Boss boss) {
super(boss);
this.department = boss.getDepartment();
this.firstName = boss.getFirst_name();
}
public String getDepartment() {
return department;
}
public String getFirst_name() {
return firstName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ReverseFieldBoss)) return false;
if (!super.equals(o)) return false;
ReverseFieldBoss boss = (ReverseFieldBoss) o;
if (department != null ? !department.equals(boss.department) : boss.department != null) return false;
if (firstName != null ? !firstName.equals(boss.firstName) : boss.firstName != null) return false;
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (department != null ? department.hashCode() : 0);
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
return result;
}
@Override
public String toString() {
return this.getClass().getSimpleName()+"{" +
"department='" + department + '\'' +
", firstName='" + firstName + '\'' +
"} " + super.toString();
}
}

View File

@ -0,0 +1,81 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public class ReverseFieldPerson implements Person {
protected long personNo;
protected Date birthDate;
protected String first_name;
protected String lastName;
protected ReverseFieldPerson(){
}
public ReverseFieldPerson(long personNo, Date birthDate, String firstName, String lastName) {
this.personNo = personNo;
this.birthDate = birthDate;
this.lastName = lastName;
this.first_name = firstName;
}
public ReverseFieldPerson(Person person) {
this.personNo = person.getPersonNo();
this.birthDate = person.getBirthDate();
this.lastName = person.getLastName();
this.first_name = person.getFirstName();
}
public long getPersonNo() {
return personNo;
}
public Date getBirthDate() {
return birthDate;
}
public String getFirstName() {
return first_name;
}
public String getLastName() {
return lastName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ReverseFieldPerson)) return false;
ReverseFieldPerson person = (ReverseFieldPerson) o;
if (personNo != person.personNo) return false;
if (birthDate != null ? !birthDate.equals(person.birthDate) : person.birthDate != null) return false;
if (first_name != null ? !first_name.equals(person.first_name) : person.first_name != null) return false;
if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (personNo ^ (personNo >>> 32));
result = 31 * result + (birthDate != null ? birthDate.hashCode() : 0);
result = 31 * result + (first_name != null ? first_name.hashCode() : 0);
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
return result;
}
@Override
public String toString() {
return this.getClass().getSimpleName()+"{" +
"personNo=" + personNo +
", birthDate=" + birthDate +
", first_name='" + first_name + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}

View File

@ -0,0 +1,73 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public class ReverseSetBoss extends ReverseSetPerson implements Boss {
protected String department;
protected String firstName;
protected ReverseSetBoss() {
super();
}
public ReverseSetBoss(long personNo, Date birthDate, String firstName, String lastName, String department, String first_name) {
super(personNo, birthDate, firstName, lastName);
this.department = department;
this.firstName = first_name;
}
public ReverseSetBoss(Boss boss) {
super(boss);
this.department = boss.getDepartment();
this.firstName = boss.getFirst_name();
}
public String getDepartment() {
return department;
}
public String getFirst_name() {
return firstName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ReverseSetBoss)) return false;
if (!super.equals(o)) return false;
ReverseSetBoss boss = (ReverseSetBoss) o;
if (department != null ? !department.equals(boss.department) : boss.department != null) return false;
if (firstName != null ? !firstName.equals(boss.firstName) : boss.firstName != null) return false;
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (department != null ? department.hashCode() : 0);
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
return result;
}
@Override
public String toString() {
return this.getClass().getSimpleName()+"{" +
"department='" + department + '\'' +
", firstName='" + firstName + '\'' +
"} " + super.toString();
}
public void setDepartment(String department) {
this.department = department;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}

View File

@ -0,0 +1,36 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public class ReverseSetPerson extends ReverseFieldPerson {
protected ReverseSetPerson() {
}
public ReverseSetPerson(long personNo, Date birthDate, String firstName, String lastName) {
super(personNo, birthDate, firstName, lastName);
}
public ReverseSetPerson(Person person) {
super(person);
}
public void setPersonNo(long personNo) {
this.personNo = personNo;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}

View File

@ -0,0 +1,73 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public class SetBoss extends SetPerson implements Boss {
protected String department;
protected String first_name;
protected SetBoss() {
super();
}
public SetBoss(long personNo, Date birthDate, String firstName, String lastName, String department, String first_name) {
super(personNo, birthDate, firstName, lastName);
this.department = department;
this.first_name = first_name;
}
public SetBoss(Boss boss) {
super(boss);
this.department = boss.getDepartment();
this.first_name = boss.getFirst_name();
}
public String getDepartment() {
return department;
}
public String getFirst_name() {
return first_name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SetBoss)) return false;
if (!super.equals(o)) return false;
SetBoss boss = (SetBoss) o;
if (department != null ? !department.equals(boss.department) : boss.department != null) return false;
if (first_name != null ? !first_name.equals(boss.first_name) : boss.first_name != null) return false;
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (department != null ? department.hashCode() : 0);
result = 31 * result + (first_name != null ? first_name.hashCode() : 0);
return result;
}
@Override
public String toString() {
return this.getClass().getSimpleName()+"{" +
"department='" + department + '\'' +
", first_name='" + first_name + '\'' +
"} " + super.toString();
}
public void setDepartment(String department) {
this.department = department;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
}

View File

@ -0,0 +1,36 @@
package com.moparisthebest.jdbc.dto;
import java.util.Date;
/**
* Created by mopar on 6/10/14.
*/
public class SetPerson extends FieldPerson {
protected SetPerson() {
}
public SetPerson(long personNo, Date birthDate, String firstName, String lastName) {
super(personNo, birthDate, firstName, lastName);
}
public SetPerson(Person person) {
super(person);
}
public void setPersonNo(long personNo) {
this.personNo = personNo;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}

View File

@ -109,6 +109,12 @@
<artifactId>junit</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.10.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>