Skip to content

Commit

Permalink
Merge pull request #32 from neilg/java-lang-Object-methods
Browse files Browse the repository at this point in the history
handle methods from java.lang.Object
  • Loading branch information
zhxnlai authored Oct 21, 2018
2 parents 806ae72 + fb9088a commit 0dd5493
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 4 deletions.
27 changes: 23 additions & 4 deletions scarlet/src/main/java/com/tinder/scarlet/Scarlet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.tinder.scarlet.retry.ExponentialBackoffStrategy
import com.tinder.scarlet.streamadapter.builtin.BuiltInStreamAdapterFactory
import io.reactivex.schedulers.Schedulers
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy

/**
Expand Down Expand Up @@ -117,13 +118,31 @@ class Scarlet internal constructor(
private fun createInvocationHandler(serviceInterface: Class<*>, serviceInstance: Service): InvocationHandler =
InvocationHandler { proxy, method, nullableArgs ->
val args = nullableArgs ?: arrayOf()
if (runtimePlatform.isDefaultMethod(method)) {
runtimePlatform.invokeDefaultMethod(method, serviceInterface, proxy, args)
} else {
serviceInstance.execute(method, args)
when {
runtimePlatform.isDefaultMethod(method) -> runtimePlatform.invokeDefaultMethod(method, serviceInterface, proxy, args)
isJavaObjectMethod(method) -> handleJavaObjectMethod(method, serviceInstance, serviceInterface, proxy, args)
else -> serviceInstance.execute(method, args)
}
}

private fun isJavaObjectMethod(method: Method) = method.declaringClass == Object::class.java

private fun handleJavaObjectMethod(method: Method, serviceInstance: Service, serviceInterface: Class<*>, proxy: Any, args: Array<out Any>): Any {
return when {
isEquals(method) -> proxy === args[0]
isToString(method) -> "Scarlet service implementation for ${serviceInterface.name}"
isHashCode(method) -> serviceInstance.hashCode()
else -> throw IllegalStateException("Cannot execute $method")
}
}

private fun isHashCode(method: Method) = method.name == "hashCode" && method.parameterTypes.isEmpty()

private fun isToString(method: Method) = method.name == "toString" && method.parameterTypes.isEmpty()

private fun isEquals(method: Method) =
method.name == "equals" && arrayOf(Object::class.java).contentEquals(method.parameterTypes)

/**
* Build a new [Scarlet] instance.
*
Expand Down
59 changes: 59 additions & 0 deletions scarlet/src/test/java/com/tinder/scarlet/ScarletTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.tinder.scarlet.internal.Service
import com.tinder.scarlet.internal.utils.RuntimePlatform
import com.tinder.scarlet.ws.Receive
import com.tinder.scarlet.ws.Send
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.junit.MockitoJUnitRunner
Expand Down Expand Up @@ -73,6 +74,64 @@ internal class ScarletTest {
then(service).should().execute(ExampleService::class.java.getDeclaredMethod("receive"), emptyArray())
}

@Test
fun create_hashCode_shouldEqualServiceInstanceHashCode() {
// Given
val service = mock<Service>()
given(serviceFactory.create(ExampleService::class.java)).willReturn(service)
val exampleService = scarlet.create<ExampleService>()

// When
val hashCode = exampleService.hashCode()

// Then
assertThat(hashCode).isEqualTo(service.hashCode())
}

@Test
fun create_toString_shouldProduceCorrectValue() {
// Given
val service = mock<Service>()
given(serviceFactory.create(ExampleService::class.java)).willReturn(service)
val exampleService = scarlet.create<ExampleService>()

// When
val toString = exampleService.toString()

// Then
assertThat(toString)
.isEqualTo("Scarlet service implementation for com.tinder.scarlet.ScarletTest\$Companion\$ExampleService")
}

@Test
fun create_equals_shouldEqualSelf() {
// Given
val service = mock<Service>()
given(serviceFactory.create(ExampleService::class.java)).willReturn(service)
val exampleService = scarlet.create<ExampleService>()

// When
val equalsSelf = exampleService.equals(exampleService)

// Then
assertThat(equalsSelf).describedAs("equals must be reflexive").isTrue()
}

@Test
fun create_equals_shouldNotEqualOther() {
// Given
val service = mock<Service>()
given(serviceFactory.create(ExampleService::class.java)).willReturn(service)
val exampleService = scarlet.create<ExampleService>()
val otherExampleService = scarlet.create<ExampleService>()

// When
val equalsOther = exampleService.equals(otherExampleService)

// Then
assertThat(equalsOther).describedAs("should not equal other instance").isFalse()
}

@Suppress("UNUSED")
companion object {
interface ExampleService {
Expand Down

0 comments on commit 0dd5493

Please sign in to comment.