As you have shown in your code, to prevent the creation of an instance of KeyConstants , you can throw some exception inside the private-non-argument constructor.
The harder part is the way to block the creation of the KeyConstants.Key constructor from outside the KeyConstants class.
Some wild idea
Perhaps throw an exception in your constructor and check what its stack trace looks like. When I add this code to the constructor
private Key(String id, Class<T> clazz) { StackTraceElement[] stack = new Exception().getStackTrace(); for (int i=0; i<stack.length; i++){ System.out.println(i+") "+stack[i]); } this.ID = id; this.CLAZZ = clazz; }
and create an instance of the key with reflection, for example
Constructor<?> c = KeyConstants.Key.class.getDeclaredConstructor( String.class, Class.class); c.setAccessible(true); KeyConstants.Key<MyClass> r = (KeyConstants.Key<MyClass>) c .newInstance("wrongId", MyClass.class);
I get
0) KeyConstants$Key.<init>(Test.java:38) 1) sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 2) sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 3) sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 4) java.lang.reflect.Constructor.newInstance(Constructor.java:525)
so that itβs only possible if the 4th element of the stack is java.lang.reflect.Constructor.newInstance throw Exception, to prevent the rest of the constructors code from executing, for example:
if (stack.length>=4 && stack[4].toString().startsWith("java.lang.reflect.Constructor.newInstance")){ throw new RuntimeException("cant create object with reflection"); }
source share