Thursday, 27 March 2025

Using different JDBC drivers

So I had the problem that I needed to connect to both Oracle databases as well as Postgres database.

And just including the dependencies in my Maven was not enough.

One of the drivers gets overwritten by another driver in the service provider mechanism.

At first I tried to register them by hand (which works):

DriverManager.registerDriver(new org.postgresql.Driver());
DriverManager.registerDriver(new OracleDriver()); return DriverManager.getConnection(url, user, password);

Or, you could do the extreme magic thing1 2:

Class.forName("org.postgresql.Driver");
Class.forName("oracle.jdbc.driver.OracleDriver"); return DriverManager.getConnection(url, user, password);

Which causes both drivers to run a static block registering themselves on the DriverManager in the same fashion as my code on top.

All this, because the service provider mechanism that automatically loads the JDBC driver, only allows one Driver to be registered3.

References

[1] StackOverflow - What is the difference between "Class.forName()" and "Class.forName().newInstance()"?
https://stackoverflow.com/questions/2092659/what-is-the-difference-between-class-forname-and-class-forname-newinstanc/2093236#2093236
[2] Baeldung - Loading JDBC Drivers
https://www.baeldung.com/java-jdbc-loading-drivers
[3] Baeldung - Java Service Provider Interface
https://www.baeldung.com/java-spi

Saturday, 15 March 2025

Git: recovering a dropped commit

So I was working, and I accidentally dropped one commit too many.

Oh dear.

So I thought, would there be a possibility of getting this one back? And I was quite surprised that there was.

A quick google search later, I found the information I put in the References below.

git reflog

The reflog or "Reference logs" contain a record when the tips of branches or other references were updated in the local repository. From my imperfect knowledge, it sounds like a database transaction log.

With it you can pinpoint the exact point in the records where your change/branche/commit was still there and reset the head "hard" to this SHA value.

git reset --hard d6b66766a9a

Bear in mind that the reflog is only available locally in your git repo, and it will get cleaned of old reflog entries in due time.

References

Rewind Blog - How to Restore a Deleted Branch or Commit with Git Reflog
https://rewind.com/blog/how-to-restore-deleted-branch-commit-git-reflog/
git - git-reflog - Manage reflog information
https://git-scm.com/docs/git-reflog

Tuesday, 4 March 2025

Kotlin Operator Overloading

So my colleague mentioned operator overloading, and how much fun it is.

So I wrote a little test.

package org.mrbear.kotlin.operators
import org.assertj.core.api.Assertions.assertThat
import org.mrbear.kotlin.AddressFactory
import org.mrbear.kotlin.Person
import org.mrbear.kotlin.PersonFactory
import org.testng.annotations.Test
class OperatorOverloadingTest {
@Test
fun testStandardInOperator() {
val list = listOf("A", "B", "C")
assertThat("A" in list).isTrue()
assertThat("D" in list).isFalse()
val str = "MRBEAR"
assertThat("E" in str).isTrue()
assertThat("H" in str).isFalse()
}
@Test
fun testCustomInOperator() {
val addressBook =
AddressBook(listOf(PersonFactory.alexanderGrahamnBell, PersonFactory.mrBear, PersonFactory.lordKelvin))
assertThat("Kelvin" in addressBook).isTrue()
assertThat("Mr. Bear" in addressBook).isFalse()
assertThat(PersonFactory.alexanderGrahamnBell in addressBook).isTrue()
assertThat(PersonFactory.smith in addressBook).isFalse()
}
@Test
fun testCustomNotInOperator() {
val addressBook =
AddressBook(listOf(PersonFactory.alexanderGrahamnBell, PersonFactory.mrBear, PersonFactory.lordKelvin))
assertThat(PersonFactory.alexanderGrahamnBell notIn addressBook).isFalse()
assertThat(PersonFactory.smith notIn addressBook).isTrue()
}
@Test
fun testCustomNotOperator() {
assertThat(PersonFactory.alexanderGrahamnBell.not()).isEqualTo(Person("notAlexander", "Graham", "Bell", 55, AddressFactory.addressInAmerica))
assertThat(!PersonFactory.alexanderGrahamnBell).isEqualTo(Person("notAlexander", "Graham", "Bell", 55, AddressFactory.addressInAmerica))
}
}
operator fun Person.not(): Person =
Person("not${this.firstName}", this.middleName, this.lastName, this.age, this.address)
infix fun Person.notIn(addressBook: AddressBook): Boolean = !(this in addressBook)
class AddressBook(private val listOf: List<Person>) {
operator fun contains(lastName: String): Boolean {
return listOf.map { it.lastName.uppercase() }.contains(lastName.uppercase())
}
operator fun contains(person: Person): Boolean {
return listOf.contains(person)
}
}

It works pretty good, but for infix functions it has a very high "syntactic sugar" and less about "real" operator overloading.

Also, the reference page in [1] indicates that for Infix functions, the precedence has fixed rules that do not (always) conform to precedence that we would assume.

My colleague told me that a number of infix functions were created for QueryDSL, so we could write a semblance of SQL in Kotlin, but the precedence tends to screw things up.

We removed these infix functions from our source code again.

So, use sparingly and only when it makes sense. For example if it makes your code a magnitude easier to read/reason about and preferable with as small a scope as possible.

References

[1] KotlinLang - Functions
https://kotlinlang.org/docs/functions.html#function-scope
Baeldung - Operator Overloading in Kotlin
https://www.baeldung.com/kotlin/operator-overloading
Baeldung - Infix Functions in Kotlin
https://www.baeldung.com/kotlin/infix-functions