Ninja-Squad / DbSetup

An API for populating a database in unit tests
http://dbsetup.ninja-squad.com/
212 stars 34 forks source link

Topic/java8 #52

Closed jnizet closed 8 years ago

jnizet commented 8 years ago

This is a fix for #51.

It starts the new 2.0.0 release, including these changes, that make the new version not completely compatible with the latest 1.x version:

clacote commented 8 years ago

LGTM. Nice work!

cexbrayat commented 8 years ago

LGTM (except the versioning question)

vaesbart commented 8 years ago

Hi, I'm having trouble building the code (using NetBeans 8.1 / openSUSE Leap)

Stacktrace:

FAILURE: Build failed with an exception.

* What went wrong: Execution failed for task ':checkstyleMain'. > Unable to create a Checker: cannot initialize module Header - unable to load header file config/checkstyle/java.header

I'm not really familiar with gradle & it's config, but the file java.header is available on that location.

Is it possible to provide a jar in Maven central for testing ?

TIA Bart.

jnizet commented 8 years ago

Hi @vaesbart . Thanks for your feedback. I'll deploy a beta version to Maven and let you know about it. Probably tonight. In the meantime, if that's checkstyle that's bothering you, you should be able to just do ./gradlew jar to produce the jar without executing the tests and the static code analysis.

jnizet commented 8 years ago

@vaesbart DbSetup-2.0.0-beta1 is available in Maven central.

I haven't updated the user guide or published the javadoc online, but the javadoc, available from Maven, is up-to-date.

Thank you for telling me if everything is OK.

jnizet commented 8 years ago

@vaesbart have you had a chance to test the published beta version? Any feedback?

vaesbart commented 8 years ago

Yes, sorry it took so long for me to reply - real life and sudden illness got in the way...

I updated my test project with DbSetup-2.0.0-beta1 and replaced all java.util.Date's with new JDK8 LocalDate or LocalDateTime so everything compiles and looks OK but I get following error when trying to run a test class: java.sql.SQLDataException: An attempt was made to get a data value of type 'TIMESTAMP' from a data value of type 'VARBINARY'. I attached a small stacktrace :: dbsetup2_test.txt

I'm using jdk1.8.0_66 and its' included Derby database.

jnizet commented 8 years ago

@vaesbart No worries. I hope you're better now.

I'll paste the stack trace here for the record, and an easier to follow explanation:

Caused by: java.sql.SQLDataException: An attempt was made to get a data value of type 'TIMESTAMP' from a data value of type 'VARBINARY'.
    at org.apache.derby.client.am.SQLExceptionFactory.getSQLException(Unknown Source)
    at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
    at org.apache.derby.client.am.ClientPreparedStatement.setTimestamp(Unknown Source)
    at org.apache.derby.client.am.ClientPreparedStatement.setTimestamp(Unknown Source)
    at org.apache.commons.dbcp2.DelegatingPreparedStatement.setTimestamp(DelegatingPreparedStatement.java:159)
    at org.apache.commons.dbcp2.DelegatingPreparedStatement.setTimestamp(DelegatingPreparedStatement.java:159)
    at com.ninja_squad.dbsetup.bind.Binders$DefaultBinder.bind(Binders.java:470)
    at com.ninja_squad.dbsetup.operation.Insert.execute(Insert.java:225)
    at com.ninja_squad.dbsetup.operation.CompositeOperation.execute(CompositeOperation.java:92)
    at com.ninja_squad.dbsetup.DbSetup.launch(DbSetup.java:107)
    ... 38 more

I don't know much about Derby, but reading the stack trace, it seems that it doesn't support parameter metadata. What does that mean? Normally, when inserting something in a column, DbSetup asks the database: what is the type of the column I'm going to insert somthing into? Then based on what the database returns, it chooses the best method to call: if it's a TIMESTAMP, then use setTimestamp(), etc.

For databases not supporting that feature, the default binder is used, and this uses a different technique. It looks at the value that is being inserted, and tries to guess the best way to insert that. So if you pass a LocalDateTime, DbSetup assumes that the underlying column is a TIMESTAMP (or compatible type), and calls setTimestamp().That's what happens here. Unfortunately, it seems that the column where you're trying to insert a LocalDateTime is of type VARBINARY.

That looks like a bug on your side to me: either the column is not correctly defined (i.e. doesn't have the right type), or you're not inserting the LocalDateTime in the corrrect column. If you really want to store a LocalDateTime into a column of type VARBINARY, you'll have to use a custom Binder to insert that value, because DbSetup can't guess how a LocalDateTime must be inserted into a VARBINARY column.

I hope that makes it clear.

PS: note that I released the 2.0.0 (non-beta) version now. So you should switch to that version (the code is identical to the beta).

vaesbart commented 8 years ago

Hi, I wanted to get back and explain why I got the above error. It was indeed a configuration error on my part. I'm using Hibernate to generate the database - when using JDK8 and java.time you need to declare hibernate-java8 as a dependency, so Hibernate generates Timestamp columns instead of Varbinary. Now everything works perfectly :)

jnizet commented 8 years ago

That's very nice of you. Thank you @vaesbart