Skip to content

Commit 58bebb7

Browse files
committed
[GAIA-2057] Loading the Map with the interfaceType processed by implicit is now thread-safe (cheap protection by adding a lock)
1 parent a5e0809 commit 58bebb7

File tree

2 files changed

+61
-30
lines changed

2 files changed

+61
-30
lines changed

src/main/kotlin/implicit/Implicit.kt

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import net.bytebuddy.matcher.ElementMatchers.isDeclaredBy
1818
import java.lang.reflect.InvocationTargetException
1919
import java.lang.reflect.Method
2020
import java.util.concurrent.ConcurrentHashMap
21+
import java.util.concurrent.locks.ReentrantLock
2122
import java.util.function.Function
2223
import java.util.function.Supplier
2324
import java.util.stream.Collectors
@@ -30,37 +31,40 @@ class Implicit(val namingStrategy: (TypeDescription) -> CharSequence) {
3031
companion object {
3132
private val intfTypeRegistry = ConcurrentHashMap<String, String>()
3233
private val supplierRegistry = ConcurrentHashMap<String, Supplier<*>>()
34+
private val intfTypeRegistryLock = ReentrantLock()
35+
3336
}
3437

3538
@JvmOverloads
3639
@Suppress("UNCHECKED_CAST")
3740
fun <T> create(intf: Class<T>, interceptor: ImplicitInterceptor = ImplicitInterceptor()): Class<out T> {
3841
if (!intf.isInterface)
3942
throw IllegalArgumentException("argument must be an interface")
40-
41-
if (intfTypeRegistry.containsKey(intf.name))
42-
return Class.forName(intfTypeRegistry.get(intf.name)) as Class<out T>
43-
44-
val addField = AddFieldDecorator<T>(intf)::apply
45-
val addGetterSetter = AddGetterSetterDecorator<T>(intf)::apply
46-
val addConstructor = AddConstructorDecorator<T>(intf, interceptor)::apply
47-
val addAlias = AliasDecorator<T>(intf)::apply
48-
val addMixin = MixinDecorator<T>(intf)::apply
49-
val addEqualsHashCode = AddEqualsHashCodeDecorator<T>(intf)::apply
50-
val addToString = AddToStringDecorator<T>(intf)::apply
51-
val toMap = ToMapDecorator<T>(intf)::apply
52-
53-
val unloaded = toMap(addToString(addEqualsHashCode(
54-
addMixin(addAlias(addGetterSetter(addField(addConstructor(init(intf))))))))).make()
55-
interceptor.onLoading(unloaded)
56-
57-
val loaded = unloaded.load(Implicit::class.java.classLoader, INJECTION)
58-
interceptor.onLoaded(loaded)
59-
60-
val loadedType = loaded.loaded
61-
intfTypeRegistry.put(intf.name, loadedType.name)
62-
63-
return loadedType
43+
try {
44+
intfTypeRegistryLock.lock()
45+
if (intfTypeRegistry.containsKey(intf.name))
46+
return Class.forName(intfTypeRegistry.get(intf.name)) as Class<out T>
47+
48+
val addField = AddFieldDecorator<T>(intf)::apply
49+
val addGetterSetter = AddGetterSetterDecorator<T>(intf)::apply
50+
val addConstructor = AddConstructorDecorator<T>(intf, interceptor)::apply
51+
val addAlias = AliasDecorator<T>(intf)::apply
52+
val addMixin = MixinDecorator<T>(intf)::apply
53+
val addEqualsHashCode = AddEqualsHashCodeDecorator<T>(intf)::apply
54+
val addToString = AddToStringDecorator<T>(intf)::apply
55+
val toMap = ToMapDecorator<T>(intf)::apply
56+
57+
val unloaded = toMap(addToString(addEqualsHashCode(
58+
addMixin(addAlias(addGetterSetter(addField(addConstructor(init(intf))))))))).make()
59+
interceptor.onLoading(unloaded)
60+
val loaded = unloaded.load(Implicit::class.java.classLoader, INJECTION)
61+
interceptor.onLoaded(loaded)
62+
val loadedType = loaded.loaded
63+
intfTypeRegistry.put(intf.name, loadedType.name)
64+
return loadedType
65+
} finally {
66+
intfTypeRegistryLock.unlock()
67+
}
6468
}
6569

6670
@Suppress("UNCHECKED_CAST")

src/test/kotlin/implicit/ImplicitTest.kt

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
* from Leftshift One.
1515
*/
1616

17-
package implicit;
17+
package implicit
1818

19+
import org.assertj.core.api.Assertions.assertThat
1920
import org.junit.jupiter.api.Assertions
20-
import org.junit.jupiter.api.Assertions.assertNotNull
21-
import org.junit.jupiter.api.Assertions.assertTrue
21+
import org.junit.jupiter.api.Assertions.*
2222
import org.junit.jupiter.api.Test
2323
import java.util.*
24+
import java.util.concurrent.CountDownLatch
25+
import java.util.concurrent.TimeUnit
2426

2527
class ImplicitTest {
2628

@@ -37,7 +39,32 @@ class ImplicitTest {
3739

3840
assertNotNull(pojo.getPartitionKey())
3941
assertNotNull(pojo.getSortingKey())
40-
Assertions.assertTrue(pojo::class.java.annotations.map { it.annotationClass.simpleName }.contains("Entity"))
42+
assertTrue(pojo::class.java.annotations.map { it.annotationClass.simpleName }.contains("Entity"))
43+
}
44+
45+
@Test
46+
fun parallelTest() {
47+
var creationOfPojoSuccessfull=true
48+
val barrier = CountDownLatch(1)
49+
val endBarrier = CountDownLatch(25)
50+
val factory = Implicit { "implicit.test.implicit.${it.simpleName}" }
51+
(0..24).forEach {
52+
Thread {
53+
try {
54+
barrier.await(10, TimeUnit.SECONDS)
55+
println("[${Thread.currentThread().name}] starting execution")
56+
factory.create(IPojo::class.java)
57+
}catch (ex: Exception){
58+
println("[${Thread.currentThread().name}] Error occurred when creating the pojo " + ex.message)
59+
creationOfPojoSuccessfull=false
60+
} finally {
61+
endBarrier.countDown()
62+
}
63+
}.start()
64+
}
65+
barrier.countDown()
66+
endBarrier.await(60, TimeUnit.SECONDS)
67+
assertThat(creationOfPojoSuccessfull).isTrue()
4168
}
4269

4370
@Test
@@ -50,7 +77,7 @@ class ImplicitTest {
5077

5178
assertNotNull(pojo.getPartitionKey())
5279
assertNotNull(pojo.getSortingKey())
53-
Assertions.assertTrue(pojo::class.java.annotations.map { it.annotationClass.simpleName }.contains("Entity"))
80+
assertTrue(pojo::class.java.annotations.map { it.annotationClass.simpleName }.contains("Entity"))
5481
}
5582

5683
@Test
@@ -118,7 +145,7 @@ class ImplicitTest {
118145
fun setPartitionKey(str: String)
119146

120147
fun getSortingKey(): String
121-
fun setSortingKey(str: String): Unit
148+
fun setSortingKey(str: String)
122149

123150
fun getLabelList(): List<String?>
124151
fun setLabelList(labelList: List<String?>)

0 commit comments

Comments
 (0)