История изменений
Исправление svr4, (текущая версия) :
package main;
class PublicMorozov
{
// заготавливаем инстанс, для которого мы будем создавать экземпляр inner класса
private static final PublicMorozov INSTANCE = new PublicMorozov();
// и поле, содержимое которого и будем заменять
private static final java.lang.ref.WeakReference<Inner> targetField = new java.lang.ref.WeakReference<Inner>(null);
private class Inner
{}
public PublicMorozov()
{}
public static void makeReplace() throws Exception
{
// получаем через рефлект поле, которое предстоит заменить
java.lang.reflect.Field targetAsField = Class.forName("main.PublicMorozov").getDeclaredField("targetField");
// снимаем с него private
targetAsField.setAccessible(true);
// получаем адрес поля модификаторов в целевом поле
java.lang.reflect.Field modifiers = Class.forName("java.lang.reflect.Field").getDeclaredField("modifiers");
// снимаем с него private
modifiers.setAccessible(true);
// снимаем с целевого поля private и final, а вместо них ставим public
modifiers.setInt(targetAsField, targetAsField.getModifiers() & ~java.lang.reflect.Modifier.FINAL);
modifiers.setInt(targetAsField, targetAsField.getModifiers() & ~java.lang.reflect.Modifier.PRIVATE);
modifiers.setInt(targetAsField, targetAsField.getModifiers() | java.lang.reflect.Modifier.PUBLIC);
// но всё не так просто... если попытаться применить изменения то нас может отправить куда подальше с IllegalAccessException
// поэтому мы заменяем accessor на свой, которому будет пофиг на финал
// мы используем именно overrideFieldAccessor поскольку поле изначально было private, в противном случае следует использовать fieldAccessor
java.lang.reflect.Field accessorField = Class.forName("java.lang.reflect.Field").getDeclaredField("overrideFieldAccessor");
// как обычно снимаем с него private
accessorField.setAccessible(true);
// поскольку мы заменяем статический Object нам нужен именно этот тип, их много под разные типы полей и данных
java.lang.reflect.Constructor accessorConstructor = Class.forName("sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl").getDeclaredConstructor(java.lang.reflect.Field.class, boolean.class);
// конструктор тоже сокрыт... но разве нас этим испугаешь?
accessorConstructor.setAccessible(true);
// вот теперь всё нормально - новый accessor на поле final и смотреть не будет
accessorField.set(targetAsField, accessorConstructor.newInstance(targetAsField, false));
// и на десерт - доступ к inner классу
java.lang.reflect.Constructor innerConstructor = Class.forName("main.PublicMorozov$Inner").getDeclaredConstructor(Class.forName("main.PublicMorozov"));
innerConstructor.setAccessible(true);
// заменяем таки содержимое нужного поля
targetAsField.set(null, new java.lang.ref.WeakReference<Inner>((Inner) innerConstructor.newInstance(INSTANCE)));
}
}
В плюсах обычно Паблика кастуют проще:
#define private public
Исправление svr4, :
package main;
class PublicMorozov
{
// заготавливаем инстанс, для которого мы будем создавать экземпляр inner класса
private static final PublicMorozov INSTANCE = new PublicMorozov();
// и поле, содержимое которого и будем заменять
private static final java.lang.ref.WeakReference<Inner> targetField = new java.lang.ref.WeakReference<Inner>(null);
private class Inner
{}
public PublicMorozov()
{}
public static void makeReplace() throws Exception
{
// получаем через рефлект поле, которое предстоит заменить
java.lang.reflect.Field targetAsField = Class.forName("main.PublicMorozov").getDeclaredField("targetField");
// снимаем с него private
targetAsField.setAccessible(true);
// получаем адрес поля модификаторов в целевом поле
java.lang.reflect.Field modifiers = Class.forName("java.lang.reflect.Field").getDeclaredField("modifiers");
// снимаем с него private
modifiers.setAccessible(true);
// снимаем с целевого поля private и final, а вместо них ставим public
modifiers.setInt(targetAsField, targetAsField.getModifiers() & ~java.lang.reflect.Modifier.FINAL);
modifiers.setInt(targetAsField, targetAsField.getModifiers() & ~java.lang.reflect.Modifier.PRIVATE);
modifiers.setInt(targetAsField, targetAsField.getModifiers() | java.lang.reflect.Modifier.PUBLIC);
// но всё не так просто... если попытаться применить изменения то нас может отправить куда подальше с IllegalAccessException
// поэтому мы заменяем accessor на свой, которому будет пофиг на финал
// мы используем именно overrideFieldAccessor поскольку поле изначально было private, в противном случае следует использовать fieldAccessor
java.lang.reflect.Field accessorField = Class.forName("java.lang.reflect.Field").getDeclaredField("overrideFieldAccessor");
// как обычно снимаем с него private
accessorField.setAccessible(true);
// поскольку мы заменяем статический Object нам нужен именно этот тип, их много под разные типы полей и данных
java.lang.reflect.Constructor accessorConstructor = Class.forName("sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl").getDeclaredConstructor(java.lang.reflect.Field.class, boolean.class);
// конструктор тоже сокрыт... но разве нас этим испугаешь?
accessorConstructor.setAccessible(true);
// вот теперь всё нормально - новый accessor на поле final и смотреть не будет
accessorField.set(targetAsField, accessorConstructor.newInstance(targetAsField, false));
// и на десерт - доступ к inner классу
java.lang.reflect.Constructor innerConstructor = Class.forName("main.PublicMorozov$Inner").getDeclaredConstructor(Class.forName("main.PublicMorozov"));
innerConstructor.setAccessible(true);
// заменяем таки содержимое нужного поля
targetAsField.set(null, new java.lang.ref.WeakReference<Inner>((Inner) innerConstructor.newInstance(INSTANCE)));
}
}
В плюсах обычно Паблика кастуют проще:
#define private public
Исходная версия svr4, :
package main;
class PublicMorozov
{
// заготавливаем инстанс, для которого мы будем создавать экземпляр inner класса
private static final PublicMorozov INSTANCE = new PublicMorozov();
// и поле, содержимое которого и будем заменять
private static final java.lang.ref.WeakReference<Inner> targetField = new java.lang.ref.WeakReference<Inner>(null);
private class Inner
{}
public PublicMorozov()
{}
public static void makeReplace() throws Exception
{
// получаем через рефлект поле, которое предстоит заменить
java.lang.reflect.Field targetAsField = Class.forName("main.PublicMorozov").getDeclaredField("targetField");
// снимаем с него private
targetAsField.setAccessible(true);
// получаем адрес поля модификаторов в целевом поле
java.lang.reflect.Field modifiers = Class.forName("java.lang.reflect.Field").getDeclaredField("modifiers");
// снимаем с него private
modifiers.setAccessible(true);
// снимаем с целевого поля private и final, а вместо них ставим public
modifiers.setInt(targetAsField, targetAsField.getModifiers() & ~java.lang.reflect.Modifier.FINAL);
modifiers.setInt(targetAsField, targetAsField.getModifiers() & ~java.lang.reflect.Modifier.PRIVATE);
modifiers.setInt(targetAsField, targetAsField.getModifiers() | java.lang.reflect.Modifier.PUBLIC);
// но всё не так просто... если попытаться применить изменения то нас может отправить куда подальше с IllegalAccessException
// поэтому мы заменяем accessor на свой, которому будет пофиг на финал
// мы используем именно overrideFieldAccessor поскольку поле изначально было private, в противном случае следует использовать fieldAccessor
java.lang.reflect.Field accessorField = Class.forName("java.lang.reflect.Field").getDeclaredField("overrideFieldAccessor");
// как обычно снимаем с него private
accessorField.setAccessible(true);
// поскольку мы заменяем статический Object нам нужен именно этот тип, их много под разные типы полей и данных
java.lang.reflect.Constructor accessorConstructor = Class.forName("sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl").getDeclaredConstructor(java.lang.reflect.Field.class, boolean.class);
// конструктор тоже сокрыт... но разве нас этим испугаешь?
accessorConstructor.setAccessible(true);
// вот теперь всё нормально - новый accessor на поле final и смотреть не будет
accessorField.set(targetAsField, accessorConstructor.newInstance(targetAsField, false));
// и на десерт - доступ к inner классу
java.lang.reflect.Constructor innerConstructor = Class.forName("main.PublicMorozov$Inner").getDeclaredConstructor(Class.forName("main.PublicMorozov"));
innerConstructor.setAccessible(true);
// заменяем таки содержимое нужного поля
targetAsField.set(null, new java.lang.ref.WeakReference<Inner>((Inner) innerConstructor.newInstance(INSTANCE)));
}
}