Summary
Create a SyncInstanceCreator that can replace an object directly in the memory, in order to
Enhance the injection of a synchronised object by replacing the source object by it's synchronised version.
Goals
- Ease the control of a program by injecting sychronised object more easily
- Deal with limitations of the current SyncInstanceCreator implementations
Motivations
Current implementations and their limitations
There is two default ways to create a synchronised object using SynchronisedObjectCache#syncObject(int, SyncInstanceCreator )
val player: Player = new Player(new PlayerHealth, "John", "Cena")
val playerSyncs = cache.syncObject(id, ContentPaster(players))
The ContentPaster will basically paste all the fields of the player
object to the synchronised object instance (playerSync
).
This will have for effect to possibly modify the player
object when the playerSyncs
will get modified, and vice-versa.
However, as the player
and playerSync
are two different objects. And if a non-pure method is called (such as Player#setName) on one of those objects, the other one will still get the old name reference. Consequently, the two objects could get modified by the other in a pretty random and incomprehensible manner.
val syncFile: File = cache.syncObject(id, SyncConstructor("C:/any/file/text.txt"))
This is the most clean and safe way to create a synchronized object, However, this option does not allows the user to synchronize an already existing object. Of course, you have the ContentPaster, which support this, but, as said above, if the source object still used, some uncontrollable modifications would be received on the synchronized version, which is not acceptable.
The Replace
implementation
Well, the concept of Replace(source)
is not that hard to understand : Once you get the source object you desire to synchronise, using the Replace
SyncInstanceCreator will replace the old object to its synchronized version.
Here is an example :
val cache = manager.attachToCache(id, DefaultSynchronizedObjectCache)
val source: Player = list.get(winnerIndex)
assert(source.getClass == classOf[Player]) // the object's class is Player
cache.syncObject(x, Replace(source))
assert(source.getClass != classOf[Player]) //The object's class is now the PlayerSync (and not directly Player)
Complications
As the Object Layout and memory management is not part of the Oracle's specifications, each JVM have a different way to define it's object layout. This way, it is not possible to define a static code that would work on every JVMs; the "Write once, Run everywhere" feature of java will not be usable for the Replace
implementation.
Some native code would certainly be necessary for this task, but i've personally tried to write some native code, and i did not found a way to get an object's address. For the Hotspot & OpenJDK implementations, there is the JOL library that can do this, but it's using Unsafe, and this class will later be removed in next java versions.