diff --git a/.gitignore b/.gitignore index 2fd881c..7061017 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ **.iml **/build **/target -**~ \ No newline at end of file +**~ +**derby.log diff --git a/beehive-jdbc-mapper/pom.xml b/beehive-jdbc-mapper/pom.xml index fb295ef..56ccbe3 100644 --- a/beehive-jdbc-mapper/pom.xml +++ b/beehive-jdbc-mapper/pom.xml @@ -10,6 +10,22 @@ beehive-jdbc-mapper ${project.artifactId} + + false + false + + + + junit + junit + 4.11 + test + + + org.apache.derby + derby + + ${project.artifactId} diff --git a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java index fa4a51d..f4e492b 100644 --- a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java +++ b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java @@ -19,7 +19,7 @@ public class QueryMapper implements Closeable { method.invoke(null); }catch(Throwable e){ // ignore - e.printStackTrace(); + //e.printStackTrace(); } } diff --git a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java index 90e22d3..e48d70b 100644 --- a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java +++ b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java @@ -341,23 +341,32 @@ public class RowToObjectMapper 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 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 } } } diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java new file mode 100644 index 0000000..c4ae8fb --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java @@ -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); + } +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/SimpleApp.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/SimpleApp.java new file mode 100644 index 0000000..c9061d4 --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/SimpleApp.java @@ -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; + + +/** + *

+ * This sample program is a minimal Java application showing JDBC access to a + * Derby database.

+ *

+ * Instructions for how to run this program are + * given in example.html, by default located in the + * same directory as this source file ($DERBY_HOME/demo/programs/simple/).

+ *

+ * Derby applications can run against Derby running in an embedded + * or a client/server framework.

+ *

+ * 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.

+ *

+ * 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.

+ */ +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:"; + + /** + *

+ * Starts the demo by creating a new instance of this class and running + * the go() method.

+ *

+ * When you run this application, you may give one of the following + * arguments: + *

+ *

+ * 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 protocol instance variable. + *

+ *

+ * When running this demo, you must include the correct driver in the + * classpath of the JVM. See example.html for + * details. + *

+ * @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"); + } + + /** + *

+ * 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.

+ *

+ * 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.

+ * + * @param args - Optional argument specifying which framework or JDBC driver + * to use to connect to Derby. Default is the embedded framework, + * see the main() 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, org.apache.derby.jdbc.EmbeddedDriver. + */ + 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 System.err. + * 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. + *

+ * If the argument is "embedded" or invalid, this method will not change + * anything, meaning that the default values will be used.

+ *

+ * @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/"; + } + } + } +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/Boss.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/Boss.java new file mode 100644 index 0000000..38eecf4 --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/Boss.java @@ -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(); +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/FieldBoss.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/FieldBoss.java new file mode 100644 index 0000000..727d863 --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/FieldBoss.java @@ -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(); + } +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/FieldPerson.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/FieldPerson.java new file mode 100644 index 0000000..2aab8a6 --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/FieldPerson.java @@ -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 + '\'' + + '}'; + } +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/Person.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/Person.java new file mode 100644 index 0000000..7f8ab79 --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/Person.java @@ -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(); +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseFieldBoss.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseFieldBoss.java new file mode 100644 index 0000000..c09873d --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseFieldBoss.java @@ -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(); + } +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseFieldPerson.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseFieldPerson.java new file mode 100644 index 0000000..f158083 --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseFieldPerson.java @@ -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 + '\'' + + '}'; + } +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseSetBoss.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseSetBoss.java new file mode 100644 index 0000000..533f9a3 --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseSetBoss.java @@ -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; + } +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseSetPerson.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseSetPerson.java new file mode 100644 index 0000000..513013e --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/ReverseSetPerson.java @@ -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; + } + +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/SetBoss.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/SetBoss.java new file mode 100644 index 0000000..f7dd5ea --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/SetBoss.java @@ -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; + } +} diff --git a/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/SetPerson.java b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/SetPerson.java new file mode 100644 index 0000000..331650a --- /dev/null +++ b/beehive-jdbc-mapper/src/test/java/com/moparisthebest/jdbc/dto/SetPerson.java @@ -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; + } + +} diff --git a/pom.xml b/pom.xml index 35f6cad..1371448 100644 --- a/pom.xml +++ b/pom.xml @@ -109,6 +109,12 @@ junit 3.8.1 + + org.apache.derby + derby + 10.10.2.0 + test + org.apache.ant ant