diff --git a/singleton/src/main/java/com/iluwatar/singleton/BillPughImplementation.java b/singleton/src/main/java/com/iluwatar/singleton/BillPughImplementation.java index 4656cb762..c5f6f9f2c 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/BillPughImplementation.java +++ b/singleton/src/main/java/com/iluwatar/singleton/BillPughImplementation.java @@ -40,7 +40,10 @@ public final class BillPughImplementation { * Private constructor to prevent instantiation from outside the class. */ private BillPughImplementation() { - // private constructor + // to prevent instantiating by Reflection call + if (InstanceHolder.instance != null) { + throw new IllegalStateException("Already initialized."); + } } /** diff --git a/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java b/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java index 6cff5b561..f2e427775 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java +++ b/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java @@ -43,6 +43,10 @@ public final class InitializingOnDemandHolderIdiom { * Private constructor. */ private InitializingOnDemandHolderIdiom() { + // to prevent instantiating by Reflection call + if (HelperHolder.INSTANCE != null) { + throw new IllegalStateException("Already initialized."); + } } /** diff --git a/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java index f27467272..362e1634c 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java +++ b/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java @@ -33,6 +33,10 @@ public final class IvoryTower { * Private constructor so nobody can instantiate the class. */ private IvoryTower() { + // to prevent instantiating by Reflection call + if (INSTANCE != null) { + throw new IllegalStateException("Already initialized."); + } } /** diff --git a/singleton/src/test/java/com/iluwatar/singleton/EnumIvoryTowerTest.java b/singleton/src/test/java/com/iluwatar/singleton/EnumIvoryTowerTest.java index 6b1c6e235..cd40f2d3a 100644 --- a/singleton/src/test/java/com/iluwatar/singleton/EnumIvoryTowerTest.java +++ b/singleton/src/test/java/com/iluwatar/singleton/EnumIvoryTowerTest.java @@ -24,6 +24,10 @@ */ package com.iluwatar.singleton; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; + /** * EnumIvoryTowerTest * @@ -37,4 +41,14 @@ class EnumIvoryTowerTest extends SingletonTest { super(() -> EnumIvoryTower.INSTANCE); } + /** + * Test creating new instance by reflection. + */ + @Override + @Test + void testCreatingNewInstanceByReflection() throws Exception { + // Java does not allow Enum instantiation http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9 + assertThrows(ReflectiveOperationException.class, EnumIvoryTower.class::getDeclaredConstructor); + } + } diff --git a/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java b/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java index 7093ffc73..81e5f4132 100644 --- a/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java +++ b/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java @@ -27,8 +27,10 @@ package com.iluwatar.singleton; import static java.time.Duration.ofMillis; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTimeout; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.concurrent.Callable; import java.util.concurrent.Executors; @@ -106,4 +108,14 @@ abstract class SingletonTest { } + /** + * Test creating new instance by reflection. + */ + @Test + void testCreatingNewInstanceByReflection() throws Exception { + var firstTimeInstantiated = this.singletonInstanceMethod.get(); + var constructor = firstTimeInstantiated.getClass().getDeclaredConstructor(); + constructor.setAccessible(true); + assertThrows(InvocationTargetException.class, () -> constructor.newInstance((Object[]) null)); + } } diff --git a/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLockingTest.java b/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLockingTest.java index e9d8ef048..e88968223 100644 --- a/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLockingTest.java +++ b/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLockingTest.java @@ -24,11 +24,6 @@ */ package com.iluwatar.singleton; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.lang.reflect.InvocationTargetException; -import org.junit.jupiter.api.Test; - /** * ThreadSafeDoubleCheckLockingTest * @@ -42,15 +37,4 @@ class ThreadSafeDoubleCheckLockingTest extends SingletonTest constructor.newInstance((Object[]) null)); - } - }